# LotQueryManagerImpl.java

    package com.mycim.server.wip.manager.impl;

    import com.fa.sesa.exception.Assert;
    import com.fa.sesa.exception.Errors;
    import com.fa.sesa.exception.SystemIllegalArgumentException;
    import com.fa.sesa.exception.SystemIllegalStateException;
    import com.fa.sesa.i18n.I18nUtils;
    import com.fa.sesa.threadlocal.LocalContext;
    import com.mycim.framework.jdbc.Page;
    import com.mycim.framework.logging.Logger;
    import com.mycim.framework.logging.LoggerFactory;
    import com.mycim.framework.utils.MiscUtils;
    import com.mycim.framework.utils.beans.BeanUtils;
    import com.mycim.framework.utils.lang.StringUtils;
    import com.mycim.framework.utils.lang.collections.CollectionUtils;
    import com.mycim.framework.utils.lang.collections.MapUtils;
    import com.mycim.framework.utils.lang.math.NumberUtils;
    import com.mycim.framework.utils.lang.time.DateUtils;
    import com.mycim.server.automonitor.manager.LotAutoMonitorInqManager;
    import com.mycim.server.base.manager.NamedObjectManager;
    import com.mycim.server.base.manager.ObjectVersionManager;
    import com.mycim.server.carrier.manager.CarrierManager;
    import com.mycim.server.carrier.manager.PcdManager;
    import com.mycim.server.constrain.manager.EquipmentConstrainInfoManager;
    import com.mycim.server.ctx.exec.manager.*;
    import com.mycim.server.ctx.manager.ContextValueManager;
    import com.mycim.server.ems.manager.EntityManager;
    import com.mycim.server.prp.manager.*;
    import com.mycim.server.rcp.manager.RecipeManager;
    import com.mycim.server.rcp.manager.RecipeVersionManager;
    import com.mycim.server.reticle.manager.LocationInqManager;
    import com.mycim.server.security.manager.UserManager;
    import com.mycim.server.spec.manager.AttributeConvertManager;
    import com.mycim.server.spec.manager.ProcessSpecItemManager;
    import com.mycim.server.system.manager.ReferenceFileManager;
    import com.mycim.server.wip.dao.LotQueryDAO;
    import com.mycim.server.wip.manager.*;
    import com.mycim.utils.WflLinkContextSetupAttributeUtil;
    import com.mycim.utils.WipUtils;
    import com.mycim.valueobject.MessageIdList;
    import com.mycim.valueobject.ObjectList;
    import com.mycim.valueobject.automonitor.entity.AutoMonitorItemStep;
    import com.mycim.valueobject.automonitor.entity.LotAutoMonitorInfo;
    import com.mycim.valueobject.automonitor.entity.LotMonitorJobStore;
    import com.mycim.valueobject.automonitor.util.AutoMonitorOperationConstants;
    import com.mycim.valueobject.bas.NamedObject;
    import com.mycim.valueobject.bas.TransactionLog;
    import com.mycim.valueobject.consts.*;
    import com.mycim.valueobject.ems.Carrier;
    import com.mycim.valueobject.ems.Entity;
    import com.mycim.valueobject.ems.Equipment;
    import com.mycim.valueobject.prp.*;
    import com.mycim.valueobject.runcard.util.RunCardUtils;
    import com.mycim.valueobject.security.User;
    import com.mycim.valueobject.sys.ReferenceFile;
    import com.mycim.valueobject.sys.ReferenceFileDetail;
    import com.mycim.valueobject.wip.*;
    import com.mycim.valueobject.wip.dto.LotQueryParameterDto;
    import com.mycim.valueobject.wip.dto.ShipQueryConditionDto;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.util.StopWatch;

    import java.lang.Override;
    import java.sql.Timestamp;
    import java.time.Duration;
    import java.time.LocalDateTime;
    import java.util.*;
    import java.util.function.BiConsumer;
    import java.util.function.Consumer;
    import java.util.regex.Matcher;
    import java.util.stream.Collectors;

    /**
     * @author Johnson.Wang
     * @version 6.0.0
     * @date 2019/9/4
     **/
    @Service
    @Transactional
    public class LotQueryManagerImpl implements LotQueryManager {
        private static final String TRACKOUTHOLD_REASON_PREFIX = "(TR)";

        private static final String FUTUREHOLD_REASON_PREFIX = "(FH)";

        protected static String STATION_RRN = "stationRrn";

        protected static String EQUIPMENT_RRN = "equipmentRrn";

        protected static String LOT_STATUS = "lotStatus";

        protected static String DUMMY_FLAG = "dummyFlag";

        private final Logger logger = LoggerFactory.getLogger(LotQueryManagerImpl.class);

        @Autowired
        private LotQueryDAO lotQueryDAO;

        @Autowired
        private NamedObjectManager namedObjectManager;

        @Autowired
        private ReferenceFileManager referenceFileManager;

        @Autowired
        private ProcessOperationDescContextValueManager operationDescContextValueManager;

        @Autowired
        private ResequenceContextValueManager resequenceContextValueManager;

        @Autowired
        private RecipeContextManager recipeContextManager;

        @Autowired
        private ContextValueManager contextValueManager;

        @Autowired
        private WorkflowManager workflowManager;

        @Autowired
        private WflLinkContextValueManager wflLinkContextValueManager;

        @Autowired
        private TimeLimitSetUpManager timeLimitSetUpManager;

        @Autowired
        private UnitQueryManager unitQueryManager;

        @Autowired
        private WipWorkflowQueryManager wipWorkflowQueryManager;

        @Autowired
        private ObjectVersionManager objectVersionManager;

        @Autowired
        private ReworkRouteContextValueManager reworkRouteContextValueManager;

        @Autowired
        private OperationManager operationManager;

        @Autowired
        private BORContextValueManager bORContextValueManager;

        @Autowired
        private RecipeManager recipeManager;

        @Autowired
        private UserManager userManager;

        @Autowired
        private StageContextValueManager stageContextValueManager;

        @Autowired
        private EquipmentConstrainInfoManager equipmentConstrainInfoManager;

        @Autowired
        private RecipeVersionManager recipeVersionManager;

        @Autowired
        private CarrierManager carrierManager;

        @Autowired
        private ProductManager productManager;

        @Autowired
        private RunCardQueryManager runCardQueryManager;

        @Autowired
        private LotRecycledContextValueManager lotRecycledContextValueManager;

        @Autowired
        private LotRecycledManager lotRecycledManager;

        @Autowired
        private EntityManager entityManager;

        @Autowired
        private PcdManager pcdManager;

        @Autowired
        private AttributeConvertManager attributeConvertManager;

        @Autowired
        private DiffBatchQueryManager diffBatchQueryManager;

        @Autowired
        private LotAutoMonitorInqManager lotAutoMonitorInqManager;

        @Autowired
        private EquipmentQueryManager equipmentQueryManager;

        @Autowired
        private LotInqManager lotInqManager;

        @Autowired
        private LocationInqManager locationInqManager;

        @Override
        public Map selectMatchingRulesFromReworkLot(long executionRrn) {
            return lotQueryDAO.selectMatchingRulesFromReworkLot(executionRrn);
        }

        @Override
        public Map selectMatchingRulesFromLot(long executionRrn) {
            return lotQueryDAO.selectMatchingRulesFromLot(executionRrn);
        }

        @Override
        public Map selectMatchingRulesFromExecution(long executionRrn) {
            return lotQueryDAO.selectMatchingRulesFromExecution(executionRrn);
        }

        @Override
        public long getReworkLotCountByExecutionRrn(long executionRrn) {
            return lotQueryDAO.getReworkLotCountByExecutionRrn(executionRrn);
        }

        @Override
        public long getLotCountByExecutionRrn(long executionRrn) {
            return lotQueryDAO.getLotCountByExecutionRrn(executionRrn);
        }

        @Override
        public Lot getLot(String lotSql, long lotRrn, long facilityRrn, String lotId) {
            return lotQueryDAO.getLot(lotSql, lotRrn, facilityRrn, lotId);
        }

        @Override
        public Lot getLot(String lotId, long facility) {
            Lot lot = lotQueryDAO.getLot(facility, lotId);
            this.fillLotExt(lot);
            return lot;
        }

        @Override
        public List getChildLotsForMerge(Lot lot) {
            return lotQueryDAO.getChildLotsForMerge(lot);
        }

        @Override
        public Map getLotStepHisotryInfoByOperationRrn(Map info) {
            return lotQueryDAO.getLotStepHisotryInfoByOperationRrn(info);
        }

        @Override
        public Map<Long, Map<String, Object>> getLotStepSeqAndStatusByRrns(List<Long> lotRrns) {
            if (CollectionUtils.isEmpty(lotRrns)) {
                return null;
            }
            Map<Long, Map<String, Object>> result = new HashMap<>();
            for (long lotrrn : lotRrns) {
                //如果lotrrn 查不到数据. 那就是神秘力量干预了
                Map<String, Object> tempMap = lotQueryDAO.getLotStateAndStepSeq(lotrrn);
                if (tempMap == null) {
                    continue;
                }
                result.put(lotrrn, tempMap);
            }
            return result;
        }

        @Override
        public Lot getLot(long lotRrn) {
            Lot lot = lotQueryDAO.getLot(lotRrn);
            this.fillLotExt(lot);
            return lot;
        }

        @Override
        public int getLotCountByStatus(String lotType, String... status) {
            List<Map<String, Object>> lotList = lotQueryDAO.getLotInfoByStatus(LocalContext.getFacilityRrn(), lotType,
                                                                               status);
            return CollectionUtils.isNotEmpty(lotList) ? lotList.size() : 0;
        }

        @Override
        public Map<String, Object> getLotInfoByStatus(String lotType, int pageSize, int pageNum, String... status) {
            List<Map<String, Object>> lotList = lotQueryDAO.getLotInfoByStatus(LocalContext.getFacilityRrn(), lotType,
                                                                               status);
            Map<String, Object> lotInfo = new HashMap<String, Object>();
            if (CollectionUtils.isEmpty(lotList)) {
                return lotInfo;
            }

            lotInfo.put("totalCount", lotList.size());

            if (pageSize > 0 && pageNum > 0) {
                if (pageSize * pageNum > lotList.size()) {
                    lotList = lotList.subList(pageSize * (pageNum - 1), lotList.size());
                } else {
                    lotList = lotList.subList(pageSize * (pageNum - 1), pageSize * pageNum);
                }
            }
            lotInfo.put("lotInfo", lotList);
            return lotInfo;
        }

        @Override
        public Long getLotRrn(String lotId) {
            return lotQueryDAO.getLotRrn(lotId, LocalContext.getFacilityRrn());
        }

        @Override
        public Map<String, Object> getLotCountInfo(Map lotPortalFormMap) {
            return lotQueryDAO.getLotCountInfo(lotPortalFormMap);
        }

        @Override
        public Lot getLotByCarrierId(String carrierId, Long facilityRrn) {
            Lot lot = new Lot();
            // 因为设备的object也为entity，因此加上object_type保证唯一性
            long carrierRrn = namedObjectManager.getNamedObjectRrn(carrierId, namedObjectManager.getNamedSpace(facilityRrn,
                                                                                                               ObjectList.ENTITY_KEY),
                                                                   ObjectList.ENTITY_KEY, ObjectList.CARRIER_KEY);
            if (carrierRrn > 0) {
                lot = lotQueryDAO.getLotByCarrierId(carrierRrn);
            }
            this.fillLotExt(lot);
            return lot;
        }

        @Override
        public Lot getLotByCarrierRrn(Long carrierRrn) {
            Lot lot = new Lot();
            // 因为设备的object也为entity，因此加上object_type保证唯一性
            if (carrierRrn > 0) {
                lot = lotQueryDAO.getLotByCarrierId(carrierRrn);
            }
            this.fillLotExt(lot);
            return lot;
        }

        @Override
        public Lot getLotExt(Lot lotExt) {
            return lotQueryDAO.getLotExt(lotExt);
        }

        @Override
        public List<Lot> getLotListByCarrierRrn(Long carrierRrn) {
            return lotQueryDAO.getLotListByCarrierRrn(carrierRrn);
        }

        @Override
        public List<Lot> getLotListByCarrierId(String carrierId, Long facilityRrn) {
            List<Lot> lotList = new ArrayList<>();
            // 因为设备的object也为entity，因此加上object_type保证唯一性
            long carrierRrn = namedObjectManager.getNamedObjectRrn(carrierId, namedObjectManager.getNamedSpace(facilityRrn,
                                                                                                               ObjectList.ENTITY_KEY),
                                                                   ObjectList.ENTITY_KEY, ObjectList.CARRIER_KEY);
            if (carrierRrn > 0) {
                lotList = lotQueryDAO.getLotListByCarrierRrn(carrierRrn);
            }
            return lotList;
        }

        @Override
        public List<Lot> getLotsByEqpWithStatus(long eqpRrn, String... lotStatus) {
            return lotQueryDAO.getLotsByEqpWithStatus(eqpRrn, lotStatus);
        }

        @Override
        public List<Map> getLotList4ExtAtEqpt(Map criterion) {
            // 派工页面查询条件
            String sapphire = MapUtils.getString(criterion, "Sapphire");
            String lotId = MapUtils.getString(criterion, "lotId");
            String proId = MapUtils.getString(criterion, "proId");
            String _objectRrn = MapUtils.getString(criterion, "objectRrn");
            String objectType = MapUtils.getString(criterion, "objectType");
            Object stationRrn = criterion.get("stationRrn");
            String objectRrn = _objectRrn.split("#\\$#")[0];

            StringBuffer whereSql = new StringBuffer(
                    " WHERE 1 = 1 AND  LOT.LOT_RRN = LOT_EXT.LOT_RRN  AND LOT.LOT_RRN = T.LOT_RRN(+) ");
            if (criterion.get(LOT_STATUS) != null) {
                ArrayList statusList = (ArrayList) criterion.get(LOT_STATUS);
                whereSql.append(" AND (LOT.LOT_STATUS='" + statusList.remove(0) + "'");
                for (Iterator iterator = statusList.iterator(); iterator.hasNext(); ) {
                    String status = (String) iterator.next();
                    whereSql.append(" OR LOT.LOT_STATUS='" + status + "'");
                }
                whereSql.append(" ) ");
            }

            if (criterion.get(DUMMY_FLAG) != null) {
                whereSql.append(" AND  DUMMY_FLAG = '" + criterion.get(DUMMY_FLAG) + "'");
            }

            if (objectType != null) {
                objectRrn = _objectRrn.replace("#$#", ",");
                whereSql.append(" AND ((lot.operation_rrn IN (SELECT o.operation_rrn FROM operation o WHERE " + "o" +
                                        ".entity_group_rrn in (SELECT distinct to_rrn FROM relation t WHERE t" +
                                        ".link_type" + "='ENTITY_TO_ENTITY_GROUP' AND t.from_rrn IN (" + objectRrn +
                                        ") ) ) ) ");
                // 如果批次操作了 更新作业菜单 (批次特殊化改变设备) 则可以在派工页面显示批次
                whereSql.append(
                        "OR LOT_EXT.ATTRIBUTE_DATA3 IN (select INSTANCE_ID from NAMED_OBJECT where INSTANCE_RRN" + " IN " +
                                "(" + objectRrn + ")))");
            }

            if (stationRrn != null) {
                whereSql.append(
                        " AND ((lot.operation_rrn IN (SELECT distinct to_rrn FROM relation t WHERE t" + ".link_type" +
                                "='STATION_TO_OPERATION' AND t.from_rrn=" + stationRrn + " ) )) ");
            }

            // 查询Running和Processed作业时需要关联JOB表
            if (criterion.get("jobGridFlag") != null && ((Boolean) criterion.get("jobGridFlag")).booleanValue()) {
                whereSql.append(" AND  LOT.JOB_RRN=JOB.JOB_RRN AND JOB.EQPT_RRN in (" + objectRrn + ")");
                whereSql = (new StringBuffer(" ," + DataBaseNames.JOB)).append(whereSql);
            }
            // 查询Bonding批次
            if (sapphire != null && sapphire.equalsIgnoreCase("isSapphire")) {
                whereSql.append("AND LOT.PRODUCT_RRN IN (SELECT INSTANCE_RRN FROM NAMED_OBJECT WHERE OBJECT_TYPE=" +
                                        MiscUtils.parseSQL(ObjectList.SAPPHIRE) + ")");
            }
            // 查询非Bonding批次
            if (sapphire != null && sapphire.equalsIgnoreCase("notSapphire")) {
                whereSql.append("AND LOT.PRODUCT_RRN NOT IN (SELECT INSTANCE_RRN FROM NAMED_OBJECT WHERE OBJECT_TYPE=" +
                                        MiscUtils.parseSQL(ObjectList.SAPPHIRE) + ")");
            }
            // 派工页面查询条件
            if (lotId != null && !lotId.equals("")) {
                whereSql.append(" AND LOT_ID LIKE UPPER (" + "'" + '%' + lotId + '%' + "'" + ")");
            }
            if (proId != null && !proId.equals("")) {
                whereSql.append(
                        " AND PRODUCT_RRN IN ( SELECT INSTANCE_RRN FROM NAMED_OBJECT WHERE INSTANCE_ID IN " + "(SELECT " +
                                "INSTANCE_ID FROM NAMED_OBJECT where INSTANCE_ID LIKE UPPER (" + "'" + '%' + proId + '%' +
                                "'" + ")))");
            }

            int limit = 0;
            if (criterion.get("PAGESIZE") != null) {
                limit = MapUtils.getIntValue(criterion, "PAGESIZE");
            }

            //todo NPW_BANK先不要
            //whereSql.append(" AND LOT_ID NOT IN (SELECT LOT_ID FROM NPW_BANK )");
            List<Map> availableLotListWithExt = lotQueryDAO.getAvailableLotListWithExt(whereSql.toString(), limit);
            for (Map map : availableLotListWithExt) {
                map.put("recipeParam", recipeContextManager.parseRecipeParam((String) map.get("recipeRrn")));
            }
            return availableLotListWithExt;
        }

        @Override
        public PlanLot getPlanLot(PlanLot planLot) {
            PlanLot lot = lotQueryDAO.getPlanLot(planLot);
            if (lot.getProductRrn() != null && lot.getProductRrn() != 0) {
                lot.setProductId(namedObjectManager.getInstanceId(planLot.getProductRrn()));
            }
            if (lot.getDefaultProcessRrn() != null && lot.getDefaultProcessRrn() != 0) {
                lot.setDefaultProcessID(namedObjectManager.getInstanceId(planLot.getDefaultProcessRrn()));
            }
            return lot;
        }

        @Override
        public Lot getLotPlan(String lotId) {
            Lot lot = lotQueryDAO.getLotPlan(lotId);
            if (lot == null) {
                return new Lot();
            } else {
                // 补充数据
                paddingDataPlanLot(lot);
            }
            this.buildfWflSeqForLot(lot);
            return lot;
        }

        @Override
        public long getLotRrnByExecutionRrn(long executionRrn) {
            return lotQueryDAO.getlotRrnByExecutionRrn(executionRrn);
        }

        @Override
        public Page queryLotStepHistory(Page page, String lotId) {
            Long lotRrn = this.getLotRrn(lotId);

            Assert.notNull(lotRrn, Errors.create().key(MessageIdList.LOT_MISSING).content("Cannot Find Lot!").build());

            page = lotQueryDAO.queryLotStepHistory(page, lotRrn);

            List<Map> results = (List<Map>) page.getResults();

            for (Map map : results) {
                map.put("recipe_parameter", recipeContextManager.parseRecipeParam((String) map.get("recipe_string")));
                map.put("recipe_id", recipeContextManager.parseRecipeId((String) map.get("recipe_string")));

                // 补充数据
                map.put("eqpt_id", namedObjectManager.getInstanceId(MapUtils.getLongValue(map, "eqpt_rrn")));
                map.put("operation_id", namedObjectManager.getInstanceId(MapUtils.getLongValue(map, "operation_rrn")));
                map.put("operation_desc", namedObjectManager.getInstanceId(MapUtils.getLongValue(map, "operation_rrn")));
            }
            page.setResults(results);
            return page;
        }

        @Override
        public String getLotId(long lotRrn) {
            return lotQueryDAO.getLotId(lotRrn);
        }

        @Override
        public Page getLotPlanPage(Long facilityRrn, Page page, Map<String, Object> condition) {
            return lotQueryDAO.getLotPlanPage(facilityRrn, page, condition);
        }

        @Override
        public boolean checkLotStatus(Long recipeRrn, long entityRrn) {
            return lotQueryDAO.checkLotStatus(recipeRrn, entityRrn);
        }

        @Override
        public Map getLotInfoasMap(long facilityRrn, String lotId, Long carrierRrn) {

            Map lotInfo = lotQueryDAO.getLotInfoasMap(facilityRrn, lotId, carrierRrn);
            if (lotInfo != null) {
                String recipeId = "";
                long recipeLogicalRrn = MapUtils.getLong(lotInfo, "recipeLogicalRrn");
                if (recipeLogicalRrn != 0) {
                    recipeId = namedObjectManager.getInstanceId(recipeLogicalRrn);
                } else {
                    String recipeString = recipeContextManager.getRecipeString((Lot) lotInfo.get("tempLot"));
                    recipeId = recipeContextManager.parseRecipeId(recipeString);

                }
                lotInfo.put("recipeId", recipeId);

                paddingDataLotInfoMap(lotInfo);
            }
            return lotInfo;
        }

        @Override
        public Map getLotInfoasMap(long facilityRrn, String lotId) {
            return paddingDataLotInfoMap(lotQueryDAO.getLotInfoasMap(facilityRrn, lotId));
        }

        @Override
        public Long getCount(String tblName, Map condition) {
            return lotQueryDAO.getCount(tblName, condition);
        }

        @Override
        public List qryLotTransHistory(Map map, int current, int pageSize) {
            return paddingDataTrans(lotQueryDAO.qryLotTransHistory(map, current, pageSize));
        }

        @Override
        public List<Map> qryAllLotAdjustDetail(Long lotRrn) {
            return lotQueryDAO.qryAllLotAdjustDetail(lotRrn);
        }

        @Override
        public Map getLotPlanMap(String lotId) {
            Lot lot = lotQueryDAO.getLotPlan(lotId);

            if (lot == null) {
                return null;
            } else {
                paddingDataPlanLot(lot);
            }
            Map map = new HashMap();
            BeanUtils.copyBeanToMap(map, lot);
            map.put("qty1", MapUtils.getDouble(map, "qty1", new Double(0)).longValue());
            return map;
        }

        @Override
        public List queryLotPlanHistory(Map map, int current, int pageSize) {
            Page page = new Page();

            page.setPageSize(pageSize);
            page.setPageNo(current);

            List<Map> results = (List<Map>) lotQueryDAO.queryLotPlanHistory(page, map).getResults();
            // 补充数据
            for (Map m : results) {
                Long tempRrn = MapUtils.getLongValue(m, "product_rrn");
                m.put("productId", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "process_rrn");
                m.put("processId", namedObjectManager.getInstanceId(tempRrn));
            }

            return results;
        }

        @Override
        public String getHotflagSplicingPriority(Integer hotFlag, Integer priority, Long facilityRrn) {
            String result = StringUtils.EMPTY;
            if (priority != null && hotFlag != null) {
                String priorityDesc = this.getPriorityText(priority, facilityRrn);
                String hotflagDesc = this.getHotflagText(hotFlag, facilityRrn);
                result = hotflagDesc + "-" + priorityDesc;
            }

            return result;
        }

        @Override
        public Map qryAdjustTransHistory(Long transRrn, Long lotRrn) {
            return lotQueryDAO.qryAdjustTransHistory(transRrn, lotRrn);
        }

        @Override
        public Map qryTransHistoryDetail(Long transRrn, Long lotRrn) {
            return lotQueryDAO.qryTransHistoryDetail(transRrn, lotRrn);
        }

        @Override
        public List<Map> queryAllLotTrans(Long lotRrn) {
            return paddingDataAllTrans(lotQueryDAO.queryAllLotTrans(lotRrn));
        }

        @Override
        public String queryLotPurposeByLotRrn(Long lotRrn) {
            return lotQueryDAO.queryLotPurposeByLotRrn(lotRrn);
        }

        @Override
        public Map qryLotAfterTransDetail(Long transRrn, Long lotRrn) {
            return lotQueryDAO.qryLotAfterTransDetail(transRrn, lotRrn);
        }

        @Override
        public String getParamCon(Long lotRrn, String stepSequence) {
            return lotQueryDAO.getParamCon(lotRrn, stepSequence);
        }

        @Override
        public List<Map> getHoldReasons(long lotRrn) {
            List<Map> holdReasons = lotQueryDAO.getHoldReasons(lotRrn);
            Lot lot = lotQueryDAO.getLot(lotRrn);
            for (Map map : holdReasons) {
                String holdCode = (String) map.get("reasonCode");
                String holdDesc = referenceFileManager.getReferenceDetailExchange("$HOLD_CODE", holdCode, "DATA_1_VALUE");
                map.put("holdDesc", holdDesc);
                map.put("lotId", lot.getLotId());
                map.put("transQty1", lot.getQty1());
            }

            return holdReasons;
        }

        @Override
        public List<Map> getReleaseReasonCodes(String releaseReasonGroupID, List<Object> releaseRoles,
                                               String referenceFileId) {
            return lotQueryDAO.getReleaseReasonCodes(releaseReasonGroupID, releaseRoles, referenceFileId);
        }

        @Override
        public List<Map> getHoldReasonCodes(String holdReasonGroupID, List<String> holdRoles, String referenceFileId) {
            return lotQueryDAO.getHoldReasonCodes(holdReasonGroupID, holdRoles, referenceFileId);
        }

        @Override
        public List<Map> getHoldReasonCodes4HoldCodeGroupAll(String referenceFileId) {
            return lotQueryDAO.getHoldReasonCodes4HoldCodeGroupAll(referenceFileId);
        }

        @Override
        public List<Map> getReleaseGroup(String holdCode, String classTableValue) {
            return lotQueryDAO.getReleaseGroup(holdCode, classTableValue);
        }

        @Override
        public Lot qryLotExtInfo(long lotRrn) {
            Lot lot = lotQueryDAO.qryLotExtInfo(lotRrn);
            String reticleGroupId = namedObjectManager.getInstanceId(lot.getReticleGroupRrn());
            if (reticleGroupId == null) {
                reticleGroupId = "";
            }
            lot.setReticleGroupId(reticleGroupId);
            return lot;
        }

        @Override
        public boolean isMultipleHoldExisted(long lotRrn) {
            return lotQueryDAO.isMultipleHoldExisted(lotRrn);
        }

        @Override
        public List qryLotCreateHistory(long lotRrn, int current, int pageSize) {
            return lotQueryDAO.qryLotCreateHistory(lotRrn, current, pageSize);
        }

        @Override
        public String getConsumedMaterial(Long lotRrn) {
            return lotQueryDAO.getConsumedMaterial(lotRrn);
        }

        @Override
        public int countPilotLotInfo(long lotRrn) {
            return lotQueryDAO.countPilotLotInfo(lotRrn);
        }

        @Override
        public PilotLotInfo getPilotLotInfo(long lotRrn) {
            return lotQueryDAO.getPilotLotInfo(lotRrn);
        }

        @Override
        public List<Map> getLotsByReticle(long reticleRrn) {
            return lotQueryDAO.getLotsByReticle(reticleRrn);
        }

        @Override
        public List qryLotHoldReleaseHistory(long lotRrn) {
            List list = lotQueryDAO.qryLotHoldReleaseHistory(lotRrn);
            paddingDataHoldRelease(list);
            for (Object obj : list) {
                Map map = (Map) obj;
                //            if ("query".equals(type)) {
                String recipeId = recipeManager.buildRecipePhysicalId(MapUtils.getString(map, "recipeId"), map);
                map.put("recipePhysicalId", recipeId);
                //            } else if ("export".equals(type)) {
                //                String recipeString = recipeContextManager.getRecipeString((Lot) map.get
                //                ("tempLot"));
                //                String recipeId     = recipeContextManager.parseRecipeId(recipeString);
                //                map.put("recipePhysicalId", recipeId);
                //            }

                // TODO: 2020/9/29 按照Dao层逻辑转换Key/Value。 由于涉及地方较多，优先保证使用不出错。 后续需要优化
                map.put("operationId", MapUtils.getString(map, "operation_id"));
                map.put("processId", MapUtils.getString(map, "technology_id"));
                map.put("productId", MapUtils.getString(map, "product_id"));
            }

            return list;
        }

        @Override
        public Page qryLotHoldReleaseHistory(Page page, long lotRrn, String lotTransId, String type) {
            Page pageH = lotQueryDAO.qryLotHoldReleaseHistory(page, lotRrn, lotTransId, type);
            List<Map> list = (List<Map>) pageH.getResults();
            paddingDataHoldRelease(list);
            for (Map map : list) {
                String recipeId = recipeManager.buildRecipePhysicalId(MapUtils.getString(map, "recipeId"), map);
                map.put("recipePhysicalId", recipeId);
                // TODO: 2020/9/29 按照Dao层逻辑转换Key/Value。 由于涉及地方较多，优先保证使用不出错。 后续需要优化
                map.put("operationId", MapUtils.getString(map, "operation_id"));
                map.put("processId", MapUtils.getString(map, "technology_id"));
                map.put("productId", MapUtils.getString(map, "product_id"));
            }

            return pageH;
        }

        @Override
        public Page qryLotHoldInfoForRelease(Page page, long lotRrn, long transRrn) {
            page = lotQueryDAO.qryLotHoldInfoForRelease(page, lotRrn, transRrn);
            paddingDataHoldRelease((List) page.getResults());
            for (Object obj : page.getResults()) {
                Map lotInfo = (Map) obj;
                String recipeString = recipeContextManager.getRecipeString((Lot) lotInfo.get("tempLot"));
                String recipeId = recipeContextManager.parseRecipeId(recipeString);
                lotInfo.put("recipeId", recipeId);
            }
            return page;
        }

        @Override
        public List qryLotSplitMergeHistory(long lotRrn, String startDate, String endDate, Integer thisPage,
                                            Integer pageSize, String type, String sourceLotId) {
            List list = lotQueryDAO.qryLotSplitMergeHistory(lotRrn, startDate, endDate, thisPage, pageSize, type,
                                                            sourceLotId);
            paddingDataSplitMergeHistory(list);
            for (Object obj : list) {
                Map map = (Map) obj;
                String recipeId = recipeManager.buildRecipePhysicalId(MapUtils.getString(map, "recipeId"), map);
                map.put("recipePhysicalId", recipeId);
            }
            return list;
        }

        @Override
        public Long qryLotSplitMergeHistoryCount(long lotRrn, String startDate, String endDate) {
            return lotQueryDAO.qryLotSplitMergeHistoryCount(lotRrn, startDate, endDate);
        }

        @Override
        public Page qryLotSplitMergeHistory(Page page, long lotRrn, String startDate, String endDate, String sourceLotId) {
            page = lotQueryDAO.qryLotSplitMergeHistory(page, lotRrn, startDate, endDate, sourceLotId);
            paddingDataSplitMergeHistory(page);
            for (Object obj : page.getResults()) {
                Map map = (Map) obj;
                String recipeId = recipeManager.buildRecipePhysicalId(MapUtils.getString(map, "recipeId"), map);
                map.put("recipePhysicalId", recipeId);
            }
            return page;
        }

        @Override
        public List<Map> getScrapReasons(long lotRrn) {
            return lotQueryDAO.getScrapReasons(lotRrn);
        }

        @Override
        public boolean isLotsInSameJobPrepared(Long jobRrn) {
            return lotQueryDAO.isLotsInSameJobPrepared(jobRrn);
        }

        @Override
        public List<Lot> getLotsByJobRrn(Long jobRrn) {
            Assert.state(jobRrn != null, Errors.create().content("This job Rrn is null!").build());
            String whereSql = " WHERE JOB_RRN = " + jobRrn;
            return lotQueryDAO.getLots(whereSql);
        }

        @Override
        public List<TimelimitStatus> getLotTimeLimitStatusByLotRrn(Long lotRrn, String targetStatus) {
            List<TimelimitStatus> results = lotQueryDAO.getLotTimelimitStatusByLotRrn(lotRrn, targetStatus);
            if (CollectionUtils.isEmpty(results)) {
                results = Collections.emptyList();
            }
            return results;
        }

        @Override
        public String getMaxLotId(String lotId) {
            return lotQueryDAO.getMaxLotId(lotId);
        }

        @Override
        public String getLotStatus(long lotRrn) {
            return lotQueryDAO.getLotStatus(lotRrn);
        }

        @Override
        public Page qryLotStatus(Page page, Map condition) {
            page = lotQueryDAO.qryLotStatus(page, condition);

            List<Map> results = (List<Map>) page.getResults();
            paddingDataLotStatus(results);

            for (Map map : results) {
                Long productRrn = (Long) map.get("product_rrn");
                Integer productVersion = MapUtils.getInteger(map, "product_version");
                Long processRrn = (Long) map.get("process_rrn");
                Integer processVersion = (Integer) map.get("process_version");
                Long routeRrn = (Long) map.get("route_rrn");
                Long operationRrn = (Long) map.get("operation_rrn");
                Long facilityRrn = MapUtils.getLong(map, "facilityRrn");

                String recipeId = recipeContextManager.getProcessRecipeId(productRrn, productVersion, processRrn,
                                                                          processVersion, routeRrn, operationRrn);

                map.put("recipeId", recipeId);

                map.put("recipePhysicalId", recipeManager.buildRecipePhysicalId(recipeId, map));
                map.put("lotStatusReferenceData",
                        this.buildLotStatusByLotStatusReference(MapUtils.getString(map, "lot_status"), facilityRrn));

                Lot lot = this.getLot(MapUtils.getString(map, "lot_id"), facilityRrn);
                if (StringUtils.equalsIgnoreCase(LotStatus.BANKED, MapUtils.getString(map, "lot_status")) ||
                        StringUtils.equalsIgnoreCase(LotStatus.OUTSOURCING, MapUtils.getString(map, "lot_status"))) {
                    lot.setOperationRrn(lot.getPrevOperationRrn());
                    map.put("operation_id", lot.getPrevOperation());
                }
                map.put("flowSeq", resequenceContextValueManager.buildContextValue4FlowSeq(facilityRrn, lot));
                map.put("operationDesc", operationDescContextValueManager.buildContextValue4StepDesc(facilityRrn, lot));
                lot.setOperationRrn(lot.getNextOperationRrn1());
                map.put("nextOperationDesc", operationDescContextValueManager.buildContextValue4StepDesc(facilityRrn, lot));

                map.put("priorityValue",
                        this.getHotflagSplicingPriority(NumberUtils.toInt(MapUtils.getString(map, "hotFlag"), 0),
                                                        NumberUtils.toInt(MapUtils.getString(map, "priority"), 0),
                                                        facilityRrn));

                Long qty1 = MapUtils.getLongValue(map, "qty1", 0);
                if (qty1 != null) {
                    map.put("qty1", qty1);
                }

            }

            page.setResults(results);

            return page;
        }

        @Override
        public String getLayerId(Long executeRrn) {
            return lotQueryDAO.getLayerId(executeRrn);
        }

        @Override
        public List<Bonding> getBondingsByLotRrn(long targetLotRrn, String sourceLotPlanType) {
            return lotQueryDAO.getBondingsByLotRrn(targetLotRrn, sourceLotPlanType);
        }

        @Override
        public int getInuseWaferQtyForReticle(long reticleRrn) {
            return lotQueryDAO.getInuseWaferQtyForReticle(reticleRrn);
        }

        @Override
        public List<Map> getLotInfo4Transaction(Long jobRrn, Long lotRrn) {
            return lotQueryDAO.getLotInfo4Transaction(jobRrn, lotRrn);
        }

        @Override
        public List<LotRecycledInfo> queryLotRecycledInfoByLotNoVersion(LotRecycledInfo lotRecycledInfo) {
            return lotQueryDAO.queryLotRecycledInfoByLotNoVersion(lotRecycledInfo);
        }

        @Override
        public Map getQtyForUnscrap(long lotRrn) {
            return lotQueryDAO.getQtyForUnscrap(lotRrn);
        }

        @Override
        public List<Map<String,Object>>  qryLotHistoryExp(Long lotRrn) {
            return qryLotHistoryExp(lotRrn, 0, 0);
        }

        @Override
        public List<Map<String,Object>> qryLotHistoryExp(Long lotRrn, Integer startRow, Integer pageSize) {
            return paddingDataLotHistory(lotQueryDAO.qryLotHistoryExp(lotRrn, startRow, pageSize));
        }

        @Override
        public List qryLotStepHistoryComment(long lotRrn, long stepSequence, int thisPage, int pageSize) {
            return lotQueryDAO.qryLotStepHistoryComment(lotRrn, stepSequence, thisPage, pageSize);
        }

        @Override
        public List<Map> initLotStatusComboDoOrder() {
            List<ReferenceFileDetail> data = referenceFileManager.getRefFileValues("$$LOT_STATUS",
                                                                                   LocalContext.getFacilityRrn());
            List<Map> list = new ArrayList<Map>();
            for (ReferenceFileDetail rf : data) {
                Map<String, Object> combo = new HashMap<>(2);
                combo.put("key", rf.getData1Value());
                combo.put("value", rf.getKey1Value());
                list.add(combo);
            }
            return list;
        }

        @Override
        public List<Map> initLotPortalComboData(String type) {
            boolean sqlFlag = false;
            if (StringUtils.equals("workArea", type)) {
                type = "$$WORK_AREA";
            } else if (StringUtils.equals("productType", type)) {
                type = "$PRODUCT_TYPE";
            } else if (StringUtils.equals("lotType", type)) {
                type = "$LOT_TYPE";
            } else if (StringUtils.equals("project", type)) {
                type = "$$PROJECT_TYPE";
            } else if (StringUtils.equals("priority", type)) {
                type = "$$LOT_HOTFLAG";
            } else if (StringUtils.equals("userDep", type)) {
                type = "$DEPARTMENT";
            } else if (StringUtils.equals("stage", type)) {
                type = "$$STAGEID";
            } else if (StringUtils.equalsIgnoreCase("station", type)) {
                type = "STATION";
                sqlFlag = true;
            } else if (StringUtils.equals("group", type) || StringUtils.equalsIgnoreCase("ENTITYGROUP", type)) {
                type = "ENTITYGROUP";
                sqlFlag = true;
            } else if (StringUtils.equals("lotCategory", type)) {
                type = "$LOT_CREATE_CATEGORY";
            } else if (StringUtils.equalsIgnoreCase("product", type)) {
                type = "PRODUCT";
                sqlFlag = true;
            } else if (StringUtils.equals("rcLotStatus", type)) {
                type = "$$RUNCARD_LOT_STATUS";
            } else if (StringUtils.equalsIgnoreCase("PROCESS", type)) {
                type = "PROCESS";
                sqlFlag = true;
            } else if (StringUtils.equalsIgnoreCase("PROCEDURE", type)) {
                type = "PROCEDURE";
                sqlFlag = true;
            } else if (StringUtils.equals("PRODUCTDOWNGRADE", type)) {
                type = "PRODUCT";
                sqlFlag = true;
            } else if (StringUtils.equals("PARAMETER", type)) {
                type = "PARAMETER";
                sqlFlag = true;
            } else if (StringUtils.equals("PARAMETERSET", type)) {
                type = "PARAMETERSET";
                sqlFlag = true;
            }

            Map<String, List> dataMap = new HashMap<String, List>();
            List<Map> list = new ArrayList<Map>();

            if (sqlFlag) {
                String namedSpace = "";
                String object = "";
                String objectType = "";
                String objectSubType = "";
                if (StringUtils.equals("ENTITYGROUP", type)) {
                    object = ObjectList.ENTITYGROUP_KEY;
                } else if (StringUtils.equals("STATION", type)) {
                    object = ObjectList.STATION_KEY;
                } else if (StringUtils.equals("PRODUCT", type)) {
                    object = ObjectList.PRODUCT_KEY;
                } else if (StringUtils.equals("PROCESS", type)) {
                    object = ObjectList.WFL_KEY;
                    objectType = ObjectList.ROUTE_KEY;
                    objectSubType = ObjectList.PROCESS_KEY;
                } else if (StringUtils.equals("PROCEDURE", type)) {
                    object = ObjectList.WFL_KEY;
                    objectType = ObjectList.ROUTE_KEY;
                    objectSubType = ObjectList.PROCEDURE_KEY;
                } else if (StringUtils.equals("PARAMETER", type)) {
                    object = ObjectList.PARAMETER_KEY;
                } else if (StringUtils.equals("PARAMETERSET", type)) {
                    object = ObjectList.PARAMETERSET_KEY;
                }
                namedSpace = namedObjectManager.getNamedSpace(LocalContext.getFacilityRrn(), object);

                List<String> comboList = namedObjectManager.getComboDataBySql(namedSpace, object, objectType, objectSubType,
                                                                              LocalContext.getUserRrn());
                if (comboList != null && comboList.size() > 0) {
                    for (String s : comboList) {
                        Map<String, Object> combo = new HashMap<>(2);
                        combo.put("key", s);
                        combo.put("value", s);
                        list.add(combo);
                    }
                }
            } else {
                ReferenceFile referenceFile = new ReferenceFile(type, namedObjectManager.getNamedSpace(
                        LocalContext.getFacilityRrn(), ObjectList.REFERENCE_FILE_KEY), ObjectList.REFERENCE_FILE_KEY);

                referenceFile = referenceFileManager.getReferenceFile(referenceFile);
                List<ReferenceFileDetail> collection = (List<ReferenceFileDetail>) referenceFile.getValuesItems();
                // 批次类型特殊处理
                if (StringUtils.equalsIgnoreCase("$$LOT_NAMING_RULE", type)) {
                    for (ReferenceFileDetail rfd : collection) {
                        Map<String, Object> combo = new HashMap<>(2);
                        combo.put("key", rfd.getKey2Value());
                        combo.put("value", rfd.getKey2Value());
                        list.add(combo);
                    }
                } else if (StringUtils.equalsIgnoreCase("$LOT_CREATE_CATEGORY", type)) {
                    for (ReferenceFileDetail rfd : collection) {
                        Map<String, Object> combo = new HashMap<>(2);
                        combo.put("key", rfd.getData1Value());
                        combo.put("value", rfd.getKey1Value());
                        list.add(combo);
                    }
                } else {
                    for (ReferenceFileDetail rfd : collection) {
                        Map<String, Object> combo = new HashMap<>(2);
                        combo.put("key", rfd.getKey1Value());
                        combo.put("value", rfd.getData1Value());
                        list.add(combo);
                    }
                }
            }

            if (StringUtils.equalsIgnoreCase("$DEPARTMENT", type)) {
                // hold部门添加一个 System 选项
                Map<String, Object> combo = new HashMap<>(2);
                combo.put("key", "SYSTEM");
                combo.put("value", "SYSTEM");

                list.add(0, combo);
            }

            Map<String, Object> combo = new HashMap<>(2);
            if (StringUtils.equalsIgnoreCase("CN", I18nUtils.getCurrentLanguage().name())) {
                combo.put("key", "--选择--");
            } else {
                combo.put("key", "--Choice--");
            }
            combo.put("value", " ");
            list.add(0, combo);

            return list;
        }

        @Override
        public List<Map> qryConditionCombo(String type, String cascadeSource) {
            List<Map> comboList = new ArrayList<>();

            Map<String, Object> conditionMap = new HashMap<String, Object>();
            if (StringUtils.isNotBlank(cascadeSource)) {
                String[] cascadeConditionArray = cascadeSource.split(";;");
                conditionMap.put("lotId", StringUtils.trimToUpperCase(
                        StringUtils.replace(cascadeConditionArray[0], "*", "%").toString()));
                conditionMap.put("lotCategory", StringUtils.trimToUpperCase(
                        StringUtils.replace(cascadeConditionArray[1], "*", "%").toString()));
                conditionMap.put("lotType", StringUtils.trimToUpperCase(
                        StringUtils.replace(cascadeConditionArray[2], "*", "%").toString()));
                conditionMap.put("lotStatus", StringUtils.trimToUpperCase(
                        StringUtils.replace(cascadeConditionArray[3], "*", "%").toString()));
                conditionMap.put("productType", StringUtils.trimToUpperCase(
                        StringUtils.replace(cascadeConditionArray[4], "*", "%").toString()));
                conditionMap.put("product", StringUtils.trimToUpperCase(
                        StringUtils.replace(cascadeConditionArray[5], "*", "%").toString()));
                conditionMap.put("process", StringUtils.trimToUpperCase(
                        StringUtils.replace(cascadeConditionArray[6], "*", "%").toString()));
                conditionMap.put("route", StringUtils.trimToUpperCase(
                        StringUtils.replace(cascadeConditionArray[7], "*", "%").toString()));
                conditionMap.put("carrier", StringUtils.trimToUpperCase(
                        StringUtils.replace(cascadeConditionArray[8], "*", "%").toString()));
                conditionMap.put("workArea", StringUtils.trimToUpperCase(
                        StringUtils.replace(cascadeConditionArray[9], "*", "%").toString()));
                conditionMap.put("station", StringUtils.trimToUpperCase(
                        StringUtils.replace(cascadeConditionArray[10], "*", "%").toString()));
                conditionMap.put("eqptGroup", StringUtils.trimToUpperCase(
                        StringUtils.replace(cascadeConditionArray[11], "*", "%").toString()));
                conditionMap.put("hotFlag", StringUtils.trimToUpperCase(
                        StringUtils.replace(cascadeConditionArray[12], "*", "%").toString()));
                conditionMap.put("internalPriority", StringUtils.trimToUpperCase(
                        StringUtils.replace(cascadeConditionArray[13], "*", "%").toString()));
            }
            String referenceNamedSpace = namedObjectManager.getNamedSpace(LocalContext.getFacilityRrn(),
                                                                          ObjectList.REFERENCE_FILE_KEY);
            conditionMap.put("referenceNamedSpace", referenceNamedSpace);
            conditionMap.put("facilityRrn", LocalContext.getFacilityRrn());
            conditionMap.put("loginUserRrn", LocalContext.getUserRrn());

            if (StringUtils.equals("lotCategory", type)) {
                comboList = lotQueryDAO.queryLotPortalCondition(type,
                                                                "lot_base_t.create_category, lot_base_t" + ".lot_category",
                                                                "create_category", "lot_category", conditionMap);
            } else if (StringUtils.equals("lotType", type)) {
                comboList = lotQueryDAO.queryLotPortalCondition(type, "lot_base_t.lot_type", "lot_type", "lot_type",
                                                                conditionMap);
            } else if (StringUtils.equalsIgnoreCase("lotStatus", type)) {
                comboList = lotQueryDAO.queryLotPortalCondition(type,
                                                                "lot_base_t.lot_status, lot_base_t" + ".lot_status_data, " +
                                                                        "lot_base_t.status_sort, lot_base_t" +
                                                                        ".rework_category", "lot_status", "lot_status_data",
                                                                conditionMap);
                return comboList;
            } else if (StringUtils.equals("productType", type)) {
                comboList = lotQueryDAO.queryLotPortalCondition(type, "lot_base_t.object_type, lot_base_t.product_type",
                                                                "object_type", "product_type", conditionMap);
            } else if (StringUtils.equalsIgnoreCase("product", type)) {
                comboList = lotQueryDAO.queryLotPortalCondition(type, "lot_base_t.product_id", "product_id", "product_id",
                                                                conditionMap);
            } else if (StringUtils.equalsIgnoreCase("process", type)) {
                comboList = lotQueryDAO.queryLotPortalCondition(type, "lot_base_t.process_id", "process_id", "process_id",
                                                                conditionMap);
            } else if (StringUtils.equalsIgnoreCase("route", type)) {
                comboList = lotQueryDAO.queryLotPortalCondition(type, "lot_base_t.route_id", "route_id", "route_id",
                                                                conditionMap);
            } else if (StringUtils.equals("workArea", type)) {
                comboList = lotQueryDAO.queryLotPortalCondition(type,
                                                                "oe.attribute_data5 as work_area_key, " + "work_area_ref" +
                                                                        ".data_1_value as work_area_data", "work_area_key",
                                                                "work_area_data", conditionMap);
            } else if (StringUtils.equals("station", type)) {
                comboList = lotQueryDAO.queryLotPortalCondition(type, "oper_station_t.station_id", "station_id",
                                                                "station_id", conditionMap);
            } else if (StringUtils.equals("group", type)) {
                comboList = lotQueryDAO.queryLotPortalCondition(type,
                                                                "getinstanceid(o.entity_group_rrn) as " + "entity_group_id",
                                                                "entity_group_id", "entity_group_id", conditionMap);
            } else if (StringUtils.equals("priority", type)) {
                comboList = lotQueryDAO.queryLotPortalCondition(type, "lot_base_t.hot_flag_priority", "hot_flag_priority",
                                                                "hot_flag_priority", conditionMap);
            } else if (StringUtils.equals("subTechnologyId", type)) {
                List list = namedObjectManager.getNamedObjectIdList(ObjectList.SUB_TECHNOLOGY,
                                                                    namedObjectManager.getNamedSpace(
                                                                            LocalContext.getFacilityRrn(),
                                                                            ObjectList.SUB_TECHNOLOGY));
                comboList = new ArrayList<>();
                for (Object obj : list) {
                    Map map = new HashMap(3);
                    String subTechnologyId = (String) obj;
                    map.put("key", subTechnologyId);
                    map.put("value", subTechnologyId);
                    comboList.add(map);
                }
            } else if (StringUtils.equals("technologyId", type)) {
                List list = namedObjectManager.getNamedObjectIdList(ObjectList.TECHNOLOGY, namedObjectManager.getNamedSpace(
                        LocalContext.getFacilityRrn(), ObjectList.TECHNOLOGY));
                comboList = new ArrayList<>();
                for (Object obj : list) {
                    Map map = new HashMap(3);
                    String subTechnologyId = (String) obj;
                    map.put("key", subTechnologyId);
                    map.put("value", subTechnologyId);
                    comboList.add(map);
                }
            }
            Map<String, Object> combo = new HashMap<>(2);
            if (StringUtils.equalsIgnoreCase("CN", I18nUtils.getCurrentLanguage().name())) {
                combo.put("key", "--选择--");
            } else {
                combo.put("key", "--Choice--");
            }
            combo.put("value", " ");
            comboList.add(0, combo);

            return comboList;
        }

        @Override
        public List<Map> getWorkAreaAndEqptGroupAndStationComboData(String type, String operationRrns,
                                                                    String cascadeSource) {
            List<Map> comboList = new ArrayList<Map>();

            Map<String, Object> conditionMap = new HashMap<String, Object>();
            conditionMap.put("referenceNamedSpace", namedObjectManager.getNamedSpace(LocalContext.getFacilityRrn(),
                                                                                     ObjectList.REFERENCE_FILE_KEY));
            conditionMap.put("loginUserRrn", LocalContext.getUserRrn());
            List<Long> operationLongList = new ArrayList<Long>();
            if (StringUtils.isNotBlank(operationRrns)) {
                if (StringUtils.indexOf(operationRrns, ",") > 0) {
                    String[] operationrArray = operationRrns.split(",");
                    for (int i = 0; i < operationrArray.length; i++) {
                        Long operationRrn = Long.parseLong(operationrArray[i]);
                        operationLongList.add(operationRrn);
                    }
                } else {
                    operationLongList.add(Long.parseLong(operationRrns));
                }
            }
            conditionMap.put("operationRrnList", operationLongList);

            if (StringUtils.equalsIgnoreCase("workArea", type)) {
                comboList = lotQueryDAO.qryWorkAreaAndEqptGroupAndStationComboData(
                        "oe.attribute_data5 as work_area_key, work_area_ref.data_1_value as work_area_data",
                        "work_area_key", "work_area_data", conditionMap);
            } else if (StringUtils.equalsIgnoreCase("station", type)) {
                if (StringUtils.isNotBlank(cascadeSource)) {
                    conditionMap.put("eqptGroupId",
                                     StringUtils.trimToUpperCase(StringUtils.replace(cascadeSource, "*", "%").toString()));
                }
                comboList = lotQueryDAO.qryWorkAreaAndEqptGroupAndStationComboData("oper_station_t.station_id",
                                                                                   "station_id", "station_id",
                                                                                   conditionMap);
            } else if (StringUtils.equalsIgnoreCase("eqptGroup", type)) {
                if (StringUtils.isNotBlank(cascadeSource)) {
                    conditionMap.put("stationId",
                                     StringUtils.trimToUpperCase(StringUtils.replace(cascadeSource, "*", "%").toString()));
                }
                comboList = lotQueryDAO.qryWorkAreaAndEqptGroupAndStationComboData(
                        "getinstanceid(o.entity_group_rrn) as entity_group_id", "entity_group_id", "entity_group_id",
                        conditionMap);
            }

            Map<String, Object> combo = new HashMap<>(2);
            if (StringUtils.equalsIgnoreCase("CN", I18nUtils.getCurrentLanguage().name())) {
                combo.put("key", "--选择--");
            } else {
                combo.put("key", "--Choice--");
            }
            combo.put("value", " ");
            comboList.add(0, combo);
            return comboList;
        }

        @Override
        public List<Map<String, Object>> qryLotInfo(Map lotPortalFormMap, long facilityRrn, String rowStart,
                                                    String pageSize) {
            this.buildLotPortalConditionMap(lotPortalFormMap);

            int startRow = 0;
            int currentTotalRow = 10;
            if (StringUtils.isNotBlank(rowStart) && StringUtils.isNotBlank(pageSize)) {
                startRow = Integer.parseInt(rowStart);
                currentTotalRow = startRow + Integer.parseInt(pageSize);
            }

            String refNamedSpace;
            refNamedSpace = namedObjectManager.getNamedSpace(facilityRrn, ObjectList.REFERENCE_FILE_KEY);
            lotPortalFormMap.put("referenceNamedSpace", refNamedSpace);
            lotPortalFormMap.put("facilityRrn", facilityRrn);

            return lotQueryDAO.qryLotInfo(lotPortalFormMap, startRow, currentTotalRow);
        }

        @Override
        public Page qryBondedMappingInfos(String tLotId, String tUnitId, String productId, String startDateStr,
                                          String endDateStr, Page page) {
            return lotQueryDAO.qryBondedMappingInfos(tLotId, tUnitId, productId, startDateStr, endDateStr, page);
        }

        @Override
        public long getMaxOfLotByProduct(Long productRrn) {
            return lotQueryDAO.getMaxOfLotByProduct(productRrn);
        }

        @Override
        public List<Map<String, Object>> getSameEqptTrackInLotListByEqptRrn(Long eqptRrn) {
            return lotQueryDAO.getSameEqptTrackInLotListByEqptRrn(eqptRrn);
        }

        @Override
        public boolean isLotHaveMovein(long lotRrn) {
            return lotQueryDAO.isLotHaveMovein(lotRrn);
        }

        @Override
        public String getLotExtPL(long lotRrn) {
            return lotQueryDAO.getLotExtPL(lotRrn);
        }

        @Override
        public LotStepHistory getLotStepHistory(long lotRrn, long stepSequence) {
            return lotQueryDAO.getLotStepHistory(lotRrn, stepSequence);
        }

        @Override
        public Long getMinReworkInfo(Long transRrn, Long lotRrn) {
            return lotQueryDAO.getMinReworkInfo(transRrn, lotRrn);
        }

        @Override
        public Long getReutrnExe(long reworkTransRrn) {
            return lotQueryDAO.getReutrnExe(reworkTransRrn);
        }

        @Override
        public Map getReworkExecutionInfo(Long transRrn, Long lotRrn) {
            return lotQueryDAO.getReworkExecutionInfo(transRrn, lotRrn);
        }

        @Override
        public Map getReturnProcessInfo(Long reworkTransRrn, Long lotRrn) {
            return lotQueryDAO.getReturnProcessInfo(reworkTransRrn, lotRrn);
        }

        @Override
        public Lot getLotWithUnits(String lotId) {
            Lot lot = this.getLot(lotId, LocalContext.getFacilityRrn());
            lot.setUnitsInfo(unitQueryManager.getUnitListByCarrier(lot.getCarrierRrn()));
            return lot;
        }

        @Override
        public Map getReworkInfo(Long transRrn, Long lotRrn) {
            return lotQueryDAO.getReworkInfo(transRrn, lotRrn);
        }

        @Override
        public int getTotalQtyForUnscrap(long lotRrn) {
            return lotQueryDAO.getTotalQtyForUnscrap(lotRrn);
        }

        @Override
        public Lot getCompletedssLotInfo(String lotId) {
            Lot lot = lotQueryDAO.getCompletedssLotInfo(lotId);
            if (lot == null) {
                return null;
            }
            lot.setProductId(namedObjectManager.getInstanceId(lot.getProductRrn()));
            lot.setProcessId(namedObjectManager.getInstanceId(lot.getProcessRrn()));
            return lot;
        }

        @Override
        public List<Lot> getLotsForReassign(Long facilityRrn, Map<String, Object> condition) {
            List<Lot> lots = lotQueryDAO.getLotsForReassign(facilityRrn, condition);
            if (CollectionUtils.isEmpty(lots)) {
                lots = Collections.emptyList();
            }
            return lots;
        }

        @Override
        public String getUserName(String instanceId) {
            return lotQueryDAO.getUserName(instanceId);
        }

        /**
         * * 通过一个Integer类型的priority值与Long类型的facilityRrn返回其在类表中配置中配置的值，如果类表中的值没有找到，那么将显示为： "Priority Value : (The
         * Priority Value of the Lot)" 如果$$LOT_PRIORITY的类表不存在，则会报错提示 Reference File >>> "$$LOT_PRIORITY" <<< Not
         * Found !!!*
         *
         * @param priority
         * @param facilityRrn
         * @return
         */
        @Override
        public String getPriorityText(Integer priority, Long facilityRrn) {
            String result = StringUtils.EMPTY;
            if (priority != null) {
                ReferenceFileDetail referenceFileDetail = new ReferenceFileDetail();
                NamedObject namedObject = namedObjectManager.getNamedObject("$$LOT_PRIORITY", facilityRrn,
                                                                            ObjectList.REFERENCE_FILE_KEY);
                Long refFileDetailRrn = namedObject.getInstanceRrn();
                Assert.isFalse(refFileDetailRrn == null || refFileDetailRrn < 1L,
                               Errors.create().content("Reference File " + "$$LOT_PRIORITY Not " + "Found!").build());
                referenceFileDetail.setInstanceRrn(refFileDetailRrn);
                referenceFileDetail.setKey1Value(String.valueOf(priority));
                referenceFileDetail.setKey2Value(" ");

                referenceFileDetail = referenceFileManager.getReferenceFileDetail(referenceFileDetail);

                result = referenceFileDetail != null ? referenceFileDetail.getData1Value() : "Priority Value : " + priority;
            }
            return result;
        }

        @Override
        public List<Map<String, Object>> qryOperationParameters(Long lotRrn, Long stepSequence) {
            return lotQueryDAO.qryOperationParameters(lotRrn, stepSequence);
        }

        @Override
        public int getMaxFlagFromLotId(String lotId) {
            return lotQueryDAO.getMaxFlagFromLotId(lotId);
        }

        @Override
        public long getCurrentStepSequence(long lotRrn) {
            return this.getStepSequence(lotRrn, 0);
        }

        @Override
        public long getStepSequence(long lotRrn, long operationRrn) {
            return lotQueryDAO.getStepSequence(lotRrn, operationRrn);
        }

        @Override
        public List<TimeLimitSetup> getTimeLimitSetupList(Lot lot) {
            TimeLimitSetup timeLimitSetupTemp = new TimeLimitSetup();
            timeLimitSetupTemp.setStartProductRrn(lot.getProductRrn());
            timeLimitSetupTemp.setStartProcessRrn(lot.getProcessRrn());
            timeLimitSetupTemp.setStartProcessVersion(lot.getProcessVersion());
            timeLimitSetupTemp.setStartRouteRrn(lot.getRouteRrn());
            timeLimitSetupTemp.setStartOperationRrn(lot.getOperationRrn());

            return timeLimitSetUpManager.getTimeLimitSetupsByStartInfo(timeLimitSetupTemp);
        }

        @Override
        public List<Map> getLotReworkInfo(long lotRrn) {
            return lotQueryDAO.getLotReworkInfo(lotRrn);
        }

        @Override
        public Long getNewLotTransRrn(long lotRrn) {
            return lotQueryDAO.getNewLotTransRrn(lotRrn);
        }

        @Override
        public Long getHoldBy(Long transRrn, Long parentLotRrn) {
            return lotQueryDAO.getHoldBy(transRrn, parentLotRrn);
        }

        @Override
        public Map getParentLotBankInfo(long lotRrn) {
            return lotQueryDAO.getParentLotBankInfo(lotRrn);
        }

        @Override
        public Map getLotReworkInfo(Lot lot) {

            Long returnExecutionRrn = null;
            Long executionRrn = null;
            Long tooperationRrn = null;
            Integer operationVer = null;
            String toprocessStepVersion = null;
            String returnProcessStepVersion = null;
            String toprocessStepIdVersion = null;
            String totrackUnitFlag = null;
            String tokeepUnitHistoryFlag = null;
            String tostageId = null;
            String tolayerId = null;
            Long borRrn = null;
            String torecipeString = null;

            long facilityRrn = LocalContext.getFacilityRrn();
            String user = LocalContext.getUserId();

            Map<String, Object> reworkTransInfo = new HashMap<>();

            ContextValue actionCondition = reworkRouteContextValueManager.getReworkRouteContextValueByLot(lot);
            Assert.notNull(actionCondition, Errors.create().key(MessageIdList.REWORK_NO_REWORK_MARK).content(
                    "No rework mark or rework path is set on step, Lot cannot" + " " + "be reworked!").build());

            long reworkRouteRrn = NumberUtils.toLong(actionCondition.getResultValue1());
            long returnRouteNew = NumberUtils.toLong(actionCondition.getResultValue2());
            long returnOperationNew = NumberUtils.toLong(actionCondition.getResultValue3());
            int maxReworkTimes = NumberUtils.toInt(actionCondition.getResultValue4());
            String countWay = actionCondition.getResultValue6();

            this.checkLotUnitReworkSeq(lot, countWay, maxReworkTimes);

            if (returnRouteNew == 0) {// 未设置返工路径结束后返回路径时,默认当前路径的第一步
                returnRouteNew = lot.getRouteRrn();
            }
            if (returnOperationNew == 0) {
                returnOperationNew = NumberUtils.toLong(
                        wipWorkflowQueryManager.getOprationByWflTreeBeforeFirst(lot, returnRouteNew, 0));
            }

            String processStepVersion = lot.getProcessStepVersion();
            if (StringUtils.equalsIgnoreCase(ReworkConst.CountWay.BY_ROUTE.getWay(), countWay) &&
                    StringUtils.isNotBlank(processStepVersion)) {
                processStepVersion = processStepVersion.substring(0, processStepVersion.lastIndexOf("|"));
            }

            long reworkedTimes = lotQueryDAO.getReworkCount(lot.getLotRrn(), processStepVersion);
            if (reworkedTimes < maxReworkTimes) {

                long reworkWflRrn = reworkRouteRrn;
                Map matchingRules = new HashMap();
                matchingRules.put("productRrn", String.valueOf(lot.getProductRrn()));
                int reworkWflVersion = 0;
                if (StringUtils.isNotBlank(actionCondition.getResultValue5())) {
                    reworkWflVersion = Integer.parseInt(actionCondition.getResultValue5());
                }
                List<String[]> routeTree = workflowManager.getReworkWorkFlowTree(reworkWflRrn, reworkWflVersion,
                                                                                 matchingRules);

                String stepNumber = "";
                for (Iterator itt = routeTree.iterator(); itt.hasNext(); ) {
                    String[] tempString = (String[]) itt.next();
                    stepNumber = tempString[6];
                    break;
                }

                Map stepMatchingRules = new HashMap();
                stepMatchingRules.put("productRrn", String.valueOf(lot.getProductRrn()));
                stepMatchingRules.put("processRrn", lot.getProcessRrn());
                stepMatchingRules.put("lotRrn", lot.getLotRrn() + "");
                Map tempInfo = wipWorkflowQueryManager.getReworkStepsInfo(reworkWflRrn, reworkWflVersion, stepNumber,
                                                                          stepMatchingRules);
                executionRrn = (Long) tempInfo.get("executionRrn");

                String nextStep = namedObjectManager.getInstanceId(returnOperationNew);

                String reworkCategory = lot.getReworkCategory();
                tooperationRrn = (Long) tempInfo.get("operationRrn");

                operationVer = (Integer) tempInfo.get("operationVer");

                toprocessStepVersion = (String) tempInfo.get("processStepVersion");

                toprocessStepIdVersion = (String) tempInfo.get("processStepIdVersion");

                tostageId = (String) tempInfo.get("stageId");
                tolayerId = (String) tempInfo.get("layerId");

                tempInfo = (HashMap) operationManager.getOperationInfo(tooperationRrn, operationVer);
                totrackUnitFlag = (String) tempInfo.get("trackUnitFlag");
                tokeepUnitHistoryFlag = (String) tempInfo.get("keepUnitHistoryFlag");

                tempInfo = new HashMap();
                tempInfo.put("operationRrn", tooperationRrn);
                tempInfo.put("productRrn", lot.getProductRrn());
                tempInfo.put("routeRrn", WipUtils.getRouteByProcessStepVersion(toprocessStepVersion)[0]);
                tempInfo.put("technologyRrn", lot.getProcessRrn());
                tempInfo.put("recipeRrn", null);
                tempInfo.put("lotRrn", new Long(lot.getLotRrn()));
                tempInfo.put("facilityRrn", lot.getFacilityRrn());
                borRrn = bORContextValueManager.getBomRrn(tempInfo);
                torecipeString = recipeContextManager.getRecipeString(tempInfo);
                routeTree = new ArrayList();

                if (reworkCategory == null) {

                    returnProcessStepVersion = wipWorkflowQueryManager.getStepNumberByWflTreeBeforeFirst(lot,
                                                                                                         returnRouteNew,
                                                                                                         returnOperationNew);
                    Map returnMap = new HashMap();
                    Map matchingRulesForVersion = new HashMap();
                    matchingRulesForVersion.put("productRrn", String.valueOf(lot.getProductRrn()));
                    matchingRulesForVersion.put("processRrn", lot.getProcessRrn());
                    matchingRulesForVersion.put("lotRrn", lot.getLotRrn() + "");
                    int avtiveVersion = objectVersionManager.getActiveVersion(lot.getProcessRrn(), true);
                    returnMap = wipWorkflowQueryManager.getStepsInfoByVersion(lot.getProcessRrn(), avtiveVersion,
                                                                              returnProcessStepVersion,
                                                                              matchingRulesForVersion);
                    returnExecutionRrn = (Long) returnMap.get("executionRrn");

                } else {
                    // modify byfan 所有返回步骤都有用户设置，直接取
                    returnProcessStepVersion = wipWorkflowQueryManager.getStepNumberByWflTreeBeforeFirst(lot,
                                                                                                         returnRouteNew,
                                                                                                         returnOperationNew);
                    Map MatchingRules = new HashMap();
                    MatchingRules.put("productRrn", String.valueOf(lot.getProductRrn()));
                    MatchingRules.put("processRrn", lot.getProcessRrn());
                    MatchingRules.put("lotRrn", lot.getLotRrn() + "");
                    Map returnMap = wipWorkflowQueryManager.getStepsInfo(lot.getProcessRrn(), returnProcessStepVersion,
                                                                         MatchingRules);
                    returnExecutionRrn = (Long) returnMap.get("executionRrn");
                }

                if ((lot.getReworkCategory() != null) && (returnProcessStepVersion != null)) {
                    if (returnProcessStepVersion.indexOf("|") > 0) {
                        returnProcessStepVersion = returnProcessStepVersion.substring(
                                returnProcessStepVersion.indexOf("|") + 1);
                    }
                }

                reworkTransInfo.put("reworkWflRrn", new Long(reworkWflRrn));
                reworkTransInfo.put("stepNumber", stepNumber);
                reworkTransInfo.put("lotRrn", new Long(lot.getLotRrn()));
                reworkTransInfo.put("lotId", lot.getLotId());
                reworkTransInfo.put("productRrn", lot.getProductRrn());
                reworkTransInfo.put("processRrn", lot.getProcessRrn());
                reworkTransInfo.put("processVersion", lot.getProcessVersion());
                reworkTransInfo.put("qty", "" + lot.getQty1());
                reworkTransInfo.put("executionRrn", executionRrn);
                reworkTransInfo.put("fromOperation", lot.getOperationId());
                reworkTransInfo.put("operationRrn", tooperationRrn);
                reworkTransInfo.put("operationId", namedObjectManager.getInstanceId(tooperationRrn));
                String returnOperation = nextStep;
                reworkTransInfo.put("returnOperationId", returnOperation);
                reworkTransInfo.put("operationVer", operationVer);
                reworkTransInfo.put("processStepVersion", toprocessStepVersion);
                reworkTransInfo.put("routeId", WipUtils.getRouteByProcessStepVersion(toprocessStepIdVersion)[0]);
                reworkTransInfo.put("processStepIdVersion", toprocessStepIdVersion);
                reworkTransInfo.put("trackUnitFlag", totrackUnitFlag);
                reworkTransInfo.put("keepUnitHistoryFlag", tokeepUnitHistoryFlag);
                reworkTransInfo.put("stageId", tostageId);
                reworkTransInfo.put("layerId", tolayerId);
                reworkTransInfo.put("recipeString", torecipeString);
                reworkTransInfo.put("borRrn", borRrn);

                if ((returnProcessStepVersion != null) && !returnProcessStepVersion.equals("")) {
                    Map routeMap = new HashMap();
                    routeMap.put("Process", lot.getProcessRrn());
                    routeMap.put("Route", new Long(returnRouteNew));
                    routeMap.put("Operation", new Long(returnOperationNew));
                    reworkTransInfo.put("returnProcessStepVersion",
                                        wipWorkflowQueryManager.reconstructRouteMap(returnProcessStepVersion, routeMap));
                } else {
                    reworkTransInfo.put("returnProcessStepVersion", lot.getProcessStepVersion());
                }

                reworkTransInfo.put("returnProcessStepVersion4wfl", returnProcessStepVersion);
                String returnRouteId = WipUtils.getRouteByProcessStepVersion(
                        MapUtils.getString(reworkTransInfo, "returnProcessStepVersion"))[0];

                reworkTransInfo.put("returnRouteId", returnRouteId);
                reworkTransInfo.put("reworkCategory", "REWORK");
                reworkTransInfo.put("transPerformedby", user);
                reworkTransInfo.put("returnExecutionRrn", returnExecutionRrn);

                reworkTransInfo.put("RETURN_ROUTE_NEW_ID", namedObjectManager.getInstanceId(returnRouteNew));
                reworkTransInfo.put("RETURN_OPERATION_NEW_ID", namedObjectManager.getInstanceId(returnOperationNew));
            } else {
                throw new SystemIllegalArgumentException(
                        Errors.create().content("Exceed max rework times,it can not rework").build());
            }
            return reworkTransInfo;

        }

        @Override
        public List getSplitLotInfo(long lotRrn, long facilityRrn) {
            List<Map> splitLotInfo = lotQueryDAO.getSplitLotInfo(lotRrn, facilityRrn);
            paddingDataSplitLotInfo(splitLotInfo);
            List resultList = new ArrayList();
            for (Map splitLotMap : splitLotInfo) {
                splitLotMap.put("lotStatusReferenceData",
                                this.buildLotStatusByLotStatusReference(MapUtils.getString(splitLotMap, "lotStatus"),
                                                                        facilityRrn));
                if (StringUtils.equals(MapUtils.getString(splitLotMap, "lotStatus"), LotStatus.BANKED)) {
                    Lot lot = this.getLot(MapUtils.getString(splitLotMap, "splitLotId"), facilityRrn);
                    lot.setOperationRrn(lot.getPrevOperationRrn());
                    splitLotMap.put("prevOperation", lot.getPrevOperation());
                }
                resultList.add(splitLotMap);
            }
            return resultList;
        }

        @Override
        public long getReworkSeq(long lotRrn, String reworkRouteRrn) {
            return lotQueryDAO.getReworkSeq(lotRrn, reworkRouteRrn);
        }

        @Override
        public List<LotFutureReassign> getLotFutureReassigns(long lotRrn, String curWflStepPath) {
            return lotQueryDAO.getLotFutureReassigns(lotRrn, curWflStepPath);
        }

        @Override
        public Map getStepsInfoByLot(Lot lot, Long processRrn, Integer processVer, String stepPath) {
            Map matchingRules = new HashMap();
            matchingRules.put("productRrn", String.valueOf(lot.getProductRrn()));
            matchingRules.put("processRrn", processRrn);
            matchingRules.put("lotRrn", lot.getLotRrn() + "");
            return wipWorkflowQueryManager.getStepsInfo(processRrn, stepPath, matchingRules);
        }

        @Override
        public Map getStepsInfoByLot(Lot lot, Long routeRrn, String stepPath) {
            int avtiveVersion = objectVersionManager.getActiveVersion(routeRrn, true);

            return this.getStepsInfoByLot(lot, routeRrn, avtiveVersion, stepPath);
        }

        @Override
        public Map getReworkStepsInfoByLot(Lot lot, Long routeRrn, int routeVersion, String stepPath) {
            if (routeVersion > 0) {
                return this.getStepsInfoByLot(lot, routeRrn, routeVersion, stepPath);
            }
            int avtiveVersion = objectVersionManager.getActiveVersion(routeRrn, true);
            return this.getStepsInfoByLot(lot, routeRrn, avtiveVersion, stepPath);
        }

        @Override
        public List<Map> getFutureholdLotList(Map lotMap) {
            lotMap.put("routeSeq", StringUtils.isEmpty(
                    MapUtils.getString(lotMap, "routeSeq")) ? StringUtils.WRITE_SPACE : MapUtils.getString(lotMap,
                                                                                                           "routeSeq"));
            lotMap.put("operationSeq", StringUtils.isEmpty(
                    MapUtils.getString(lotMap, "operationSeq")) ? StringUtils.WRITE_SPACE : MapUtils.getString(lotMap,
                                                                                                               "operationSeq"));
            List<Map> futureHoldLotList = lotQueryDAO.getFutureholdLotList(lotMap);
            if (CollectionUtils.isEmpty(futureHoldLotList)) {
                return null;
            }

            for (Map lotInfo : futureHoldLotList) {
                lotInfo.put("routeId", namedObjectManager.getNamedObjectId(MapUtils.getLongValue(lotInfo, "routeRrn")));
                lotInfo.put("operationId",
                            namedObjectManager.getNamedObjectId(MapUtils.getLongValue(lotInfo, "operationRrn")));
            }

            return futureHoldLotList;
        }

        @Override
        public List<Map> getFutureholdProductList(Map productMap) {
            List<Map> futureHoldProductList = lotQueryDAO.getFutureholdProductList(productMap);

            if (CollectionUtils.isEmpty(futureHoldProductList)) {
                return null;
            }

            for (Map futureHoldMap : futureHoldProductList) {

                Map tempInfo = new HashMap();
                tempInfo.put("operationRrn", MapUtils.getLongValue(futureHoldMap, "operationRrn"));
                tempInfo.put("productRrn", MapUtils.getLongValue(futureHoldMap, "productRrn"));
                tempInfo.put("routeRrn", MapUtils.getLongValue(futureHoldMap, "routeRrn"));
                tempInfo.put("technologyRrn", MapUtils.getLongValue(futureHoldMap, "technologyRrn"));
                tempInfo.put("recipeRrn", null);

                tempInfo.put("lotRrn", null);

                tempInfo.put("equipmentModel", null);
                tempInfo.put("lotId", null);
                tempInfo.put("facilityRrn", null);
                tempInfo.put("entityRrn", null);
                tempInfo.put("productLayer", null);

                String recipeString = recipeContextManager.getRecipeString(tempInfo);

                String recipeId = recipeContextManager.parseRecipeId(recipeString);
                futureHoldMap.put("recipeId", recipeId);

                futureHoldMap.put("processId",
                                  namedObjectManager.getNamedObjectId(MapUtils.getLongValue(futureHoldMap, "processRrn")));
                futureHoldMap.put("routeId",
                                  namedObjectManager.getNamedObjectId(MapUtils.getLongValue(futureHoldMap, "routeRrn")));
                futureHoldMap.put("operationId", namedObjectManager.getNamedObjectId(
                        MapUtils.getLongValue(futureHoldMap, "operationRrn")));
                futureHoldMap.put("operationDesc", namedObjectManager.getNamedObjectDesc(
                        MapUtils.getLongValue(futureHoldMap, "operationRrn")));
            }

            return futureHoldProductList;
        }

        @Override
        public List<Map> getFutureholdOperationList(long refRrn, long operationRrn) {
            List<Map> futureHoldOperationList = lotQueryDAO.getFutureholdOperationList(refRrn, operationRrn);

            if (CollectionUtils.isEmpty(futureHoldOperationList)) {
                return null;
            }

            for (Map futureHoldMap : futureHoldOperationList) {
                futureHoldMap.put("operationId", namedObjectManager.getNamedObjectId(
                        MapUtils.getLongValue(futureHoldMap, "operationRrn")));
            }
            return futureHoldOperationList;
        }

        @Override
        public String getPreviousStationStep(Lot lot) {
            return lotQueryDAO.getPreviousStationStep(lot);
        }

        @Override
        public boolean isMaterialMapping(Lot lot) {
            return lotQueryDAO.isMaterialMapping(lot);
        }

        @Override
        public int queryLotExtCount(long lotRrn) {
            return lotQueryDAO.queryLotExtCount(lotRrn);
        }

        @Override
        public List<Map> getLotList4Ext(Map condition) {
            // 处理条件中的 lot category数组
            String[] lotCategoryArray = (String[]) MapUtils.getObject(condition, "lotCategory");
            String lotCategoryStr = StringUtils.EMPTY;
            if (lotCategoryArray != null && lotCategoryArray.length > 0) {
                for (int i = 0; i < lotCategoryArray.length; i++) {
                    if (StringUtils.isNotBlank(lotCategoryArray[i])) {
                        lotCategoryStr += "'" + lotCategoryArray[i] + "'";
                        if (i != (lotCategoryArray.length - 1)) {
                            lotCategoryStr += ", ";
                        }
                    }
                }
            }
            condition.put("lotCategory", lotCategoryStr);

            // 条件lotID，productID处理
            if (StringUtils.isNotBlank(MapUtils.getString(condition, "lotId"))) {
                String lotId = MapUtils.getString(condition, "lotId");
                if (StringUtils.indexOf(lotId, "*") > -1) {
                    lotId = StringUtils.replace(lotId, "*", "%").toString();
                    condition.put("lotId", StringUtils.trimToUpperCase(lotId));
                }
            }
            if (StringUtils.isNotBlank(MapUtils.getString(condition, "proId"))) {
                String productId = MapUtils.getString(condition, "proId");
                if (StringUtils.indexOf(productId, "*") > -1) {
                    productId = StringUtils.replace(productId, "*", "%").toString();
                    condition.put("proId", StringUtils.trimToUpperCase(productId));
                }
            }
            List<Map> list = lotQueryDAO.getLotList4Ext(condition);
            for (Map map : list) {
                map.put("carrierId", namedObjectManager.getNamedObjectId(MapUtils.getLong(map, "CARRIER_RRN")));
                map.put("operationId", namedObjectManager.getNamedObjectId(MapUtils.getLong(map, "operationRrn")));
                map.put("operationDesc", namedObjectManager.getNamedObjectDesc(MapUtils.getLong(map, "operationRrn")));
                map.put("reticleId", namedObjectManager.getNamedObjectId(MapUtils.getLong(map, "reticleRrn")));
                map.put("productId", namedObjectManager.getNamedObjectId(MapUtils.getLong(map, "productRrn")));
                map.put("processId", namedObjectManager.getNamedObjectId(MapUtils.getLong(map, "processRrn")));
                String recipeId = "";
                if (StringUtils.isNotBlank(MapUtils.getString(map, "recipePhysicalId"))) {
                    recipeId = MapUtils.getString(map, "recipePhysicalId");
                } else if (MapUtils.getLongValue(map, "recipeLogicalRrn") == 0 ||
                        StringUtils.equalsIgnoreCase(MapUtils.getString(map, "lotStatus"), LotStatus.HOLD) ||
                        StringUtils.equalsIgnoreCase(MapUtils.getString(map, "lotStatus"), LotStatus.WAITING)) {
                    HashMap tempInfo = new HashMap();
                    tempInfo.put("operationRrn", MapUtils.getLong(map, "operationRrn"));
                    tempInfo.put("productRrn", MapUtils.getLong(map, "productRrn"));

                    tempInfo.put("routeRrn", MapUtils.getString(map, "routeRrn"));
                    tempInfo.put("technologyRrn", MapUtils.getLong(map, "processRrn"));
                    tempInfo.put("recipeRrn", null);

                    tempInfo.put("lotRrn", MapUtils.getLong(map, "lotRrn"));

                    tempInfo.put("equipmentModel", null);
                    tempInfo.put("lotId", MapUtils.getString(map, "lotId"));
                    tempInfo.put("facilityRrn", MapUtils.getLong(map, "facilityRrn"));
                    tempInfo.put("entityRrn", MapUtils.getLongValue(map, "equipmentRrn"));
                    tempInfo.put("productLayer", MapUtils.getString(map, "productLayer"));
                    tempInfo.put("routeSeq", MapUtils.getString(map, "routeSeq"));
                    tempInfo.put("operationSeq", MapUtils.getString(map, "operationSeq"));
                    tempInfo.put("processVersion", MapUtils.getInteger(map, "processVersion"));

                    String recipeString = recipeContextManager.getRecipeString(tempInfo);
                    recipeId = recipeContextManager.parseRecipeId(recipeString);
                } else {
                    recipeId = namedObjectManager.getNamedObjectId(MapUtils.getLong(map, "recipeLogicalRrn"));
                }
                map.put("recipeId", recipeId);
            }
            return list;
        }

        @Override
        public LotExt getLotExt(LotExt lotExt) {
            return lotQueryDAO.getLotExt(lotExt);
        }

        @Override
        public List<Map<String, Object>> getProcessAllReworkStepInfoByLot(long lotRrn, Long productRrn, String flowSeq,
                                                                          long pageSize, int processVersion,
                                                                          Integer productVersion) {
            return lotQueryDAO.getProcessAllReworkStepInfoByLot(lotRrn, productRrn, flowSeq, pageSize, processVersion,
                                                                productVersion);
        }

        @Override
        public List<TimelimitStatus> getLotTimeLimitStatusForNormal() {
            return lotQueryDAO.getLotTimeLimitStatusForNormal();
        }

        @Override
        public List<Map> getComboItems(long facilityRrn, String type, String likeValue) {
            List<Map> result = new ArrayList<>();
            if (StringUtils.equalsIgnoreCase(type, "lotCategory")) {
                List<ReferenceFileDetail> valueArrays = referenceFileManager.getReferenceFileDetails(
                        namedObjectManager.getNamedObjectRrn(ReferenceDetailNames.LOT_CREATE_CATEGORY, facilityRrn,
                                                             ObjectList.REFERENCE_FILE_KEY));
                String category = referenceFileManager.referenceDetailExchangeByKey2(ReferenceDetailNames.LOT_NAMING_RULE,
                                                                                     likeValue, "KEY_1_VALUE");
                for (ReferenceFileDetail object : valueArrays) {
                    if (StringUtils.isEmpty(likeValue) || StringUtils.equals(object.getKey1Value(), category)) {
                        Map<String, String> map = new HashMap<>();
                        map.put("key", object.getKey1Value());
                        map.put("value", object.getData1Value());
                        result.add(map);
                    }
                }
            }
            if (StringUtils.equalsIgnoreCase(type, "lotType")) {
                List<ReferenceFileDetail> valueArrays = referenceFileManager.getReferenceFileDetails(
                        namedObjectManager.getNamedObjectRrn(ReferenceDetailNames.LOT_TYPE, facilityRrn,
                                                             ObjectList.REFERENCE_FILE_KEY));
                for (ReferenceFileDetail object : valueArrays) {
                    if (StringUtils.isEmpty(likeValue) || StringUtils.equals(object.getKey1Value(), likeValue)) {
                        Map<String, String> map = new HashMap<>();
                        map.put("key", object.getKey1Value());
                        map.put("value", object.getData1Value());
                        result.add(map);
                    }
                }
            }

            List<String> values = Collections.emptyList();
            if (StringUtils.equalsIgnoreCase(type, ObjectList.PRODUCT_KEY)) {
                if (StringUtils.isEmpty(likeValue)) {
                    values = this.getInstanceIdsInLotAndLotPlan("PRODUCT_RRN");
                } else {
                    values = this.getProductOrProcessByRelationInLotAndLotPlan("PRODUCT_ID", "PROCESS_ID", likeValue);
                }
            }

            if (ObjectList.PROCESS_KEY.equalsIgnoreCase(type)) {
                if (StringUtils.isEmpty(likeValue)) {
                    values = this.getInstanceIdsInLotAndLotPlan("PROCESS_RRN");
                } else {
                    values = this.getProductOrProcessByRelationInLotAndLotPlan("PROCESS_ID", "PRODUCT_ID", likeValue);
                }
            }

            if ("outerOrderNo".equalsIgnoreCase(type)) {
                values = lotQueryDAO.getFieldValueInLotAndLotPlan("OUTERORDERNO");
            }

            if ("outOrderType".equalsIgnoreCase(type)) {
                values = lotQueryDAO.getFieldValueInLotAndLotPlan("OUT_ORDER_TYPE");
            }

            if ("shippingCode".equalsIgnoreCase(type)) {
                values = lotQueryDAO.getFieldValueInLotAndLotPlan("SHIPPINGCODE");
            }

            if ("customerId".equalsIgnoreCase(type)) {
                values = lotQueryDAO.getFieldValueInLotAndLotPlan("CUSTOMER_ID");
            }

            if ("lotOwner".equalsIgnoreCase(type)) {
                values = lotQueryDAO.getFieldValueInLotAndLotPlan("LOT_OWNER");
            }

            if ("priority".equalsIgnoreCase(type)) {
                List<String[]> valueArrays = lotQueryDAO.getPriorityInLotAndLotPlan();
                Set set = new HashSet();
                for (String[] strings : valueArrays) {
                    Map<String, String> map = new HashMap<>();
                    String hotFlagValue = strings[0];
                    String priorityValue = strings[1];
                    String priority = referenceFileManager.referenceDetailExchange(ReferenceDetailNames.LOT_PRIORITY,
                                                                                   priorityValue, "DATA_1_VALUE");
                    map.put("key",
                            referenceFileManager.referenceDetailExchange(ReferenceDetailNames.LOT_HOTFLAG, hotFlagValue,
                                                                         "DATA_1_VALUE") + "-" +
                                    (StringUtils.isEmpty(priority) ? 0 : priority));
                    map.put("value", hotFlagValue + "-" + (StringUtils.isEmpty(priorityValue) ? 0 : priorityValue));
                    if (set.add(map)) {
                        result.add(map);
                    }
                }
            }

            if ("lotStatus".equalsIgnoreCase(type)) {
                result = this.initLotStatusComboDoOrder();
                return result;
            }

            for (String string : values) {
                Map<String, String> map = new HashMap<>();
                map.put("key", string);
                map.put("value", string);
                result.add(map);
            }

            return result;
        }

        @Override
        public Page getLotPlanPage(long facilityRrn, int pageSize, int pageNo, Map<String, Object> params) {
            Page page = new Page();

            page.setPageSize(pageSize);
            page.setPageNo(pageNo);

            page = this.getLotPlanPage(facilityRrn, page, params);
            for (Object object : page.getResults()) {
                Map<String, Object> map = (Map<String, Object>) object;

                map.put("routeRrn", WipUtils.getRouteRrnByProcessStep(MapUtils.getString(map, "processStepVersion")));

                String userId = MapUtils.getString(map, "createdUserId");
                if (StringUtils.isNotEmpty(userId)) {
                    User user = new User(userId, namedObjectManager.getNamedSpace(facilityRrn, ObjectList.USER_KEY),
                                         ObjectList.USER_KEY);
                    user = userManager.getUser(user);
                    if (!(user == null || user.getInstanceRrn() <= 0)) {
                        map.put("createdUserId", user.getInstanceId());
                        map.put("createdUserName", user.getUserName());
                    }
                }

                map.put("createCategory",
                        referenceFileManager.referenceDetailExchange(ReferenceDetailNames.LOT_CREATE_CATEGORY,
                                                                     MapUtils.getString(map, "createCategory"),
                                                                     "DATA_1_VALUE"));
                map.put("hotFlag", referenceFileManager.referenceDetailExchange(ReferenceDetailNames.LOT_HOTFLAG,
                                                                                MapUtils.getString(map, "hotFlag"),
                                                                                "DATA_1_VALUE"));
                map.put("priority", referenceFileManager.referenceDetailExchange(ReferenceDetailNames.LOT_PRIORITY,
                                                                                 MapUtils.getString(map, "priority"),
                                                                                 "DATA_1_VALUE"));

                Long processRrn = MapUtils.getLong(map, "processRrn");
                Long routeRrn = MapUtils.getLong(map, "routeRrn");
                Long operationRrn = MapUtils.getLong(map, "operationRrn");
                Integer processVersion = MapUtils.getInteger(map, "processVersion");

                map.put("wflSeq",
                        resequenceContextValueManager.getFlowSeq(processRrn, processVersion, operationRrn, routeRrn));
                if (StringUtils.isBlank(MapUtils.getString(map, "stageId"))) {
                    Lot lot = new Lot();

                    lot.setProductRrn(MapUtils.getLong(map, "productRrn"));
                    lot.setProcessRrn(MapUtils.getLong(map, "processRrn"));
                    lot.setProcessVersion(MapUtils.getInteger(map, "processVersion"));
                    lot.setRouteRrn(MapUtils.getLong(map, "routeRrn"));
                    lot.setOperationRrn(MapUtils.getLong(map, "operationRrn"));
                    lot.setProcessStepVersion(MapUtils.getString(map, "processStepVersion"));
                    map.put("stageId", stageContextValueManager.getStageIdByContext(lot, facilityRrn));
                }
            }

            return page;
        }

        @Override
        public List<Map> getLotsByEquipment4Ext(long longValue, String operationStep, List<Map> operationMap) {
            return lotQueryDAO.getLotsByEquipment4Ext(longValue, operationStep, operationMap);
        }

        @Override
        public List<Map> queryFutureLotDetail4Extjs(long equipmentRrn, String operationStep, List<Map> operationMap) {
            List<Map> datas = lotQueryDAO.queryFutureLotDetail4Extjs(equipmentRrn, operationStep, operationMap);

            for (Map data : datas) {
                if (MapUtils.isNotEmpty(data)) {
                    data.put("carrierId", namedObjectManager.getInstanceId(MapUtils.getLongValue(data, "carrierRrn")));
                    data.put("operationId", namedObjectManager.getInstanceId(MapUtils.getLongValue(data, "operationRrn")));
                    data.put("reticleId", namedObjectManager.getInstanceId(MapUtils.getLongValue(data, "reticleRrn")));
                    data.put("productId", namedObjectManager.getInstanceId(MapUtils.getLongValue(data, "productRrn")));
                    data.put("processId", namedObjectManager.getInstanceId(MapUtils.getLongValue(data, "processRrn")));
                    data.put("operationDesc",
                             operationDescContextValueManager.getOperationDesc(MapUtils.getLongValue(data, "productRrn"),
                                                                               MapUtils.getLongValue(data, "processRrn"),
                                                                               MapUtils.getIntValue(data, "processVersion"),
                                                                               MapUtils.getLongValue(data, "routeRrn"),
                                                                               MapUtils.getLongValue(data,
                                                                                                     "operationRrn")));

                    Map tempInfo = MapUtils.getMap(data, "tempInfo");
                    RecipeContextValue recipeContextValue = recipeContextManager.buildContextValue(tempInfo);
                    List<ContextValue> contextValues = contextValueManager.simulateContextValues(recipeContextValue);
                    StringBuffer sb = new StringBuffer();
                    for (ContextValue ctxValue : contextValues) {

                        if (ctxValue == null) {
                            continue;
                        }

                        // format the correct recipe string
                        sb.append(ctxValue.getResultValue1());

                        if (ctxValue.getResultValue2() != null) {
                            sb.append("|");
                            sb.append(ctxValue.getResultValue2());
                        }

                        sb.append(",");
                    }

                    if (sb.length() > 0) {
                        if (sb.charAt(sb.length() - 1) == ',') {
                            sb.deleteCharAt(sb.length() - 1);
                        }
                    }

                    String recipeString = sb.toString();
                    String recipeId = recipeContextManager.parseRecipeId(recipeString);
                    data.put("recipeId", recipeId);
                    data.put("recipeParam", recipeContextManager.parseRecipeParam(recipeString));
                }
            }

            return datas;
        }

        @Override
        public long getParentLotRrn(long lotRrn) {
            return lotQueryDAO.getParentLotRrn(lotRrn);
        }

        @Override
        public Map getLotRecipeInfo(List<Map> lots, String lotId, String logicalRecipeId, String chamberType,
                                    String chamberEqptsId) {
            for (Object obj : lots) {
                Map lotInfo = (Map) obj;
                if (StringUtils.equals(lotId, MapUtils.getString(lotInfo, "lotId"))) {
                    Long recipeGroupRrn = MapUtils.getLong(lotInfo, "recipeRrn");
                    RecipeVersion recipeGroupVersion = recipeVersionManager.getNowActiveRecipeVersion(recipeGroupRrn);

                    Long recipeLogicalRrn = null;
                    RecipeVersion recipeLogicalVersion = null;

                    String recipePhysicalId = "";
                    if (StringUtils.equalsIgnoreCase(logicalRecipeId, MapUtils.getString(lotInfo, "recipeId"))) {
                        recipeLogicalRrn = recipeGroupRrn;
                        recipeLogicalVersion = recipeGroupVersion;
                    } else {
                        recipeLogicalRrn = namedObjectManager.getNamedObjectRrn(logicalRecipeId,
                                                                                LocalContext.getFacilityRrn(),
                                                                                ObjectList.RECIPE_KEY);
                        recipeLogicalVersion = recipeVersionManager.getNowActiveRecipeVersion(recipeLogicalRrn);
                    }

                    recipePhysicalId = recipeManager.buildRecipePhysicalId(logicalRecipeId, lotInfo);
                    Map lotRecipeInfo = new HashMap();
                    lotRecipeInfo.put("recipeGroupRrn", recipeGroupRrn);
                    lotRecipeInfo.put("recipeGroupVersion", recipeGroupVersion.getInstanceVersion());
                    lotRecipeInfo.put("recipeLogicalRrn", recipeLogicalRrn);
                    lotRecipeInfo.put("recipeLogicalVersion", recipeLogicalVersion.getInstanceVersion());
                    lotRecipeInfo.put("recipePhysicalId", recipePhysicalId);
                    lotRecipeInfo.put("chamberType", chamberType);
                    lotRecipeInfo.put("chamberEqptsId", chamberEqptsId);
                    lotRecipeInfo.put("recipeParam", MapUtils.getString(lotInfo, "recipeParam"));
                    return lotRecipeInfo;
                }
            }
            return null;
        }

        @Override
        public Map getLotRecipeInfo(Lot lot, Long recipeLogicalRrn) {
            String logicalRecipeId = namedObjectManager.getNamedObjectId(recipeLogicalRrn);
            RecipeContextValue recipeContextValue = recipeContextManager.getRecipeContextValue(lot);
            Long recipeGroupRrn = recipeContextValue.getRecipeRrn();
            RecipeVersion recipeGroupVersion = recipeVersionManager.getNowActiveRecipeVersion(recipeGroupRrn);

            RecipeVersion recipeLogicalVersion = recipeVersionManager.getNowActiveRecipeVersion(recipeLogicalRrn);

            String recipePhysicalId = recipeManager.buildRecipePhysicalId(logicalRecipeId, BeanUtils.copyBeanToMap(lot));

            Map lotRecipeInfo = new HashMap();
            lotRecipeInfo.put("recipeGroupRrn", recipeGroupRrn);
            lotRecipeInfo.put("recipeGroupVersion", recipeGroupVersion.getInstanceVersion());
            lotRecipeInfo.put("recipeLogicalRrn", recipeLogicalRrn);
            lotRecipeInfo.put("recipeLogicalVersion", recipeLogicalVersion.getInstanceVersion());
            lotRecipeInfo.put("recipePhysicalId", recipePhysicalId);
            lotRecipeInfo.put("chamberType", recipeLogicalVersion.getChamberTypes());
            lotRecipeInfo.put("recipeParam", lot.getRecipeParameter());
            return lotRecipeInfo;
        }

        @Override
        public String getToCarrierTypeForChange(Lot lot) {
            Carrier currentCarrier = carrierManager.getCarrier(lot.getCarrierRrn());

            String targetCarrierType = carrierManager.getCarriertypeByProcessLocation(lot);

            Matcher mathcher = WipUtils.PCDPATERN.matcher(targetCarrierType);

            Boolean match = mathcher.matches();
            if (!match) {
                // 不是sorter机台（process location定义的是A或者B 不是A-B）并且不匹配 不允许出站
                Assert.isFalse(!StringUtils.equalsIgnoreCase(targetCarrierType, currentCarrier.getObjectSubtype()) &&
                                       lot.getAutoSplitMergFlag() != 1,
                               Errors.create().key(MessageIdList.CASSETTE_NOT_MATCH_LOT_PROCESS)
                                     .content("Cassette type for {}  not match!").args(lot.getLotId()).build());

            }

            if (match) {
                targetCarrierType = targetCarrierType.substring(
                        targetCarrierType.indexOf(WipUtils.CSTTYPE_SEPERATER_KEY) + 1);
            }

            return targetCarrierType == null ? StringUtils.EMPTY : targetCarrierType;
        }

        @Override
        public List<Lot> getLotsByEqpt(String whereSql, long eqptRrn) {
            return lotQueryDAO.getLotsByEqpt(whereSql, eqptRrn);
        }

        @Override
        public List<LotProcessInfo> getLotProcessInfo(long lotRrn, String stepType) {
            return lotQueryDAO.getLotProcessInfo(lotRrn, stepType);
        }

        @Override
        public String getMaxLotIdByProductType(String productType) {
            return lotQueryDAO.getMaxLotIdByProductType(productType);
        }

        @Override
        public List<Map> getLotsList(Map actionMap) {
            List<Map> lotsList = lotQueryDAO.getLotsList(actionMap);
            return lotsList;
        }

        @Override
        public Map getLotTransInfo(String lotrrn) {
            return lotQueryDAO.getLotTransInfo(lotrrn);
        }

        @Override
        public long getBatchRrn() {
            return lotQueryDAO.getBatchRrn();
        }

        @Override
        public List<Map> getLotPriorityList(long productRrn) {
            long facilityRrn = LocalContext.getFacilityRrn();
            List<Map> lotsList = lotQueryDAO.getLotPriorityList(productRrn);
            for (Map lotsMap : lotsList) {
                String allPriority = this.getHotflagSplicingPriority(
                        NumberUtils.toInt(MapUtils.getString(lotsMap, "hotFlag")), MapUtils.getInteger(lotsMap, "priority"),
                        facilityRrn);
                lotsMap.put("allPriority", allPriority);
                if (StringUtils.equalsIgnoreCase(MapUtils.getString(lotsMap, "lotStatus"), LotStatus.BANKED) ||
                        StringUtils.equalsIgnoreCase(MapUtils.getString(lotsMap, "lotStatus"), LotStatus.OUTSOURCING)) {
                    long lotRrn = MapUtils.getLong(lotsMap, "lotRrn");
                    Lot lot = this.getLot(lotRrn);
                    lotsMap.put("prevOperationId", lot.getPrevOperation());
                    lotsMap.put("prevFlowSeq", lot.getPrevFlowSeq());
                    lotsMap.put("prevOperationDesc", lot.getPrevOperationDesc());
                }
            }
            return lotsList;
        }

        @Override
        public List<Map> getHoldLotsList(Map actionMap) {
            List<Map> holdLotsList = lotQueryDAO.getHoldLotsList(actionMap);
            return holdLotsList;
        }

        @Override
        public String getBatchId(String lotId) {
            return lotQueryDAO.getBatchId(lotId);
        }

        @Override
        public List<NpwBank> getNPWBankLot(Map<String, String> queryInfo) {
            return lotQueryDAO.getNPWBankLot(queryInfo);
        }

        @Override
        public Map getMaxLotIdByLotType(String lotType) {
            return lotQueryDAO.getMaxLotIdByLotType(lotType);
        }

        @Override
        public Map getMaxLotIdByLotType4NPW(String lotType) {
            return lotQueryDAO.getMaxLotIdByLotType4NPW(lotType);
        }

        @Override
        public boolean generateLotIdIsExisted(String generateLotId) {
            return lotQueryDAO.generateLotIdIsExisted(generateLotId);
        }

        @Override
        public List<Map> getLotListAtEqpt(Long eqptRrn) {
            Map criterion = new HashMap();
            criterion.put("PAGESIZE", 500);
            criterion.put("jobGridFlag", true);
            criterion.put("objectRrn", eqptRrn);
            criterion.put("objectType", ObjectList.ENTITY_KEY);
            List lotStatus = new ArrayList();
            lotStatus.add(LotStatus.RUNNING);
            lotStatus.add(LotStatus.RUNNINGHOLD);
            lotStatus.add(LotStatus.PROCESSED);
            criterion.put("lotStatus", lotStatus);

            return this.getLotList4ExtAtEqpt(criterion);
        }

        @Override
        public Map<String, Object> getComsumeLotsByEqpt(Lot lot, Integer lotSize) {
            return lotQueryDAO.getComsumeLotsByEqpt(lot, lotSize);
        }

        @Override
        public String getSourceLotBondingTag(Long trLotProductRrn, Long soLotProductRrn, Long trOperationRrn) {
            Collection sapphireList = productManager.getProductSapphireList(trLotProductRrn);
            String sourceBondingTag = "";
            for (Iterator it = sapphireList.iterator(); it.hasNext(); ) {
                Map map = (Map) it.next();
                if (soLotProductRrn.longValue() == MapUtils.getLongValue(map, "instancerrn") &&
                        trOperationRrn.longValue() == MapUtils.getLongValue(map, "attributedata1")) {
                    sourceBondingTag = MapUtils.getString(map, "attributedata5");
                    break;
                }
            }
            if (StringUtils.isBlank(sourceBondingTag)) {
                sourceBondingTag = "BOTTOM";
            }
            return sourceBondingTag;
        }

        @Override
        public LotSapphreInfo getLotSapphreInfo(Long lotRrn) {
            return lotQueryDAO.getLotSapphreInfo(lotRrn);
        }

        @Override
        public List<Map> qryBondedLotInfos(Unit unit) {
            List<Map> lotBonded = lotQueryDAO.qryBondedLotInfos(unit);
            for (Map bondedTrans : lotBonded) {
                long productRrn = MapUtils.getLong(bondedTrans, "productRrn");
                long operationRrn = MapUtils.getLong(bondedTrans, "operationRrn");
                long processRrn = MapUtils.getLong(bondedTrans, "processRrn");
                long carrierRrn = MapUtils.getLong(bondedTrans, "carrierRrn");
                bondedTrans.put("productId", namedObjectManager.getInstanceId(productRrn));
                bondedTrans.put("operationId", namedObjectManager.getInstanceId(operationRrn));
                bondedTrans.put("processId", namedObjectManager.getInstanceId(processRrn));
                bondedTrans.put("carrierId", namedObjectManager.getInstanceId(carrierRrn));
            }
            return lotBonded;
        }

        @Override
        public List<Map> qryBondedLotInfos(Lot lot) {
            List<Map> lotBonded = lotQueryDAO.qryBondedLotInfos(lot);
            for (Map bondedTrans : lotBonded) {
                long productRrn = MapUtils.getLong(bondedTrans, "productRrn");
                long operationRrn = MapUtils.getLong(bondedTrans, "operationRrn");
                long processRrn = MapUtils.getLong(bondedTrans, "processRrn");
                long carrierRrn = MapUtils.getLong(bondedTrans, "carrierRrn");
                bondedTrans.put("productId", namedObjectManager.getInstanceId(productRrn));
                bondedTrans.put("operationId", namedObjectManager.getInstanceId(operationRrn));
                bondedTrans.put("processId", namedObjectManager.getInstanceId(processRrn));
                bondedTrans.put("carrierId", namedObjectManager.getInstanceId(carrierRrn));
            }
            return lotBonded;
        }

        @Override
        public List<Map> qryByBondedLotInfos(Unit unit) {
            List<Map> lotBonded = lotQueryDAO.qryByBondedLotInfos(unit);
            for (Map bondedTrans : lotBonded) {
                long productRrn = MapUtils.getLong(bondedTrans, "productRrn");
                long operationRrn = MapUtils.getLong(bondedTrans, "operationRrn");
                long processRrn = MapUtils.getLong(bondedTrans, "processRrn");
                long carrierRrn = MapUtils.getLong(bondedTrans, "carrierRrn");
                bondedTrans.put("productId", namedObjectManager.getInstanceId(productRrn));
                bondedTrans.put("operationId", namedObjectManager.getInstanceId(operationRrn));
                bondedTrans.put("processId", namedObjectManager.getInstanceId(processRrn));
                bondedTrans.put("carrierId", namedObjectManager.getInstanceId(carrierRrn));
            }
            return lotBonded;
        }

        @Override
        public String getInstanceIdFromHoldComments(String holdReason) {
            String reason = holdReason;
            if (reason.startsWith(FUTUREHOLD_REASON_PREFIX)) {
                reason = StringUtils.substringAfter(reason, FUTUREHOLD_REASON_PREFIX);
            } else if (reason.startsWith(TRACKOUTHOLD_REASON_PREFIX)) {
                reason = StringUtils.substringAfter(reason, TRACKOUTHOLD_REASON_PREFIX);
            }
            return StringUtils.substringBefore(StringUtils.substringAfter(reason, "ID: "), ",");
        }

        @Override
        public long queryLotStepEquipmentHistoryByLot(long lotRrn) {
            return lotQueryDAO.queryLotStepEquipmentHistoryByLot(lotRrn);
        }

        @Override
        public int qryLotTransHistoryCount(long lotRrn) {
            return lotQueryDAO.qryLotTransHistoryCount(lotRrn);
        }

        @Override
        public List<LotRecycledInfo> getLotRecycledInfosOfActivity(Long facilityRrn, Lot lot) {

            List<LotRecycledInfo> results = new ArrayList<>();

            LotRecycledInfo searchRecyInfo = new LotRecycledInfo();
            searchRecyInfo.setLotRrn(lot.getLotRrn());
            searchRecyInfo.setProcessRrn(lot.getProcessRrn());
            List<LotRecycledInfo> lotRecycledInfos = queryLotRecycledInfoByLotNoVersion(searchRecyInfo);
            if (CollectionUtils.isEmpty(lotRecycledInfos)) {
                lotRecycledInfos = Collections.emptyList();
            }
            for (LotRecycledInfo lotRecycledInfo : lotRecycledInfos) {
                // 查询批次当前版本的loop sum count
                lotRecycledInfo.setProcessVersion(lot.getProcessVersion());
                LotRecycledContextValue lotRecycledContextValue = lotRecycledContextValueManager.getContextValues(
                        lotRecycledInfo);

                int sumLoopCount = 0;
                if (lotRecycledContextValue != null && lotRecycledContextValue.getResultValue1() != null) {
                    sumLoopCount = NumberUtils.toInt(lotRecycledContextValue.getResultValue1());
                }

                int remainLoopCount = sumLoopCount - lotRecycledInfo.getLoopCount();
                if (remainLoopCount > 0) { // 剩余次数 > 0 才是活动的循环信息
                    results.add(lotRecycledInfo);
                }
            }

            return results;

        }

        @Override
        public LotRecycledInfo getValidLotRecycledEndInfo(Long facilityRrn, Lot lot) {
            List<LotRecycledInfo> lotRecycledInfos = queryEndOfLotRecycledInfoByLot(lot);

            if (CollectionUtils.isNotEmpty(lotRecycledInfos)) {
                LotRecycledInfo lotRecycledInfo = lotRecycledInfos.iterator().next();

                LotRecycledContextValue lotRecycledContextValue = lotRecycledContextValueManager.getContextValues(
                        lotRecycledInfo);
                if (lotRecycledContextValue != null && isNeedLoopAgain(lotRecycledManager.getHasLoopCount(lotRecycledInfo),
                                                                       lotRecycledContextValue.getLoopCount())) {

                    return lotRecycledInfo;
                }
            }

            return null;
        }

        @Override
        public List<LotRecycledInfo> qryLotRecycledInfos(LotRecycledInfo lotRecycledInfo, String filterFlag) {
            List<LotRecycledInfo> lotRecycledInfos = lotQueryDAO.qryLotRecycledInfos(lotRecycledInfo, filterFlag);
            if (lotRecycledInfos == null) {
                lotRecycledInfos = Collections.emptyList();
            }
            return lotRecycledInfos;
        }

        @Override
        public boolean hasInvalidLoopInfoInTargetVersion(Integer processVersion, List<LotRecycledInfo> lotRecycledInfos) {
            if (CollectionUtils.isNotEmpty(lotRecycledInfos)) {
                for (LotRecycledInfo lotRecycledInfo : lotRecycledInfos) {
                    long processRrn = lotRecycledInfo.getProcessRrn();

                    boolean isExists = workflowManager.hasThisRouteAndOperationInProcess(processRrn, processVersion,
                                                                                         lotRecycledInfo.getStartRouteRrn(),
                                                                                         lotRecycledInfo.getStartOperationRrn());
                    isExists = isExists && workflowManager.hasThisRouteAndOperationInProcess(processRrn, processVersion,
                                                                                             lotRecycledInfo.getEndRouteRrn(),
                                                                                             lotRecycledInfo.getEndOperationRrn());

                    if (!isExists) {
                        return true;
                    }
                }
            }
            return false;
        }

        @Override
        public boolean hasSameStartEndLoopSetupInTargetVersion(Long facilityRrn, Integer processVersion,
                                                               List<LotRecycledInfo> lotRecycledInfos) {
            boolean hasLoopSetup = false;

            if (CollectionUtils.isNotEmpty(lotRecycledInfos)) {
                for (LotRecycledInfo lotRecycledInfo : lotRecycledInfos) {
                    lotRecycledInfo.setProcessVersion(processVersion);
                    LotRecycledContextValue lotRecycledContextValue = lotRecycledContextValueManager.getContextValues(
                            lotRecycledInfo);

                    if (lotRecycledContextValue != null && NumberUtils.toLong(lotRecycledContextValue.getResultValue2()) ==
                            lotRecycledInfo.getStartRouteRrn() &&
                            NumberUtils.toLong(lotRecycledContextValue.getResultValue3()) ==
                                    lotRecycledInfo.getStartOperationRrn()) {
                        hasLoopSetup = true;
                    } else {
                        return false;
                    }
                }
            }

            return hasLoopSetup;
        }

        @Override
        public List<Map<String, Object>> queryLotListCache(LotQueryParameterDto queryParameterDto) {
            StopWatch stopWatch = new StopWatch("queryLotList");

            stopWatch.start("queryLotInfoByPage");
            //        List<Map<String, Object>> queryLots = lotQueryDAO.queryLotInfoByPage(queryParameterDto);
            final List<Map<String, Object>> queryLots = queryLotInfoByPage(queryParameterDto);
            stopWatch.stop();
            fillLotInfo(queryLots,queryParameterDto);
            return queryLots;

        }

        private void fillLotInfo(List<Map<String,Object>> queryLots,LotQueryParameterDto queryParameterDto){
            if (CollectionUtils.isNotEmpty(queryLots)) {
                setValue(queryLots, queryParameterDto);
                final Map<String, String> keyMap=attributeConvertManager.getWorkAreaKeyMap();
                queryLots.parallelStream().forEach(dataMap -> {
                    if (dataMap != null) {
                        if (pcdManager.isPcdCleaningTimeIsLessThan3Days(MapUtils.getLong(dataMap, "carrierRrn"))) {
                            dataMap.put("pcdCleanRedFlag", "1");
                        }
                        if (MapUtils.isNotEmpty(keyMap)) {
                            String key = MapUtils.getString(dataMap, "workArea");
                    if(StringUtils.isNotEmpty(key)){
                        String desc= MapUtils.getString(keyMap,key);
                        if(StringUtils.isNotEmpty(desc)){
                                    dataMap.put("workArea", desc);
                                }
                            }
                        }
                    }
                });
            }
        }

        @Override
        public List<Map<String,Object>> queryLotByOperatorPanel(LotQueryParameterDto lotQueryParameterDto) {
            return queryLotForOperatorPanel(lotQueryParameterDto);
        }

        @Override
        public List<Map> getUnitBondingInfo(Long unitRrn) {
            return lotQueryDAO.getUnitBondingInfo(unitRrn);
        }

        private List<Map<String, Object>> queryLotForOperatorPanel(LotQueryParameterDto lotQueryParameterDto) {
            //基础检查
            if(lotQueryParameterDto==null||lotQueryParameterDto.getOperatorPanelParam()==null){
                return new ArrayList<>();
            }
            //operator panel 设备组必不可少

            QueryLotInfoProp queryLotInfoProp = getOperatorPanelQueryProp(lotQueryParameterDto);
            List<Map<String,Object>> queryLots = lotQueryDAO.queryLotInfoByPage(queryLotInfoProp.getSqlBuffer(),queryLotInfoProp.getArgs(),lotQueryParameterDto);
            fillLotInfo(queryLots,lotQueryParameterDto);
            return queryLots;
        }

        private QueryLotInfoProp getOperatorPanelQueryProp(LotQueryParameterDto lotQueryParameterDto) {
            List<Object> args = new ArrayList<>();
            StringBuilder sql =new StringBuilder();
            sql.append(        " SELECT l.lot_type,   ");
            sql.append(   "         l.Step_Sequence,   ");
            sql.append(   "         l.RECIPE_STRING,   ");
            sql.append(   "         l.HOLD_TIMESTAMP,   ");
            sql.append(   "         l.prev_operation_rrn,   ");
            sql.append(   "         l.CREATE_CATEGORY,   ");
            sql.append(   "         l.REWORK_CATEGORY,   ");
            sql.append(   "         e.SHIPPING_CODE,   ");
            sql.append(   "         e.CUSTOMER_ID,   ");
            sql.append(   "         e.OUT_ORDER_TYPE,   ");
            sql.append(   "         e.CUSTOMER_LOT_ID,   ");
            sql.append(   "         l.FLOW_SEQ,   ");
            sql.append(   "         e.LOCATION,   ");
            sql.append(   "         e.PLOCATION,   ");
            sql.append(   "         l.lot_rrn,   ");
            sql.append(   "         l.lot_id,   ");
            sql.append(   "         l.lot_status,   ");
            sql.append(   "         l.hot_flag,   ");
            sql.append(   "         l.priority,   ");
            sql.append(   "         l.due_date,   ");
            sql.append(   "         getlotqty1(l.LOT_RRN) AS QTY1,   ");
            sql.append(   "         l.input_qty1,   ");
            sql.append(   "         l.carrier_rrn,   ");
            sql.append(   "         l.product_rrn,   ");
            sql.append(   "         l.lot_owner,   ");
            sql.append(   "         l.process_rrn,   ");
            sql.append(   "         l.process_version,   ");
            sql.append(   "         l.process_step_version,   ");
            sql.append(   "         l.process_location,   ");
            sql.append(   "         l.route_seq,   ");
            sql.append(   "         l.operation_rrn,   ");
            sql.append(   "         l.operation_version,   ");
            sql.append(   "         l.operation_seq,   ");
            sql.append(   "         l.process_step_id_version,   ");
            sql.append(   "         l.eqpt_rrn,   ");
            sql.append(   "         l.queue_timestamp,   ");
            sql.append(   "         l.stage_id,   ");
            sql.append(   "         l.lot_comments,   ");
            sql.append(   "         e.outer_order_no,   ");
            sql.append(   "         e.INNER_ORDER_NO,   ");
            sql.append(   "         e.attribute_data1   as pollution_level,   ");
            sql.append(   "         e.CURRENT_STEP_TIME_STRUCT,   ");
            sql.append(   "         TO_NUMBER((SYSDATE - CASE   ");
            sql.append(   "                   WHEN l.LOT_STATUS <> 'HOLD' AND l.LOT_STATUS <> 'RUNNINGHOLD' THEN SYSDATE   ");
            sql.append(   "         ELSE NVL(l.hold_timestamp, SYSDATE) END) +   ");
            sql.append(   "         (SYSDATE - NVL(l.queue_timestamp, SYSDATE)))         TOTAL_WAITING_TIME,   ");
            sql.append(   "         mater.unit_alias_2,   ");
            sql.append(   "         ROUND((GETMINREMAINTIMEBYLOTRRN(l.LOT_RRN, '0') / 3600), 2) AS Q_TIME,   ");
            sql.append(   " l.JOB_RRN   ");
            sql.append(   " FROM (LOT l left join LOT_EXT e on l.lot_rrn = e.lot_rrn)   ");
            sql.append(   " left join (SELECT listagg(unit_alias_2, ',') WITHIN GROUP ( ORDER BY unit_alias_2 ) as unit_alias_2, lot_rrn   ");
            sql.append(   " FROM (SELECT DISTINCT unit_alias_2, lot_rrn from unit) unn   ");
            sql.append(   " GROUP BY unn.lot_rrn) mater on l.lot_rrn = mater.lot_rrn   ");
            sql.append(   " WHERE  (L.IS_DUMMY_LOT = 0 OR L.IS_DUMMY_LOT IS NULL)  AND (L.EQPT_RRN IS NULL OR L.EQPT_RRN =0) ");//排除掉 lot 运行时指定的 eqpt
            LotQueryParameterDto.OperatorPanelParam operatorPanelParam =  lotQueryParameterDto.getOperatorPanelParam();

            if(StringUtils.isNotEmpty(lotQueryParameterDto.getLotId())){
                sql.append(String.format(" AND L.LOT_ID %s ? ",lotQueryParameterDto.getLotId().contains("%")?"like":"="));
                args.add(lotQueryParameterDto.getLotId());
            }

            if(CollectionUtils.isNotEmpty(operatorPanelParam.getEqptGroupRrns())){//一个设备可能在多个设备组

                String inParams =  operatorPanelParam.getEqptGroupRrns().stream().distinct().map(e->"?").collect(
                        Collectors.joining(","));
                sql.append( " AND EXISTS(SELECT 1 ");
                sql.append( "        FROM (SELECT PROCESS_RRN, ");
                sql.append( "              PROCESS_VERSION, ");
                sql.append( "              ROUTE_RRN, ");
                sql.append( "              OPERATION_RRN, ");
                sql.append( "              REGEXP_SUBSTR(T.EQUIPMENT_GROUP_RRNS, '[^,]+', 1, LEVEL) EQUIPMENT_GROUP_RRN ,FLOW_SEQ");
                sql.append( "              FROM (SELECT PSA.EQUIPMENT_GROUP_RRNS, ");
                sql.append( "                    PSA.PROCESS_RRN, ");
                sql.append( "                    PSA.PROCESS_VERSION, ");
                sql.append( "                    PSA.ROUTE_RRN, ");
                sql.append( "                    PSA.OPERATION_RRN, PSA.FLOW_SEQ, ");
                sql.append( "                    ROWNUM NUM ");
                sql.append( "                    FROM LOT L, ");
                sql.append( "                    PROCESS_SPEC_ITEM_ACTIVE PSA ");
                sql.append( "                    WHERE ");
                sql.append( "                    PSA.PROCESS_RRN = L.PROCESS_RRN ");
                sql.append( "                    AND PSA.PROCESS_VERSION = L.PROCESS_VERSION ");
                sql.append( "                    AND PSA.OPERATION_RRN = L.OPERATION_RRN ");
                sql.append( "                    AND PSA.FLOW_SEQ = L.FLOW_SEQ ");
                sql.append( "                   ) T ");
                sql.append( "              CONNECT BY LEVEL <= REGEXP_COUNT(T.EQUIPMENT_GROUP_RRNS, '[^,]+') ");
                sql.append( "              AND PRIOR NUM = NUM ");
                sql.append( "              AND PRIOR DBMS_RANDOM.VALUE() IS NOT NULL) T ");
                sql.append( "        WHERE EQUIPMENT_GROUP_RRN IN ("+inParams+") ");
                sql.append( " AND l.PROCESS_RRN = T.PROCESS_RRN ");
                sql.append( " AND l.PROCESS_VERSION = T.PROCESS_VERSION ");
                sql.append( " AND l.OPERATION_RRN = T.OPERATION_RRN ");
                sql.append( "   AND L.FLOW_SEQ = T.FLOW_SEQ)");
                args.addAll(operatorPanelParam.getEqptGroupRrns().stream().distinct().collect(Collectors.toList()));
            }

            if(lotQueryParameterDto.getLotCategory()!=null&&lotQueryParameterDto.getLotCategory().length>0){
                String inParams = Arrays.stream(lotQueryParameterDto.getLotCategory()).map(e->"?").collect(Collectors.joining(","));
                sql.append(
                        " AND L.CREATE_CATEGORY in ("+inParams+") "
                );
                args.addAll(Arrays.stream(lotQueryParameterDto.getLotCategory()).collect(Collectors.toList()));
            }

            if(lotQueryParameterDto.getLotStatus()!=null&&lotQueryParameterDto.getLotStatus().length>0){
                String inParams = Arrays.stream(lotQueryParameterDto.getLotStatus()).filter(e->!LotStatus.isRunningHold(e)).map(e->"?").collect(Collectors.joining(","));
                sql.append(
                        "   AND L.LOT_STATUS in ("+inParams+") "
                          );
                args.addAll(Arrays.stream(lotQueryParameterDto.getLotStatus()).filter(e->!LotStatus.isRunningHold(e)).collect(Collectors.toList()));
            }

            if(StringUtils.isNotEmpty(lotQueryParameterDto.getProductId())){
                //判断是否包含
                sql.append(String.format(" AND EXISTS(" +
                                                 "         SELECT 1 FROM PRODUCT P WHERE P.PRODUCT_ID %s ? AND P" +
                                                 "          .SYS_RRN = L.PRODUCT_RRN" +
                                                 "   )", lotQueryParameterDto.getProductId().contains("%")?"like":"="));
                args.add( lotQueryParameterDto.getProductId());

            }

            //运行中的设备 指定了 设备，这里要特殊过滤 上面的要排除掉设备 rrn 这里就要根据设备指定判断
            if(lotQueryParameterDto.getOperatorPanelParam()!=null
                    &&lotQueryParameterDto.getOperatorPanelParam().getEqptRrn()!=null
                    &&lotQueryParameterDto.getOperatorPanelParam().getEqptRrn()>0L
                    && Arrays.asList(lotQueryParameterDto.getLotStatus()).contains(LotStatus.RUNNINGHOLD)){
                sql.append("  UNION ALL  ");
                sql.append("    SELECT l.lot_type, ");
                sql.append("            l.Step_Sequence, ");
                sql.append("            l.RECIPE_STRING, ");
                sql.append("            l.HOLD_TIMESTAMP, ");
                sql.append("            l.prev_operation_rrn, ");
                sql.append("            l.CREATE_CATEGORY, ");
                sql.append("            l.REWORK_CATEGORY, ");
                sql.append("            e.SHIPPING_CODE, ");
                sql.append("            e.CUSTOMER_ID, ");
                sql.append("            e.OUT_ORDER_TYPE, ");
                sql.append("            e.CUSTOMER_LOT_ID, ");
                sql.append("            l.FLOW_SEQ, ");
                sql.append("            e.LOCATION, ");
                sql.append("            e.PLOCATION, ");
                sql.append("            l.lot_rrn, ");
                sql.append("            l.lot_id, ");
                sql.append("            l.lot_status, ");
                sql.append("            l.hot_flag, ");
                sql.append("            l.priority, ");
                sql.append("            l.due_date, ");
                sql.append("            getlotqty1(l.LOT_RRN)                                       AS QTY1, ");
                sql.append("    l.input_qty1, ");
                sql.append("            l.carrier_rrn, ");
                sql.append("            l.product_rrn, ");
                sql.append("            l.lot_owner, ");
                sql.append("            l.process_rrn, ");
                sql.append("            l.process_version, ");
                sql.append("            l.process_step_version, ");
                sql.append("            l.process_location, ");
                sql.append("            l.route_seq, ");
                sql.append("            l.operation_rrn, ");
                sql.append("            l.operation_version, ");
                sql.append("            l.operation_seq, ");
                sql.append("            l.process_step_id_version, ");
                sql.append("            l.eqpt_rrn, ");
                sql.append("            l.queue_timestamp, ");
                sql.append("            l.stage_id, ");
                sql.append("            l.lot_comments, ");
                sql.append("            e.outer_order_no, ");
                sql.append("            e.INNER_ORDER_NO, ");
                sql.append("            e.attribute_data1                                           as pollution_level, ");
                sql.append("    e.CURRENT_STEP_TIME_STRUCT, ");
                sql.append("            TO_NUMBER((SYSDATE - CASE ");
                sql.append("                      WHEN l.LOT_STATUS <> 'HOLD' AND l.LOT_STATUS <> 'RUNNINGHOLD' THEN SYSDATE ");
                sql.append("    ELSE NVL(l.hold_timestamp, SYSDATE) END) + ");
                sql.append("            (SYSDATE - NVL(l.queue_timestamp, SYSDATE)))         TOTAL_WAITING_TIME, ");
                sql.append("            mater.unit_alias_2, ");
                sql.append("            ROUND((GETMINREMAINTIMEBYLOTRRN(l.LOT_RRN, '0') / 3600), 2) AS Q_TIME, ");
                sql.append("    l.JOB_RRN ");
                sql.append("    FROM (LOT l left join LOT_EXT e on l.lot_rrn = e.lot_rrn) ");
                sql.append("    left join (SELECT listagg(unit_alias_2, ',') WITHIN GROUP ( ORDER BY unit_alias_2 ) as unit_alias_2, ");
                sql.append("            lot_rrn ");
                sql.append("    FROM (SELECT DISTINCT unit_alias_2, lot_rrn from unit) unn ");
                sql.append("    GROUP BY unn.lot_rrn) mater on l.lot_rrn = mater.lot_rrn ");
                sql.append("    WHERE (L.IS_DUMMY_LOT = 0 OR L.IS_DUMMY_LOT IS NULL) ");
                sql.append("    AND l.EQPT_RRN=?  AND L.LOT_STATUS =? ");
                args.add(lotQueryParameterDto.getOperatorPanelParam().getEqptRrn());
                args.add(LotStatus.RUNNINGHOLD);
                if(StringUtils.isNotEmpty(lotQueryParameterDto.getLotId())){
                    sql.append(String.format(" AND L.LOT_ID %s ? ",lotQueryParameterDto.getLotId().contains("%")?"like":"="));
                    args.add(lotQueryParameterDto.getLotId());
                }
                if(lotQueryParameterDto.getLotCategory()!=null&&lotQueryParameterDto.getLotCategory().length>0){
                    String inParams = Arrays.stream(lotQueryParameterDto.getLotCategory()).map(e->"?").collect(Collectors.joining(","));
                    sql.append(
                            " AND L.CREATE_CATEGORY in ("+inParams+") "
                              );
                    args.addAll(Arrays.stream(lotQueryParameterDto.getLotCategory()).collect(Collectors.toList()));
                }

                if(StringUtils.isNotEmpty(lotQueryParameterDto.getProductId())){
                    //判断是否包含
                    sql.append(String.format(" AND EXISTS(" +
                                                     "         SELECT 1 FROM PRODUCT P WHERE P.PRODUCT_ID %s ? AND P" +
                                                     "          .SYS_RRN = L.PRODUCT_RRN" +
                                                     "   )", lotQueryParameterDto.getProductId().contains("%")?"like":"="));
                    args.add( lotQueryParameterDto.getProductId());

                }
            }

            //第二部分 runcard
            sql.append(" UNION ALL ");
            sql.append(" SELECT T.LOT_TYPE,  ");
            sql.append("         SLS.STEP_SEQUENCE,  ");
            sql.append("         SLSS.RECIPE_ID          AS RECIPE_STRING,  ");
            sql.append(" T.HOLD_TIMESTAMP,  ");
            sql.append("         T.PREV_OPERATION_RRN,  ");
            sql.append("         T.CREATE_CATEGORY,  ");
            sql.append("         T.REWORK_CATEGORY,  ");
            sql.append("         E.SHIPPING_CODE,  ");
            sql.append("         E.CUSTOMER_ID,  ");
            sql.append("         E.OUT_ORDER_TYPE,  ");
            sql.append("         E.CUSTOMER_LOT_ID,  ");
            sql.append("         SLS.FLOW_SEQ,  ");
            sql.append("         E.LOCATION,  ");
            sql.append("         E.PLOCATION,  ");
            sql.append("         SLS.LOT_RRN,  ");
            sql.append("         SLS.LOT_ID,  ");
            sql.append("         T.LOT_STATUS,  ");
            sql.append("         T.HOT_FLAG,  ");
            sql.append("         T.PRIORITY,  ");
            sql.append("         T.DUE_DATE,  ");
            sql.append("         getlotqty1(T.LOT_RRN)      AS QTY1,  ");
            sql.append("         T.INPUT_QTY1,  ");
            sql.append("         SLS.CARRIER_RRN,  ");
            sql.append("         LRC.PRODUCT_RRN,  ");
            sql.append("         LRC.LOT_OWNER,  ");
            sql.append("         SLS.PROCESS_RRN,  ");
            sql.append("         SLS.PROCESS_VERSION,  ");
            sql.append("         T.PROCESS_STEP_VERSION,  ");
            sql.append("         SLSS.PROCESS_LOCATION,  ");
            sql.append("         T.ROUTE_SEQ,  ");
            sql.append("         SLS.OPERATION_RRN,  ");
            sql.append("         T.OPERATION_VERSION,  ");
            sql.append("         T.OPERATION_SEQ,  ");
            sql.append("         T.PROCESS_STEP_ID_VERSION,  ");
            sql.append("         SLSS.EQPT_RRN,  ");
            sql.append("         T.QUEUE_TIMESTAMP,  ");
            sql.append("         (select STAGE_ID FROM LOT L WHERE L.LOT_ID=SLS.MAIN_LOT_ID) AS STAGE_ID ,  ");
            sql.append("         T.LOT_COMMENTS,  ");
            sql.append("         E.OUTER_ORDER_NO,  ");
            sql.append("         E.INNER_ORDER_NO,  ");
            sql.append("         E.ATTRIBUTE_DATA1            as pollution_level,  ");
            sql.append(" E.CURRENT_STEP_TIME_STRUCT,  ");
            sql.append("         TO_NUMBER((SYSDATE - CASE  ");
            sql.append("                   WHEN T.LOT_STATUS <> 'HOLD' AND T.LOT_STATUS <> 'RUNNINGHOLD' THEN SYSDATE  ");
            sql.append(" ELSE NVL(T.hold_timestamp, SYSDATE) END) +  ");
            sql.append("         (SYSDATE - NVL(T.queue_timestamp, SYSDATE)))         TOTAL_WAITING_TIME,  ");
            sql.append("         '',  ");
            sql.append("         ROUND((GETMINREMAINTIMEBYLOTRRN(T.LOT_RRN, '0') / 3600), 2) AS Q_TIME,  ");
            sql.append(" T.JOB_RRN  ");
            sql.append(" FROM SRC_LOT_STORE SLS, ");
            sql.append(" SRC_LOT_SPECIAL_STEP SLSS, ");
            sql.append(" LOT T, ");
            sql.append(" LOT_EXT E, ");
            sql.append(" LOT_RUN_CARD LRC, ");
            sql.append(" NAMED_OBJECT N, ");
            sql.append(" NAMED_OBJECT EQPT_N ");
            sql.append( "  WHERE SLS.LOT_SPECIAL_STEP_RRN = SLSS.LOT_SPECIAL_STEP_RRN(+)");
            sql.append( "  AND SLS.STEP_SEQUENCE = SLSS.STEP_SEQUENCE(+)");
            sql.append( "  AND SLS.LOT_RRN = T.LOT_RRN");
            sql.append( "  AND SLS.RUNCARD_RRN = LRC.RUN_CARD_RRN(+)");
            sql.append( "  AND to_number(substr(SLS.runcard_rrn_h, instr(SLS.runcard_rrn_h, ',', -1) + 1)) =");
            sql.append( "          N.INSTANCE_RRN");
            sql.append( "  AND T.EQPT_RRN = EQPT_N.INSTANCE_RRN(+)");
            sql.append( " AND N.OBJECT = 'ECN'");
            sql.append( " AND N.NAMED_SPACE = 'MYCIM2'");
            sql.append( "  AND (N.OBJECT_TYPE = 'SPLITRUNCARD' OR N.OBJECT_TYPE = 'RECOVERYRUNCARD')");
            sql.append( "  AND E.LOT_RRN = T.LOT_RRN");

            if(StringUtils.isNotEmpty(lotQueryParameterDto.getLotId())){
                sql.append(String.format(" AND T.LOT_ID %s ? ",lotQueryParameterDto.getLotId().contains("%")?"like":"="));
                args.add(lotQueryParameterDto.getLotId());
            }

            if(lotQueryParameterDto.getLotStatus()!=null&&lotQueryParameterDto.getLotStatus().length>0){
                String inParams = Arrays.stream(lotQueryParameterDto.getLotStatus()).map(e->"?").collect(Collectors.joining(","));
                sql.append(
                        "   AND T.LOT_STATUS in ("+inParams+") "
                          );
                args.addAll(Arrays.stream(lotQueryParameterDto.getLotStatus()).collect(Collectors.toList()));
            }

            if(CollectionUtils.isNotEmpty(operatorPanelParam.getEqptGroupRrns())||operatorPanelParam.getEqptRrn()!=null&&operatorPanelParam.getEqptRrn()>0){
                //优先设备过滤
                if(operatorPanelParam.getEqptRrn()!=null&&operatorPanelParam.getEqptRrn()>0){
                    sql.append(" AND SLSS.EQPT_RRN = ? " );
                    args.add(operatorPanelParam.getEqptRrn());
                }else{
                    // AND (SLSS.EQPT_GROUP_RRN = 0 OR SLSS.EQPT_RRN = 0)
                    String inParams = operatorPanelParam.getEqptGroupRrns().stream().map(e->"?").collect(Collectors.joining(","));
                    sql.append("   AND SLSS.EQPT_GROUP_RRN in ("+inParams+") " );
                    args.addAll(operatorPanelParam.getEqptGroupRrns());
                }
            }

            if(lotQueryParameterDto.getLotCategory()!=null&&lotQueryParameterDto.getLotCategory().length>0){
                String inParams = Arrays.stream(lotQueryParameterDto.getLotCategory()).map(e->"?").collect(Collectors.joining(","));
                sql.append(
                        " AND  T.CREATE_CATEGORY  in ("+inParams+") "
                          );
                args.addAll(Arrays.stream(lotQueryParameterDto.getLotCategory()).collect(Collectors.toList()));
            }

            if(StringUtils.isNotEmpty(lotQueryParameterDto.getProductId())){
                //判断是否包含
                sql.append(String.format(" AND EXISTS(" +
                                                 "         SELECT 1 FROM PRODUCT P WHERE P.PRODUCT_ID %s ? AND P" +
                                                 "          .SYS_RRN = T.PRODUCT_RRN" +
                                                 "   )", lotQueryParameterDto.getProductId().contains("%")?"like":"="));
                args.add( lotQueryParameterDto.getProductId());

            }
            sql.insert(0," select * from( ");
            sql.append(" ) l ");
            QueryLotInfoProp queryLotInfoProp =new QueryLotInfoProp();
            queryLotInfoProp.setArgs(args);
            queryLotInfoProp.setSqlBuffer(new StringBuffer(sql.toString()));
            return queryLotInfoProp;
        }

        @Override
        public List getChildLotsForMergeWithActiveHold(Lot lot) {
            return lotQueryDAO.getChildLotsForMergeWithActiveHold(lot);
        }

        @Override
        public List qryLotHistoryCommentByTime(long lotRrn) {
            return lotQueryDAO.qryLotHistoryCommentByTime(lotRrn);
        }

        @Override
        public List<Map<String, Object>> ryAllLotInfoForLotPortal(LotQueryParameterDto queryParameterDto) {
            StopWatch stopWatch = new StopWatch("queryLotList");

            stopWatch.start("queryLotInfoByPage");
            //        List<Map<String, Object>> queryLots = lotQueryDAO.queryLotInfoByPage(queryParameterDto);
            List<Map<String, Object>> queryLots = queryLotInfoByNoPage(queryParameterDto);
            stopWatch.stop();

            if (CollectionUtils.isNotEmpty(queryLots)) {

                stopWatch.start("foreach");
                setValue(queryLots, queryParameterDto);
                stopWatch.stop();

                if (logger.isDebugEnabled()) {
                    logger.debug(stopWatch.prettyPrint());
                }
            }
            return queryLots;
        }

        @Override
        public Map<String, Object> queryPriorityBeforeLastAdjust(long lotRrn, long transRrn) {
            return lotQueryDAO.queryPriorityBeforeLastAdjust(lotRrn, transRrn);
        }

        @Override
        public int qryLotTransHisCountByStepseq(long lotRrn) {
            return lotQueryDAO.qryLotTransHisCountByStepseq(lotRrn);
        }

        @Override
        public void getParamSetMapByLotRrn(Long lotRrn, Map<Long, String> paramSetMap) {
            lotQueryDAO.getParamSetMapByLotRrn(lotRrn, paramSetMap);
        }

        @Override
        public String getSpecialHoldCodeByUserGroup(String specialHoldCode, String userGroupId, String holdGroup) {
            List<Map> holdInfos = getAllHoldCodeInfoByUserGroupId(userGroupId, holdGroup);
            for (Map<String, String> map : holdInfos) {
                String holdCode = MapUtils.getString(map, "holdCode");
                if (StringUtils.contains(holdCode, specialHoldCode)) {
                    return holdCode;
                }
            }
            return specialHoldCode;
        }

        @Override
        public TimelimitStatus getLotTimeLimitStatusByLotRrnAndQtimeId(long lotRrn, String timeLimitId,
                                                                       String targetStatus) {
            return lotQueryDAO.getLotTimeLimitStatusByLotRrnAndQtimeId(lotRrn, timeLimitId, targetStatus);
        }

        @Override
        public String getLotComments(Lot lot) {
            Map<String, Object> condition = new HashMap<>();
            condition.put("lotRrn", lot.getLotRrn());
            condition.put("stepSequence", lot.getStepSequence());

            List commentList = this.qryLotStepHistoryComment(lot.getLotRrn(), lot.getStepSequence(), 1, 1000);
            Iterator it = commentList.iterator();
            StringBuilder commentStr = new StringBuilder();
            while (it.hasNext()) {
                Map<String, Object> m = (Map<String, Object>) it.next();
                commentStr.append(MapUtils.getString(m, "commentSequence")).append(".")
                          .append(MapUtils.getString(m, "stepComment")).append(";\n");
            }

            return commentStr.toString();
        }

        @Override
        public List<Map<String, String>> getLotPlanAdjustDataWithSimilarTime(Long lotRrn, Timestamp transStartTimestamp) {
            List<Map<String, String>> results = lotQueryDAO.getLotPlanAdjustDataWithSimilarTime(lotRrn,
                                                                                                transStartTimestamp);
            if (results == null) {
                results = new ArrayList<>(2);
            } else if (results.size() == 1) {
                results.add(new HashMap<String, String>());
            }
            return results;
        }

        @Override
        public String getFlowSeqByLot(Lot lot) {
            return resequenceContextValueManager.getFlowSeq(lot.getProcessRrn(), lot.getProcessVersion(),
                                                            lot.getOperationRrn(), lot.getRouteRrn());
        }

        @Override
        public Map<String, Object> getTransRrnAndSequenceForDataCollectionTrans(Long dcolRrn) {
            return lotQueryDAO.getTransRrnAndSequenceForDataCollectionTrans(dcolRrn);
        }

        @Override
        public String getDataCollectionUrlForDataCollectionTrans(long transRrn, Integer transSequence) {
            return lotQueryDAO.getDataCollectionUrlForDataCollectionTrans(transRrn, transSequence);
        }

        @Override
        public int getLotReworkCountBySubplan(Long lotRrn, String processStepVersion, String time) {
            return lotQueryDAO.getLotReworkCountBySubplan(lotRrn, processStepVersion, time);
        }

        @Override
        public Page getLotReworkHistoryInfoList(Page page, Map condition) {
            return lotQueryDAO.getLotReworkHistoryInfoList(page, condition);
        }

        @Override
        public long getReworkCount(Long lotRrn, String processStepVersion) {
            return lotQueryDAO.getReworkCount(lotRrn, processStepVersion);
        }

        @Override
        public LotProcessStepInfo getLotProcessStepInfo(long lotRrn, String stepType) {
            return lotQueryDAO.getLotProcessStepInfo(lotRrn, stepType);
        }

        @Override
        public Double getParameterValueForLot(Lot lot) {
            return lotQueryDAO.getParameterValueForLot(lot);
        }

        @Override
        public boolean isMultipathRunningHoldStep(Lot lot) {
            boolean notInMultiPathFlag = this.getMultiPathByLot(lot).stream().filter(wflLinkContextValue -> {
                return StringUtils.isNotBlank(wflLinkContextValue.getContextKey10());
            }).collect(Collectors.toList()).isEmpty();
            if (notInMultiPathFlag) {
                return false;
            }
            List<Map<String, String>> results = lotQueryDAO.isMultipathRunningHoldStep(lot);
            for (Map<String, String> result : results) {
                if (StringUtils.equals(MapUtils.getString(result, "transId"), "HOLD_RUNNING_LOT") &&
                        (StringUtils.equals(MapUtils.getString(result, "reasonCode"), "MULTIPATHHOLD") ||
                                StringUtils.equals(MapUtils.getString(result, "reasonCode"), "EDCRULEHOLD"))) {
                    return true;
                } else if (StringUtils.equals(MapUtils.getString(result, "transId"), "CANCELMOVEIN")) {
                    return false;
                }
            }
            return false;
        }

        @Override
        public List<WflLinkContextValue> getMultiPathByLot(Lot lot) {
            List<WflLinkContextValue> list = new ArrayList<>();
            WflLinkContextValue ctx = new WflLinkContextValue();
            ctx.setProductRrn(lot.getProductRrn());
            ctx.setProcessRrn(lot.getProcessRrn());
            ctx.setRouteRrn(lot.getRouteRrn());
            ctx.setOperationRrn(lot.getOperationRrn());
            ctx.setProcessVersion(lot.getProcessVersion());

            String wfl = lot.getWflStepPath();
            String stepRrn = StringUtils.substring(wfl, wfl.lastIndexOf(".") + 1);

            Boolean isRouteLastStep = checkOperationIsLastOperationInRoute(lot.getWflStepPath(), lot.getProcessRrn(), lot.getProcessVersion());
            //Boolean isRouteLastStep = workflowManager.isRouteLastStep(lot.getRouteRrn(), NumberUtils.toLong(stepRrn, 0));
            List<WflLinkContextValue> ctxList = wflLinkContextValueManager.getContextValues(ctx);
            if (ctxList != null && !ctxList.isEmpty()) {
                list.addAll(ctxList);
            }
            if (isRouteLastStep) {
                ctx.setContextKey4(" ");
                ctxList = wflLinkContextValueManager.getContextValues(ctx);
                if (ctxList != null && !ctxList.isEmpty()) {
                    ctxList = ctxList.stream()
                                     .filter(wflLinkContextValue -> WflLinkContextSetupAttributeUtil.isByRouteMultipath(
                                             wflLinkContextValue)).collect(Collectors.toList());
                    list.addAll(ctxList);
                }
            }

            return list;
        }

        @Override
        public boolean checkSetMultiPath(Lot lot, String roleType) {
            Collection operationPath = workflowManager.getWflPath(lot.getRouteRrn(), lot.getRouteVersion(),
                                                                  namedObjectManager.getInstanceId(lot.getOperationRrn()));
            Collection routePath = workflowManager.getWflPath(lot.getProcessRrn(), lot.getProcessVersion(),
                                                              lot.getRouteId());
            if (CollectionUtils.isEmpty(operationPath) && CollectionUtils.isEmpty(routePath)) {
                return false;
            }

            boolean notSetRouteMultipath = false;
            boolean notSetOperationMultipath = false;
            if (routePath.size() > 1) {

                if (checkOperationIsLastOperationInRoute(lot.getWflStepPath(), lot.getProcessRrn(),
                                                         lot.getProcessVersion())) {
                    notSetRouteMultipath = true;
                    WflLinkContextValue contextValue = new WflLinkContextValue();
                    contextValue.setProductRrn(lot.getProductRrn());
                    contextValue.setProcessRrn(lot.getProcessRrn());
                    contextValue.setProcessVersion(lot.getProcessVersion());
                    contextValue.setRouteRrn(lot.getRouteRrn());
                    List<WflLinkContextValue> wflLinkContextValueList = wflLinkContextValueManager.getContextValues(
                            contextValue);

                    if (CollectionUtils.isNotEmpty(wflLinkContextValueList)) {
                        for (WflLinkContextValue ctx : wflLinkContextValueList) {
                            boolean _flag = false;
                            if (StringUtils.equalsIgnoreCase(roleType, WflLinkContextSetupAttributeUtil.EDC_MULTIPATH)) {
                                _flag = WflLinkContextSetupAttributeUtil.isByEdcRouteMultipath(ctx);
                            } else if (StringUtils.equalsIgnoreCase(roleType,
                                                                    WflLinkContextSetupAttributeUtil.PRODUCT_MULTIPATH)) {
                                _flag = WflLinkContextSetupAttributeUtil.isByProdRouteMultipath(ctx);
                            } else if (StringUtils.equalsIgnoreCase(roleType,
                                                                    WflLinkContextSetupAttributeUtil.RECIPE_MULTIPATH)) {
                                _flag = WflLinkContextSetupAttributeUtil.isByRecipeRouteMultipath(ctx);
                            } else {
                                _flag = WflLinkContextSetupAttributeUtil.isByRouteMultipath(ctx);
                            }
                            if (_flag && NumberUtils.toLong(ctx.getContextKey1()) == lot.getProductRrn()) {
                                notSetRouteMultipath = false;
                                break;
                            }
                        }
                    }
                }
            }

            if (operationPath.size() > 1) {
                notSetOperationMultipath = true;

                WflLinkContextValue contextValue = new WflLinkContextValue();
                contextValue.setProductRrn(lot.getProductRrn());
                contextValue.setProcessRrn(lot.getProcessRrn());
                contextValue.setProcessVersion(lot.getProcessVersion());
                contextValue.setRouteRrn(lot.getRouteRrn());
                contextValue.setOperationRrn(lot.getOperationRrn());
                List<WflLinkContextValue> wflLinkContextValueList = wflLinkContextValueManager.getContextValues(
                        contextValue);

                if (CollectionUtils.isNotEmpty(wflLinkContextValueList)) {
                    for (WflLinkContextValue ctx : wflLinkContextValueList) {
                        boolean _flag = false;
                        if (StringUtils.equalsIgnoreCase(roleType, WflLinkContextSetupAttributeUtil.EDC_MULTIPATH)) {
                            _flag = WflLinkContextSetupAttributeUtil.isByEdcOperationMultipath(ctx);
                        } else if (StringUtils.equalsIgnoreCase(roleType,
                                                                WflLinkContextSetupAttributeUtil.PRODUCT_MULTIPATH)) {
                            _flag = WflLinkContextSetupAttributeUtil.isByProdOperationMultipath(ctx);
                        } else if (StringUtils.equalsIgnoreCase(roleType,
                                                                WflLinkContextSetupAttributeUtil.RECIPE_MULTIPATH)) {
                            _flag = WflLinkContextSetupAttributeUtil.isByRecipeOperationMultipath(ctx);
                        } else {
                            _flag = WflLinkContextSetupAttributeUtil.isByOperationMultipath(ctx);
                        }

                        if (_flag && NumberUtils.toLong(ctx.getContextKey1()) == lot.getProductRrn()) {
                            notSetOperationMultipath = false;
                            break;
                        }
                    }
                }
            }

            return notSetRouteMultipath || notSetOperationMultipath;
        }

        @Override
        public List<LotRecycledInfo> queryUnitRecycledInfoByLotNoVersion(LotRecycledInfo lotRecycledInfo) {
            return lotQueryDAO.queryUnitRecycledInfoByLotNoVersion(lotRecycledInfo);
        }

        @Override
        public List<Map> queryLotLoopInfo(long lotRrn, long processRrn, int processVersion) {
            return lotQueryDAO.queryLotLoopInfo(lotRrn, processRrn, processVersion);
        }

        @Override
        public Page queryLotLoopHistoryInfo(Page page, long lotRrn, long processRrn) {
            return lotQueryDAO.queryLotLoopHistoryInfo(page, lotRrn, processRrn);
        }

        @Override
        public List<Map<String, Object>> getEqpRunLotRecipeMES(long eqpRrn, Date timePoint) {
            return lotQueryDAO.getEqpRunLotRecipeMES(eqpRrn, timePoint);
        }

        @Override
        public List<Map<String, Object>> getEqpRunWaferRecipeMES(long eqpRrn, Date timePoint) {
            return lotQueryDAO.getEqpRunWaferRecipeMES(eqpRrn, timePoint);
        }

        @Override
        public List<Map<String, Object>> getEqpRunLotRecipeMESByEqpRunHist(String eqpId, Date timePoint) {
            return lotQueryDAO.getEqpRunLotRecipeMESByEqpRunHist(eqpId, timePoint);
        }

        @Override
        public List<Map<String, Object>> getEqpRunWaferRecipeMESByEqpRunHist(String eqpId, Date timePoint) {
            return lotQueryDAO.getEqpRunWaferRecipeMESByEqpRunHist(eqpId, timePoint);
        }

        @Override
        public List<Map<String, Object>> getEqpRunLotRecipeEAP(String eqpId, String chamberType, Date timePoint) {
            return lotQueryDAO.getEqpRunLotRecipeEAP(eqpId, chamberType, timePoint);
        }

        @Override
        public List<Map<String, Object>> getEqpRunWaferRecipeEAP(String eqpId, String chamberType, Date timePoint) {
            return lotQueryDAO.getEqpRunWaferRecipeEAP(eqpId, chamberType, timePoint);
        }

        @Override
        public void checkLotStatus(List<String> lotRrns, List<String> status) {
            long facility = LocalContext.getFacilityRrn();
            //userid for log
            Assert.isFalse(CollectionUtils.isEmpty(lotRrns),
                           Errors.create().key(MessageIdList.LOT_LOTRRN_NOT_FOUND).content("Lot Can't be found! ").build());
            //允许操作的状态集合不能为空
            Assert.isFalse(CollectionUtils.isEmpty(status),
                           Errors.create().key(MessageIdList.LOT_STATUS_NOT_ALLOW).content("lot status is empty! ")
                                 .build());
            for (String lotRrn : lotRrns) {
                Lot currentLot = this.getLot(Long.valueOf(lotRrn));
                //判断lot 是否能够被找到
                Assert.isTrue(currentLot != null && currentLot.getFacilityRrn() == facility,
                              Errors.create().key(MessageIdList.LOT_LOTRRN_NOT_FOUND).content("Lot Can't be found!")
                                    .build());
                //判断lot 状态是否在集合范围内
                Assert.isTrue(status.contains(currentLot.getLotStatus()),
                              Errors.create().key(MessageIdList.LOT_STATUS_NOT_ALLOW).content("Lot status not allow!")
                                    .build());
            }
        }

        @Override
        public void checkLotUnitReworkSeq(Lot lot, String countWay, Integer maxReworkTime) {
            String processStepVersion = lot.getProcessStepVersion();
            if (ReworkConst.CountWay.BY_ROUTE.getWay().equalsIgnoreCase(countWay)) {
                processStepVersion = processStepVersion.substring(0, processStepVersion.lastIndexOf("|"));
            }
            List<Map<String, Long>> list = unitQueryManager.getReworkUnitSeq(lot.getLotRrn(), processStepVersion);

            String msg = "";
            for (Map<String, Long> map : list) {
                if (MapUtils.getLongValue(map, "num") >= maxReworkTime.longValue()) {
                    msg += unitQueryManager.getUnit(MapUtils.getLong(map, "unitRrn")).getUnitId() + ",";
                }
            }

            Assert.isFalse(StringUtils.isNotBlank(msg),
                           Errors.create().key(MessageIdList.REWORK_MAXIMUM_NUMBER_EXCEEDED).content("片号{}超过最大返工次数!")
                                 .args(msg).build());
        }

        @Override
        public List<Map> queryUnitLoopInfo(LotRecycledInfo LotRecycledInfo) {
            return lotQueryDAO.queryUnitLoopInfo(LotRecycledInfo);
        }

        @Override
        public List<Map> queryUnitReworkInfo(long lotRrn, String processStepVersion) {
            return lotQueryDAO.queryUnitReworkInfo(lotRrn, processStepVersion);
        }

        @Override
        public Map<Long, Lot> getLotInfosByRrns(List<Long> lotRrns) {
            if (CollectionUtils.isEmpty(lotRrns)) {//入参非法
                return null;
            }
            Map<Long, Lot> lotInfos = new HashMap<>();
            for (Long lotRrn : lotRrns) {
                if (!lotInfos.containsKey(lotRrn)) { //去重复
                    //如果为null 则表明锁注解也有可能会出现问题
                    /**这里直接不判断对象为null，异常直接抛出来 能更直观检查出问题，**/
                    lotInfos.put(lotRrn, getLot(lotRrn));
                }
            }
            return lotInfos;
        }

        @Override
        public Long getLotCountFormHistoryByCondition(Map conditionMap) {
            List<Object> args = new ArrayList<Object>();
            String sql = buildSqlForLotCount(conditionMap, args);
            if (StringUtils.isEmpty(sql)) {
                return 0L;
            }
            return lotQueryDAO.getLotCountFormHistoryByCondition(sql, args);
        }

        @Override
        public List<Map> getBatchBankInLots(Map map) {
            List<Map> batchBankLots = lotQueryDAO.getBatchBankLots(map);
            return batchBankLots;
        }

        @Override
        public MultiLot getMultiLotByCarrierId(String carrierId, Long facilityRrn) {
            long carrierRrn = namedObjectManager.getNamedObjectRrn(carrierId, namedObjectManager.getNamedSpace(facilityRrn,
                                                                                                               ObjectList.ENTITY_KEY),
                                                                   ObjectList.ENTITY_KEY, ObjectList.CARRIER_KEY);
            return getMultiLotByCarrierRrn(carrierRrn);
        }

        @Override
        public MultiLot getMultiLotByCarrierRrn(long carrierRrn) {
            return carrierRrn > 0 ? lotQueryDAO.getMultiLotByCarrierRrn(carrierRrn) : new MultiLot();
        }

        @Override
        public String getLotMoveInTime(String lotId, String equipmentId) {
            return lotQueryDAO.getLotMoveInTime(lotId, equipmentId);
        }

        @Override
        public List<Long> getRunLotRrnsByChamberId(Long eqptRrn, String chamberId) {
            return lotQueryDAO.getRunLotRrnsByChamberId(eqptRrn, chamberId);
        }

        @Override
        public List<Map> getBatchAdjustLots(Map map) {
            List<Map> batchAdjustLots = lotQueryDAO.getBatchAdjustLots(map);
            return batchAdjustLots;
        }

        @Override
        public List<Map> getBatchCancelFutureHoldLots(Map map, long refRrn) {
            List<Map> batchCancelFutureHoldLots = lotQueryDAO.getBatchCancelFutureHoldLots(map, refRrn);
            return batchCancelFutureHoldLots;
        }

        @Override
        public List<Map> getLotList4Ship(ShipQueryConditionDto shipQueryConditionDto) {
            List<Map> lotList = lotQueryDAO.getLotList4Ship(shipQueryConditionDto);
            Map<Long, String> idList = lotQueryDAO.getInstanceIdsInLotByRrn(shipQueryConditionDto);
            if (CollectionUtils.isNotEmpty(lotList)) {
                for (Map lot : lotList) {
                    lot.put("productId", idList.getOrDefault(MapUtils.getLong(lot, "productRrn"), StringUtils.EMPTY));
                    lot.put("processId", idList.getOrDefault(MapUtils.getLong(lot, "processRrn"), StringUtils.EMPTY));
                    lot.put("routeId", idList.getOrDefault(MapUtils.getLong(lot, "routeRrn"), StringUtils.EMPTY));
                    lot.put("operationId", idList.getOrDefault(MapUtils.getLong(lot, "operationRrn"), StringUtils.EMPTY));
                }
            }
            return lotList;
        }

        @Override
        public Boolean checkSetMultiPathByManual(Lot lot) {
            Collection operationPath = workflowManager.getWflPath(lot.getRouteRrn(), lot.getRouteVersion(),
                                                                  namedObjectManager.getInstanceId(lot.getOperationRrn()));
            Collection routePath = workflowManager.getWflPath(lot.getProcessRrn(), lot.getProcessVersion(),
                                                              lot.getRouteId());
            if (CollectionUtils.isEmpty(operationPath) && CollectionUtils.isEmpty(routePath)) {
                return false;
            }

            boolean setRouteMultipath = false;
            boolean setOperationMultipath = false;
            if (routePath.size() > 1) {
                if (checkOperationIsLastOperationInRoute(lot.getWflStepPath(), lot.getProcessRrn(),
                                                         lot.getProcessVersion())) {
                    WflLinkContextValue contextValue = new WflLinkContextValue();
                    contextValue.setProductRrn(lot.getProductRrn());
                    contextValue.setProcessRrn(lot.getProcessRrn());
                    contextValue.setProcessVersion(lot.getProcessVersion());
                    contextValue.setRouteRrn(lot.getRouteRrn());
                    List<WflLinkContextValue> wflLinkContextValueList = wflLinkContextValueManager.getContextValues(
                            contextValue);
                    if (CollectionUtils.isNotEmpty(wflLinkContextValueList)) {
                        for (WflLinkContextValue ctx : wflLinkContextValueList) {
                            boolean _flag = false;
                            _flag = WflLinkContextSetupAttributeUtil.isByManualRouteMultipath(ctx);
                            if (_flag && NumberUtils.toLong(ctx.getContextKey1()) == lot.getProductRrn()) {
                                setRouteMultipath = true;
                                break;
                            }
                        }
                    }
                }
            }

            if (operationPath.size() > 1) {
                WflLinkContextValue contextValue = new WflLinkContextValue();
                contextValue.setProductRrn(lot.getProductRrn());
                contextValue.setProcessRrn(lot.getProcessRrn());
                contextValue.setProcessVersion(lot.getProcessVersion());
                contextValue.setRouteRrn(lot.getRouteRrn());
                contextValue.setOperationRrn(lot.getOperationRrn());
                List<WflLinkContextValue> wflLinkContextValueList = wflLinkContextValueManager.getContextValues(
                        contextValue);
                if (CollectionUtils.isNotEmpty(wflLinkContextValueList)) {
                    for (WflLinkContextValue ctx : wflLinkContextValueList) {
                        boolean _flag = false;
                        _flag = WflLinkContextSetupAttributeUtil.isByManualOperationMultipath(ctx);
                        if (_flag && NumberUtils.toLong(ctx.getContextKey1()) == lot.getProductRrn()) {
                            setOperationMultipath = true;
                            break;
                        }
                    }
                }
            }

            return setRouteMultipath || setOperationMultipath;
        }

        public List<Map> getAllHoldCodeInfoByUserGroupId(String userGroupId, String holdGroup) {
            return getHoldReasonCodes(holdGroup, getHoldReasonRoles(userGroupId), ReferenceDetailNames.HOLD_CODE);
        }

        public String getHotflagText(Integer hotflag, Long facilityRrn) {
            String result = StringUtils.EMPTY;
            if (hotflag != null) {
                ReferenceFileDetail referenceFileDetail = new ReferenceFileDetail();

                Long refFileDetailRrn = namedObjectManager.getNamedObject("$$LOT_HOTFLAG", facilityRrn,
                                                                          ObjectList.REFERENCE_FILE_KEY).getInstanceRrn();
                Assert.isFalse(refFileDetailRrn == null || refFileDetailRrn < 1L,
                               Errors.create().content("Reference File " + "$$LOT_HOTFLAG Not Found!").build());
                referenceFileDetail.setInstanceRrn(refFileDetailRrn);
                referenceFileDetail.setKey1Value(String.valueOf(hotflag));
                referenceFileDetail.setKey2Value(" ");
                referenceFileDetail = referenceFileManager.getReferenceFileDetail(referenceFileDetail);
                result = referenceFileDetail != null ? referenceFileDetail.getData1Value() : "Priority Value : " + hotflag;
            }
            return result;
        }

        @Override
        public void fillLotExt(Lot lot) {
            if (lot == null || lot.getLotRrn() > 0) {
                long facilityRrn = LocalContext.getFacilityRrn();
                lot = lotQueryDAO.getLotExt(lot);
                lot.setCarrierId(namedObjectManager.getNamedObjectId(lot.getCarrierRrn()));
                lot.setCarrierMapRrn(carrierManager.getCarrierMapRrn(lot.getCarrierRrn()));

                lot.setEqptID(namedObjectManager.getNamedObjectId(lot.getEqptRrn()));

                lot.setProductId(namedObjectManager.getNamedObjectId(lot.getProductRrn()));
                lot.setProductType(namedObjectManager.getNamedObject(lot.getProductRrn()).getObjectType());

                lot.setProcessId(namedObjectManager.getNamedObjectId(lot.getProcessRrn()));
                String routeRrnStr = WipUtils.getRouteByProcessStepVersion(lot.getProcessStepVersion())[0];
                lot.setRouteRrn(Long.valueOf(routeRrnStr));
                lot.setRouteId(namedObjectManager.getNamedObjectId(lot.getRouteRrn()));
                lot.setRouteDesc(namedObjectManager.getNamedObjectDesc(lot.getRouteRrn()));
                lot.setOperationId(namedObjectManager.getNamedObjectId(lot.getOperationRrn()));
                lot.setNextOperationId1(namedObjectManager.getNamedObjectId(lot.getNextOperationRrn1()));
                lot.setPrevOperation(namedObjectManager.getNamedObjectId(lot.getPrevOperationRrn()));
                lot.setReticleId(namedObjectManager.getNamedObjectId(lot.getReticleRrn()));
                lot.setReticleGroupId(namedObjectManager.getNamedObjectId(lot.getReticleGroupRrn()));
                lot.setOperationDesc(
                        operationDescContextValueManager.getOperationDesc(lot.getProductRrn(), lot.getProcessRrn(),
                                                                          lot.getProcessVersion(), lot.getRouteRrn(),
                                                                          lot.getOperationRrn()));
                String recipeId = "";
                long recipeLogicalRrn = lot.getRecipeLogicalRrn();
                if (recipeLogicalRrn != 0 &&
                        (LotStatus.RUNNING.equals(lot.getLotStatus()) || LotStatus.RUNNINGHOLD.equals(lot.getLotStatus()) ||
                                LotStatus.PROCESSED.equals(lot.getLotStatus()))) {
                    recipeId = namedObjectManager.getInstanceId(recipeLogicalRrn);
                } else {
                    String recipeString = recipeContextManager.getRecipeString(lot);
                    recipeId = recipeContextManager.parseRecipeId(recipeString);
                }
                // todo: 2019-11-6
                //            lot.setRecipePhysicalId(
                //                    recipeManager.buildRecipePhysicalId(recipeId, BeanUtils.copyBeanToMap
                //                    (lot)));
                lot.setRecipeId(recipeId);

                if (StringUtils.equalsIgnoreCase(LotStatus.BANKED, lot.getLotStatus()) ||
                        StringUtils.equalsIgnoreCase(LotStatus.OUTSOURCING, lot.getLotStatus())) {
                    lot.setPrevFlowSeq(
                            resequenceContextValueManager.getFlowSeq(lot.getProcessRrn(), lot.getProcessVersion(),
                                                                     lot.getRouteRrn(), lot.getPrevOperationRrn()));
                    lot.setPrevOperationDesc(
                            operationDescContextValueManager.getOperationDesc(lot.getProductRrn(), lot.getProcessRrn(),
                                                                              lot.getProcessVersion(), lot.getRouteRrn(),
                                                                              lot.getPrevOperationRrn()));
                    lot.setOperationId(namedObjectManager.getNamedObjectId(lot.getPrevOperationRrn()));
                }

                lot.setLotStatusReferenceData(
                        this.buildLotStatusByLotStatusReference(lot.getLotStatus(), lot.getFacilityRrn()));
                lot.setLocation(lot.getLocation());
                lot.setLocationRrn(lot.getLocationRrn());
                lot.setpLocation(lot.getpLocation());
                lot.setpLocationRrn(lot.getpLocationRrn());

                lot.setBatchId(diffBatchQueryManager.getLotBatchId(lot.getLotRrn()));
            }
        }

        @Override
        public Boolean checkStepHasMultiPath(Lot lot) {
            Collection operationPath = workflowManager.getWflPath(lot.getRouteRrn(), lot.getRouteVersion(),
                                                                  namedObjectManager.getInstanceId(lot.getOperationRrn()));
            Collection routePath = workflowManager
                    .getWflPath(lot.getProcessRrn(), lot.getProcessVersion(), lot.getRouteId());
            if (CollectionUtils.isEmpty(operationPath) && CollectionUtils.isEmpty(routePath)) {
                return false;
            }

            if (routePath.size() > 1 && checkOperationIsLastOperationInRoute(lot.getWflStepPath(), lot.getProcessRrn(),
                                                                             lot.getProcessVersion())) {
                return true;
            }
            if (operationPath.size() > 1) {
                return true;
            }
            return false;
        }

        @Override
        public Map<Long, List<Map<String, Object>>> queryLotStepHistoryComments(Long lotRrn, Set<Long> stepSeq) {
            return lotQueryDAO.queryLotStepHistoryComments(lotRrn,stepSeq);
        }

        @Override
        public int getLotWaferCount(Long lotRrn) {
            return lotQueryDAO.getLotWaferCount(lotRrn);
        }

        public String getHoldCodeDesc(String holdCode) {
            return referenceFileManager.getReferenceDetailExchange("$HOLD_CODE", holdCode, "DATA_1_VALUE");
        }

        public void fillLotInfoExt(Map lot) {
            if (MapUtils.isNotEmpty(lot)) {
                lot.put("carrierId", namedObjectManager.getNamedObjectId(MapUtils.getLongValue(lot, ("CARRIER_RRN"))));
                lot.put("operationId", namedObjectManager.getNamedObjectId(MapUtils.getLongValue(lot, ("OPERATION_RRN"))));
                lot.put("operationDesc",
                        namedObjectManager.getNamedObjectDesc(MapUtils.getLongValue(lot, ("OPERATION_RRN"))));
                lot.put("reticleId", namedObjectManager.getNamedObjectId(MapUtils.getLongValue(lot, ("reticle_rrn"))));
                lot.put("recipeId",
                        namedObjectManager.getNamedObjectId(MapUtils.getLongValue(lot, ("TEMP_RECIPE_STRING"))));
                lot.put("productId", namedObjectManager.getNamedObjectId(MapUtils.getLongValue(lot, ("PRODUCT_RRN"))));
                lot.put("processId", namedObjectManager.getNamedObjectId(MapUtils.getLongValue(lot, ("PROCESS_RRN"))));
            }
        }

        @Override
        public Boolean checkOperationIsLastOperationInRoute(String wflStep, Long processRrn, Integer processVersions) {
            List<String[]> workflowTree = workflowManager.getWorkFlowTree(processRrn, processVersions, new HashMap());

            boolean isLastOperation = false;
            for (int i = 0; i < workflowTree.size(); i++) {
                String[] treeNode = workflowTree.get(i);
                if (StringUtils.equals(wflStep, treeNode[6]) && i < workflowTree.size() - 1) {
                    if ("0".equals(workflowTree.get(i + 1)[7])) {
                        isLastOperation = true;
                        return isLastOperation;
                    }
                }
            }
            return isLastOperation;
        }

        private List<String> getHoldReasonRoles(String userGroupId) {
            List<String> holdReasonRoles = getHoldGroupsByUserGroup(userGroupId);
            holdReasonRoles.add("ALL");
            return holdReasonRoles;
        }

        private List<String> getHoldGroupsByUserGroup(String userGroupId) {
            return referenceFileManager.getRefFileKeys(ReferenceDetailNames.REASON_GROUP_DEPARTMENT,
                                                       ReferenceFileConst.KEY_1_VALUE, userGroupId);
        }

        private List<Map<String, Object>> queryLotInfoByNoPage(LotQueryParameterDto lotQueryParameterDto) {
            QueryLotInfoProp queryLotInfoProp = getQueryLotInfoProp(lotQueryParameterDto);
            return lotQueryDAO.queryLotInfoByNoPage(queryLotInfoProp.getSqlBuffer(), queryLotInfoProp.getArgs(),
                                                    lotQueryParameterDto);

        }

        private List<Map<String, Object>> queryLotInfoByPage(LotQueryParameterDto lotQueryParameterDto) {
            QueryLotInfoProp queryLotInfoProp = getQueryLotInfoProp(lotQueryParameterDto);
            return lotQueryDAO.queryLotInfoByPage(queryLotInfoProp.getSqlBuffer(), queryLotInfoProp.getArgs(),
                                                  lotQueryParameterDto);
        }

        private void paddingDataPlanLot(Lot lot) {
            lot.setCarrierId(namedObjectManager.getInstanceId(lot.getCarrierRrn()));

            if (lot.getProductRrn() != null) {
                lot.setProductId(namedObjectManager.getInstanceId(lot.getProductRrn()));
            }

            if (lot.getProcessRrn() != null) {
                lot.setProcessId(namedObjectManager.getInstanceId(lot.getProcessRrn()));
            }

            if (lot.getOperationRrn() != null) {
                lot.setOperationId(namedObjectManager.getInstanceId(lot.getOperationRrn()));
            }

            if (lot.getNextOperationRrn1() != null) {
                lot.setNextOperationId1(namedObjectManager.getInstanceId(lot.getNextOperationRrn1()));
            }

            lot.setReticleId(namedObjectManager.getInstanceId(lot.getReticleRrn()));
        }

        private Map paddingDataLotInfoMap(Map lotInfo) {
            if (MapUtils.isEmpty(lotInfo)) {
                return lotInfo;
            }

            // 补充数据
            Long tempRrn = MapUtils.getLongValue(lotInfo, "carrier_rrn");
            String tempId = null;
            if (tempRrn > 0) {
                tempId = namedObjectManager.getInstanceId(tempRrn);
            }
            lotInfo.put("carrierId", tempId);

            tempRrn = MapUtils.getLongValue(lotInfo, "productRrn");
            if (tempRrn > 0) {
                lotInfo.put("productId", namedObjectManager.getInstanceId(tempRrn));
                lotInfo.put("productDesc", namedObjectManager.getNamedObjectDesc(tempRrn));
            }

            tempRrn = MapUtils.getLongValue(lotInfo, "processRrn");
            if (tempRrn > 0) {
                lotInfo.put("processId", namedObjectManager.getInstanceId(tempRrn));
                lotInfo.put("processDesc", namedObjectManager.getNamedObjectDesc(tempRrn));
            }

            tempRrn = MapUtils.getLongValue(lotInfo, "operation_rrn");
            if (tempRrn > 0) {
                lotInfo.put("operationId", namedObjectManager.getInstanceId(tempRrn));
                lotInfo.put("operationDesc", namedObjectManager.getNamedObjectDesc(tempRrn));
            }

            tempRrn = MapUtils.getLongValue(lotInfo, "equipmentRrn");
            if (tempRrn > 0) {
                tempId = namedObjectManager.getInstanceId(tempRrn);
                lotInfo.put("equipmentId", tempId);
                lotInfo.put("eqptID", tempId);
                lotInfo.put("equipmentDesc", namedObjectManager.getNamedObjectDesc(tempRrn));
            } else {
                lotInfo.put("equipmentId", "");
            }

            tempRrn = MapUtils.getLongValue(lotInfo, "parseOperation");
            lotInfo.put("parseOperationDesc", namedObjectManager.getNamedObjectDesc(tempRrn));

            return lotInfo;
        }

        private List<Map> paddingDataTrans(List<Map> result) {
            // 补充数据
            for (Map m : result) {
                Long tempRrn = MapUtils.getLongValue(m, "processRrn");
                m.put("technology_id", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "productRrn");
                m.put("product_id", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "operationRrn");
                m.put("operation_id", namedObjectManager.getInstanceId(tempRrn));
                //m.put("operationDesc", namedObjectManager.getNamedObjectDesc(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "eqpt_rrn");
                m.put("equipment_id", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "carrier_rrn");
                m.put("carrierId", namedObjectManager.getInstanceId(tempRrn));
            }
            return result;
        }

        private List<Map> paddingDataAllTrans(List<Map> results) {
            for (Map m : results) {
                Long tempRrn = MapUtils.getLongValue(m, "productRrn");
                m.put("productId", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "operationRrn");
                m.put("operationId", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "eqpt_rrn");
                m.put("equipmentId", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "carrier_rrn");
                m.put("carrierId", namedObjectManager.getInstanceId(tempRrn));
            }
            return results;
        }

        private List<Map> paddingDataHoldRelease(List<Map> list) {
            for (Map m : list) {
                Long tempRrn = MapUtils.getLongValue(m, "product_rrn");
                m.put("product_id", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "process_rrn");
                m.put("technology_id", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "operation_rrn");
                m.put("operation_id", namedObjectManager.getInstanceId(tempRrn));
                m.put("operationDesc", namedObjectManager.getNamedObjectDesc(tempRrn));
            }
            return list;
        }

        private List<Map> paddingDataSplitMergeHistory(List<Map> list) {
            for (Map m : list) {
                Long tempRrn = MapUtils.getLongValue(m, "eqpt_rrn");
                if (tempRrn > 0) {
                    m.put("eqptID", namedObjectManager.getInstanceId(tempRrn));
                }

                tempRrn = MapUtils.getLongValue(m, "product_rrn");
                m.put("product_id", namedObjectManager.getInstanceId(tempRrn));
                m.put("productId", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "operation_rrn");
                m.put("operation_id", namedObjectManager.getInstanceId(tempRrn));
                m.put("operationId", namedObjectManager.getInstanceId(tempRrn));
                m.put("operationDesc", namedObjectManager.getNamedObjectDesc(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "process_rrn");
                m.put("technology_id", namedObjectManager.getInstanceId(tempRrn));
                m.put("processId", namedObjectManager.getInstanceId(tempRrn));
            }
            return list;
        }

        private void paddingDataSplitMergeHistory(Page page) {
            for (Object map : page.getResults()) {
                Map m = (Map) map;
                Long tempRrn = MapUtils.getLongValue(m, "eqpt_rrn");
                if (tempRrn > 0) {
                    m.put("eqptID", namedObjectManager.getInstanceId(tempRrn));
                }

                tempRrn = MapUtils.getLongValue(m, "product_rrn");
                m.put("product_id", namedObjectManager.getInstanceId(tempRrn));
                m.put("productId", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "operation_rrn");
                m.put("operation_id", namedObjectManager.getInstanceId(tempRrn));
                m.put("operationId", namedObjectManager.getInstanceId(tempRrn));
                m.put("operationDesc", namedObjectManager.getNamedObjectDesc(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "process_rrn");
                m.put("technology_id", namedObjectManager.getInstanceId(tempRrn));
                m.put("processId", namedObjectManager.getInstanceId(tempRrn));
            }
        }

        private List<Map> paddingDataLotStatus(List<Map> results) {
            for (Map m : results) {
                Long tempRrn = MapUtils.getLongValue(m, "process_rrn");
                m.put("process_id", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "operation_rrn");
                m.put("operation_id", namedObjectManager.getInstanceId(tempRrn));
                m.put("operationDesc", namedObjectManager.getNamedObjectDesc(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "next_operation_rrn1");
                m.put("next_step", namedObjectManager.getInstanceId(tempRrn));
                m.put("nextOperationDesc", namedObjectManager.getNamedObjectDesc(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "eqpt_rrn");
                if (tempRrn > 0) {
                    m.put("eqptID", namedObjectManager.getInstanceId(tempRrn));
                }
            }

            return results;
        }

        private List<Map<String,Object>> paddingDataLotHistory(List<Map<String,Object>> results) {
            List<Consumer<Map<Long, String>>> paddingCallBack = new ArrayList<>();
            Set<Long> instanceRrns = new HashSet<>();
            for (Map map : results) {
                List<HashMap> list = (List<HashMap>) map.get(map.get("operationRrn"));
                for (int i = 0;i<list.size();i++) {
                    final Map<String,Object> m = list.get(i);
                    Long carrierRrn = MapUtils.getLongValue(m, "carrier_rrn");
                    instanceRrns.add(carrierRrn);
                    paddingCallBack.add((resultMap) -> m.put("carrierId", resultMap.get(MapUtils.getLongValue(m, "carrier_rrn"))));

                    Long target_carrier_rrn = MapUtils.getLongValue(m, "target_carrier_rrn");
                    instanceRrns.add(target_carrier_rrn);
                    paddingCallBack.add((resultMap) -> m.put("targetCarrierId", resultMap.get(
                            MapUtils.getLongValue(m, "target_carrier_rrn"))));

                    Long productRrn = MapUtils.getLongValue(m, "productRrn");
                    instanceRrns.add(productRrn);
                    paddingCallBack.add((resultMap) -> m.put("product_id", resultMap.get(
                            MapUtils.getLongValue(m, "productRrn"))));

                    Long processRrn = MapUtils.getLongValue(m, "process_rrn");
                    instanceRrns.add(processRrn);
                    paddingCallBack.add((resultMap) -> m.put("technology_id", resultMap.get(
                            MapUtils.getLongValue(m, "process_rrn"))));

                    Long eqptRrn = MapUtils.getLongValue(m, "eqpt_rrn");
                    instanceRrns.add(eqptRrn);
                    paddingCallBack.add((resultMap) -> m.put("equipment_id", resultMap.get(
                            MapUtils.getLongValue(m, "eqpt_rrn"))));

                    Long recipeRrn = MapUtils.getLongValue(m, "recipe_logical_rrn");
                    if (recipeRrn != 0) {
                        instanceRrns.add(recipeRrn);
                        paddingCallBack.add((resultMap) -> m.put("recipeId", resultMap.get(
                                MapUtils.getLongValue(m, "recipe_logical_rrn"))));
                    }

                    Long reticleRrn = MapUtils.getLongValue(m, "reticle_rrn");
                    if (reticleRrn > 0) {
                        instanceRrns.add(reticleRrn);
                        paddingCallBack.add((resultMap) -> m.put("reticleId", resultMap.get(
                                MapUtils.getLongValue(m, "reticle_rrn"))));
                    }
                }
            }
            final Map<Long, String> queryResult = namedObjectManager.batchQueryInstanceIdByRrns(instanceRrns);
            paddingCallBack.parallelStream().forEach(e->e.accept(queryResult));
            return results;
        }

        private void paddingDataSplitLotInfo(List<Map> results) {
            for (Map m : results) {
                Long tempRrn = MapUtils.getLongValue(m, "product_rrn");
                m.put("productId", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "process_rrn");
                m.put("processId", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "operation_rrn");
                m.put("operationId", namedObjectManager.getInstanceId(tempRrn));
            }
        }

        private void paddingDataLotsList(List<Map> results) {
            for (Map m : results) {
                Long tempRrn = MapUtils.getLongValue(m, "productRrn");
                m.put("productId", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "processRrn");
                m.put("processId", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "operationRrn");
                m.put("operationId", namedObjectManager.getInstanceId(tempRrn));
            }
        }

        private List<Map<String, Object>> paddingDataRuncardLotTransHis(List<Map<String, Object>> results) {
            for (Map m : results) {
                Long tempRrn = MapUtils.getLongValue(m, "productRrn");
                m.put("product_id", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "eqpt_rrn");
                m.put("equipment_id", namedObjectManager.getInstanceId(tempRrn));

                tempRrn = MapUtils.getLongValue(m, "operationRrn");
                m.put("operationDesc", namedObjectManager.getNamedObjectDesc(tempRrn));
            }
            return results;
        }

        private QueryLotInfoProp getQueryLotInfoProp(LotQueryParameterDto lotQueryParameterDto) {
            QueryLotInfoProp pro = new QueryLotInfoProp();
            StringBuilder paramSql = new StringBuilder();
            List<Object> args = new ArrayList();

            if (StringUtils.isNotBlank(lotQueryParameterDto.getLotId())) {
                paramSql.append(" and l.lot_id like ? ");
                args.add(lotQueryParameterDto.getLotId());
            }

            if (StringUtils.isNotBlank(lotQueryParameterDto.getWorkOrderId())) {
                paramSql.append(" AND E.INNER_ORDER_NO  LIKE ? ");
                args.add(lotQueryParameterDto.getWorkOrderId());
            }

            if (StringUtils.isNotBlank(lotQueryParameterDto.getStageId())) {
                //改为由535来取值，且以flow_seq作为条件
                paramSql.append(" and EXISTS (select 1 from PROCESS_SPEC_ITEM_ACTIVE t where t.STAGE_ID like ? and l.operation_rrn = t.operation_rrn " +
                                " and l.PROCESS_RRN=t.PROCESS_RRN and l.FLOW_SEQ=t.FLOW_SEQ   and l.PROCESS_VERSION = t.PROCESS_VERSION )  ");
                args.add(lotQueryParameterDto.getStageId());
            }

            if (StringUtils.isNotBlank(lotQueryParameterDto.getCustomId())) {
                paramSql.append(" and e.customer_id like ? ");
                args.add(lotQueryParameterDto.getCustomId());
            }

            if (lotQueryParameterDto.getLotCategory() != null) {
                String[] lotCategoryArray = lotQueryParameterDto.getLotCategory();
                String categoryCondition = " and l.create_category in (";
                for (int i = 0; i < lotCategoryArray.length; i++) {
                    if (StringUtils.isNotBlank(lotCategoryArray[i])) {
                        if (i == 0) {
                            categoryCondition += "?";
                            args.add(lotCategoryArray[i]);
                        } else {
                            categoryCondition += ",?";
                            args.add(lotCategoryArray[i]);
                        }
                    }
                }
                categoryCondition += ") ";
                paramSql.append(categoryCondition);
            }

            if (lotQueryParameterDto.getLotType() != null) {
                String[] lotTypeArray = lotQueryParameterDto.getLotType();
                String typeCondition = " and l.lot_type in (";
                for (int i = 0; i < lotTypeArray.length; i++) {
                    if (StringUtils.isNotBlank(lotTypeArray[i])) {
                        if (i == 0) {
                            typeCondition += "?";
                            args.add(lotTypeArray[i]);
                        } else {
                            typeCondition += ",?";
                            args.add(lotTypeArray[i]);
                        }
                    }
                }
                typeCondition += ") ";
                paramSql.append(typeCondition);
            }

            String[] filterStatus = LotStatus.getFilterStatus();
            for (String filter : filterStatus) {
                paramSql.append(" and l.lot_status <> ? ");
                args.add(filter);
            }
            if (lotQueryParameterDto.getLotStatus() != null) {
                String[] lotStatusArray = lotQueryParameterDto.getLotStatus();
                if (!"all".equalsIgnoreCase(lotStatusArray[0])) {
                    StringBuilder statusCondition = new StringBuilder(" AND (l.LOT_STATUS IN (");
                    boolean reworkFlag = false;
                    for (int i = 0; i < lotStatusArray.length; i++) {
                        if (StringUtils.equals(LotStatus.ALL, lotStatusArray[i])) {
                            continue;
                        }
                        if (!reworkFlag && StringUtils.equals(lotStatusArray[i], LotStatus.REWORK)) {
                            reworkFlag = true;
                        }

                        if (i == 0) {
                            statusCondition.append("?");
                            args.add(lotStatusArray[i]);
                        } else {
                            statusCondition.append(",?");
                            args.add(lotStatusArray[i]);
                        }

                        if (StringUtils.equals(LotStatus.ACTIVE, lotStatusArray[i])) {
                            statusCondition.append(
                                    ", '" + LotStatus.RUNNING + "' ,'" + LotStatus.WAITING + "' , '" + LotStatus.PROCESSED +
                                            "', '" + LotStatus.DISPATCH + "' ");
                        } else if (StringUtils.equals(LotStatus.UNACTIVE, lotStatusArray[i])) {
                            statusCondition.append(
                                    ", '" + LotStatus.BONDED + "' ,'" + LotStatus.FINISH + "' , '" + LotStatus.TERMINATED +
                                            "', '" + LotStatus.SCRAPPED + "' ");
                        } else if (StringUtils.equals(LotStatus.HOLD, lotStatusArray[i])) {
                            statusCondition.append(",'" + LotStatus.RUNNINGHOLD + "', '" + LotStatus.RUNCARD_HOLD + "'");
                        }
                    }
                    statusCondition.append(") ");
                    if (reworkFlag) {
                        statusCondition.append(" OR REWORK_CATEGORY IS NOT NULL ");
                    }
                    statusCondition.append(") ");
                    paramSql.append(statusCondition);
                }

            }

            if (StringUtils.isNotBlank(lotQueryParameterDto.getPriority())) {
                if (lotQueryParameterDto.getPriority().indexOf("-") > 0) {
                    String[] pris = lotQueryParameterDto.getPriority().split("-");
                    if (pris.length == 2) {
                        paramSql.append("AND l.HOT_FLAG like ? AND l.PRIORITY like ? ");
                        args.add(pris[0]);
                        args.add(pris[1]);
                    } else if (pris.length == 1) {
                        paramSql.append("AND l.HOT_FLAG like ? AND l.PRIORITY is null ");
                        args.add(pris[0]);
                    }
                } else {
                    paramSql.append("AND l.HOT_FLAG like ? ");
                    args.add(lotQueryParameterDto.getPriority());
                }
            }

            if (StringUtils.isNotBlank(lotQueryParameterDto.getProductId()) ||
                    StringUtils.isNotBlank(lotQueryParameterDto.getProductType())) {
                //修改 使用拆分后的表查询
                // String productSelect = "SELECT 1 FROM NAMED_OBJECT P WHERE P.OBJECT = ? AND P.NAMED_SPACE = ? ";
                String productSelect = "SELECT 1 FROM PRODUCT P WHERE P.OBJ_SPACE=? ";
                // args.add(ObjectList.PRODUCT_KEY);
                args.add(namedObjectManager.getNamedSpace(lotQueryParameterDto.getFacilityRrn(), ObjectList.PRODUCT_KEY));
                if (StringUtils.isNotBlank(lotQueryParameterDto.getProductId())) {
                    if (StringUtils.contains(lotQueryParameterDto.getProductId(), "%")) {
                        productSelect += "and P.PRODUCT_ID like ? ";
                        args.add(lotQueryParameterDto.getProductId());
                    } else {
                        productSelect += "and P.PRODUCT_ID = ? ";
                        args.add(lotQueryParameterDto.getProductId());
                    }
                }
                if (StringUtils.isNotBlank(lotQueryParameterDto.getProductType())) {
                    productSelect += " AND OBJ_TYPE = ?  ";
                    args.add(lotQueryParameterDto.getProductType());
                }

                paramSql.append("and EXISTS (").append(productSelect).append(" AND  P.SYS_RRN = L.PRODUCT_RRN )");
            }

            if (StringUtils.isNotBlank(lotQueryParameterDto.getPlocation())) {
                String plocationCondition = lotQueryParameterDto.getPlocation();
                Long plocationConditionRrn = namedObjectManager.getNamedObjectRrn(plocationCondition,
                                                                                  LocalContext.getFacilityRrn(),
                                                                                  ObjectList.ENTITY_KEY);
                if (plocationConditionRrn != null && plocationConditionRrn > 0 ||
                        !(StringUtils.isNumeric(plocationCondition))) {
                    String plocation = "SELECT 1 FROM NAMED_OBJECT pl WHERE pl.OBJECT = ? AND pl.NAMED_SPACE = " + "? ";
                    args.add(ObjectList.ENTITY_KEY);
                    args.add(
                            namedObjectManager.getNamedSpace(lotQueryParameterDto.getFacilityRrn(), ObjectList.ENTITY_KEY));
                    if (StringUtils.isNotBlank(lotQueryParameterDto.getPlocation())) {
                        if (StringUtils.contains(lotQueryParameterDto.getPlocation(), "%")) {
                            plocation += "and pl.instance_id like ? ";
                            args.add(lotQueryParameterDto.getPlocation());
                        } else {
                            plocation += "and pl.instance_id = ? ";
                            args.add(lotQueryParameterDto.getPlocation());
                        }
                    }

                    paramSql.append("and EXISTS (").append(plocation).append(" AND pl.INSTANCE_RRN =e.plocation)");
                } else {
                    if (StringUtils.isNumeric(plocationCondition)) {
                        int plocationConditionInt = NumberUtils.toInt(plocationCondition, 0);
                        paramSql.append("and e.plocation = ? ");
                        args.add(-Math.abs(plocationConditionInt));
                    }
                }
            }

            if (StringUtils.isNotBlank(lotQueryParameterDto.getRouteId())) {
                //由于rework时，lot表中routeId 不存在，改为由535中进行匹配
                paramSql.append(" and EXISTS (select 1 from PROCESS_SPEC_ITEM_ACTIVE t where t.ROUTE_ID like ? and l.operation_rrn = t.operation_rrn " +
                                        " and l.PROCESS_RRN=t.PROCESS_RRN and l.FLOW_SEQ=t.FLOW_SEQ   and l.PROCESS_VERSION = t.PROCESS_VERSION )  ");
                args.add(lotQueryParameterDto.getRouteId());
            }

            if (StringUtils.isNotBlank(lotQueryParameterDto.getWorkArea())) {
                //错误 #41510 lot query页面的workarea 目前是从511 step setup取值，需要修改为从535取值 //过滤条件也跟这535表中的 workarea 一样
                paramSql.append(
                        " and EXISTS (select 1 from PROCESS_SPEC_ITEM_ACTIVE t where t.WORK_AREA = ? and l.operation_rrn " +
                                "= t.operation_rrn " +
                                " and l.PROCESS_RRN=t.PROCESS_RRN and l.FLOW_SEQ=t.FLOW_SEQ   and l.PROCESS_VERSION = t" +
                                ".PROCESS_VERSION )  ");
                args.add(lotQueryParameterDto.getWorkArea());
            }

            if (StringUtils.isNotEmpty(lotQueryParameterDto.getProcessId())) {
                if (StringUtils.contains(lotQueryParameterDto.getProcessId(), '%')) {
                    String select = "SELECT 1 FROM NAMED_OBJECT N WHERE N.OBJECT = '" + ObjectList.WFL_KEY + "' AND " +
                            "object_type= ? AND N.INSTANCE_ID LIKE ? AND l.process_rrn =N" + ".INSTANCE_RRN ";

                    paramSql.append("and EXISTS (").append(select).append(")");
                    args.add(ObjectList.ROUTE_KEY);
                    args.add(lotQueryParameterDto.getProcessId());
                } else {
                    Long processRrn = null;
                    if (StringUtils.isNotBlank(lotQueryParameterDto.getProcessId())) {
                        if (lotQueryParameterDto.getProcessRrn() == 0) {
                            processRrn = namedObjectManager.getNamedObjectRrn(lotQueryParameterDto.getProcessId(),
                                                                              namedObjectManager.getNamedSpace(
                                                                                      lotQueryParameterDto.getFacilityRrn(),
                                                                                      ObjectList.WFL_KEY),
                                                                              ObjectList.WFL_KEY, ObjectList.ROUTE_KEY);

                            lotQueryParameterDto.setProcessRrn(processRrn);
                        } else {
                            processRrn = lotQueryParameterDto.getProcessRrn();
                        }
                    }
                    paramSql.append(" and l.process_rrn = ? ");
                    args.add(processRrn);
                }
            }

            if (StringUtils.isNotEmpty(lotQueryParameterDto.getCarrierId())) {
                if (StringUtils.contains(lotQueryParameterDto.getCarrierId(), '%')) {
                    String select = "SELECT 1 FROM NAMED_OBJECT N WHERE N.OBJECT = ? AND object_type= ? " + " AND N" +
                            ".INSTANCE_ID LIKE ? AND l.carrier_rrn = N.INSTANCE_RRN";
                    paramSql.append("and EXISTS (").append(select).append(")");
                    args.add(ObjectList.ENTITY_KEY);
                    args.add(ObjectList.CARRIER_KEY);
                    args.add(lotQueryParameterDto.getCarrierId());
                } else {
                    long carrierRrn = lotQueryParameterDto.getCarrierRrn();
                    if (carrierRrn == 0) {
                        carrierRrn = namedObjectManager.getNamedObjectRrn(lotQueryParameterDto.getCarrierId(),
                                                                          namedObjectManager.getNamedSpace(
                                                                                  lotQueryParameterDto.getFacilityRrn(),
                                                                                  ObjectList.ENTITY_KEY),
                                                                          ObjectList.ENTITY_KEY, ObjectList.CARRIER_KEY);
                        lotQueryParameterDto.setCarrierRrn(carrierRrn);
                    }
                    paramSql.append(" and l.carrier_rrn = ? ");
                    args.add(lotQueryParameterDto.getCarrierRrn());
                }
            }

            if (StringUtils.isNotBlank(lotQueryParameterDto.getStationId())) {
                List<Long> steps = new ArrayList<Long>();

                if (StringUtils.contains(lotQueryParameterDto.getStationId(), '%')) {
                    List<Long> stationRrns = namedObjectManager.getInstanceRrnWithLike(lotQueryParameterDto.getStationId(),
                                                                                       namedObjectManager.getNamedSpace(
                                                                                               lotQueryParameterDto.getFacilityRrn(),
                                                                                               ObjectList.STATION_KEY),
                                                                                       ObjectList.STATION_KEY);
                    if (CollectionUtils.isNotEmpty(stationRrns)) {
                        for (Long stationRrn : stationRrns) {
                            List<Long> stations = lotQueryDAO.getStepByStation(stationRrn);
                            if (CollectionUtils.isNotEmpty(stations)) {
                                steps.addAll(stations);
                            }
                        }
                    }
                } else {
                    long stationRrn = namedObjectManager.getNamedObjectRrn(lotQueryParameterDto.getStationId(),
                                                                           namedObjectManager.getNamedSpace(
                                                                                   lotQueryParameterDto.getFacilityRrn(),
                                                                                   ObjectList.STATION_KEY),
                                                                           ObjectList.STATION_KEY);
                    List<Long> stations = lotQueryDAO.getStepByStation(stationRrn);
                    if (CollectionUtils.isNotEmpty(stations)) {
                        steps.addAll(stations);
                    }
                }

                if (CollectionUtils.isNotEmpty(steps)) {
                    if (steps.size() > 500) {
                        int size = steps.size();
                        int len = size / 500;

                        List<List<Long>> subSteps = new ArrayList<List<Long>>(size + 1);
                        for (int a = 0; a < len; a++) {
                            subSteps.add(steps.subList((500 * a), 500 * (a + 1)));
                        }
                        if (size % 500 != 0) {
                            subSteps.add(steps.subList(500 * len, size));
                        }

                        StringBuilder operationSql = new StringBuilder();
                        for (int i = 0; i < subSteps.size(); i++) {

                            if (i > 0) {
                                operationSql.append(" or ");
                            }

                            List<Long> subStep = subSteps.get(i);
                            StringBuilder typeCondition = new StringBuilder(" l.operation_rrn in (");
                            for (int k = 0; k < subStep.size(); k++) {
                                long step = subStep.get(k);
                                if (k > 0) {
                                    typeCondition.append(",");
                                }
                                typeCondition.append(step);
                            }
                            operationSql.append(typeCondition.append(")"));

                        }
                        paramSql.append(" and (").append(operationSql).append(" ) ");
                    } else {
                        StringBuilder typeCondition = new StringBuilder(" and l.operation_rrn in (");
                        for (int k = 0; k < steps.size(); k++) {
                            long step = steps.get(k);
                            if (k > 0) {
                                typeCondition.append(",");
                            }
                            typeCondition.append(step);
                        }
                        paramSql.append(typeCondition.append(")"));
                    }

                } else {
                    paramSql.append(" and l.operation_rrn is null ");
                }
            }

            if (StringUtils.isNotBlank(lotQueryParameterDto.getEqpGroupId())) {
                String select = "";
                if (StringUtils.contains(lotQueryParameterDto.getEqpGroupId(), '%')) {
                    List<Long> rrns = namedObjectManager.getInstanceRrnWithLike(lotQueryParameterDto.getEqpGroupId(),
                                                                                namedObjectManager.getNamedSpace(
                                                                                        lotQueryParameterDto.getFacilityRrn(),
                                                                                        ObjectList.ENTITYGROUP_KEY),
                                                                                ObjectList.ENTITYGROUP_KEY);
                    if (CollectionUtils.isNotEmpty(rrns)) {
                        boolean flag = false;
                        for (Long rrn : rrns) {
                            if (flag) {
                                select += ",?";
                            } else {
                                select += "?";
                            }
                            args.add(rrn);
                            flag = true;
                        }
                    }
                } else {
                    long eqpRrn = namedObjectManager.getNamedObjectRrn(lotQueryParameterDto.getEqpGroupId(),
                                                                       namedObjectManager.getNamedSpace(
                                                                               lotQueryParameterDto.getFacilityRrn(),
                                                                               ObjectList.ENTITYGROUP_KEY),
                                                                       ObjectList.ENTITYGROUP_KEY);
                    select += "?";
                    args.add(eqpRrn);
                }
                if (StringUtils.isBlank(select)) {
                    select = "?";
                    args.add(-1);
                }
                // 修改匹配条件为flow_seq
                paramSql.append(" AND EXISTS (SELECT 1 FROM (SELECT T.LOT_ID, PROCESS_RRN, PROCESS_VERSION, ROUTE_RRN, ");
                paramSql.append(" OPERATION_RRN, FLOW_SEQ, REGEXP_SUBSTR(T.EQUIPMENT_GROUP_RRNS, '[^,]+', 1,LEVEL)");
                paramSql.append(" EQUIPMENT_GROUP_RRN FROM (SELECT L.LOT_ID, PSA.EQUIPMENT_GROUP_RRNS, PSA.FLOW_SEQ, ");
                paramSql.append(" PSA.PROCESS_RRN, PSA.PROCESS_VERSION, PSA.ROUTE_RRN, PSA.OPERATION_RRN, ");
                paramSql.append(" ROWNUM NUM FROM PROCESS_SPEC_ITEM_ACTIVE PSA, LOT L WHERE PSA.PROCESS_RRN = ");
                paramSql.append(" L.PROCESS_RRN AND PSA.PROCESS_VERSION = L.PROCESS_VERSION AND PSA.OPERATION_RRN = ");
                paramSql.append(" L.OPERATION_RRN AND PSA.FLOW_SEQ = L.FLOW_SEQ  ");
                paramSql.append(" ) T CONNECT BY LEVEL <= ");
                paramSql.append(" REGEXP_COUNT(T.EQUIPMENT_GROUP_RRNS, '[^,]+') AND PRIOR NUM = NUM AND PRIOR ");
                paramSql.append(" DBMS_RANDOM.VALUE() IS NOT NULL) T WHERE EQUIPMENT_GROUP_RRN IN (" + select + ")");
                paramSql.append(" AND L.PROCESS_RRN = T.PROCESS_RRN AND L.PROCESS_VERSION = T.PROCESS_VERSION ");
                paramSql.append(" AND L.OPERATION_RRN = T.OPERATION_RRN  AND L.FLOW_SEQ=T.FLOW_SEQ )");
            }

            if (StringUtils.isNotBlank(lotQueryParameterDto.getMfgEqptGroupId())) {
                List<String> eqpGroups = new ArrayList<String>();

                if (StringUtils.isNotBlank(lotQueryParameterDto.getMfgEqptGroupId())) {
                    ReferenceFileDetail referenceFileDetail = new ReferenceFileDetail("$$MFGEQP_GROUP_ID",
                                                                                      namedObjectManager.getNamedSpace(
                                                                                              lotQueryParameterDto.getFacilityRrn(),
                                                                                              ObjectList.REFERENCE_FILE_KEY),
                                                                                      ObjectList.REFERENCE_FILE_KEY);
                    referenceFileDetail.setData1Value(lotQueryParameterDto.getMfgEqptGroupId());
                    if (StringUtils.isNotBlank(lotQueryParameterDto.getEqpGroupId())) {
                        referenceFileDetail.setKey1Value(lotQueryParameterDto.getEqpGroupId());
                    }
                    List<ReferenceFileDetail> referenceFileDetailList = referenceFileManager.getReferenceFileDetails(
                            referenceFileDetail, lotQueryParameterDto.getFacilityRrn());
                    if (CollectionUtils.isNotEmpty(referenceFileDetailList)) {
                        for (ReferenceFileDetail detail : referenceFileDetailList) {
                            eqpGroups.add(detail.getKey1Value());
                        }
                    }
                }

                if (CollectionUtils.isEmpty(eqpGroups)) {
                    paramSql.append(" and l.eqpt_rrn = null ");
                } else {
                    for (String eqp : eqpGroups) {

                        String select = "select t.operation_rrn from operation t where t.entity_group_rrn in " + "(select" +
                                " instance_rrn from named_object where instance_id {} )";
                        if (StringUtils.contains(eqp, '%')) {
                            select = StringUtils.replace(select, "{}", " like ? ");
                            args.add(eqp);
                        } else {
                            select = StringUtils.replace(select, "{}", " = ? ");
                            args.add(eqp);
                        }

                        paramSql.append(" and l.operation_rrn in (" + select + ") ");
                    }

                }
            }

            if (StringUtils.isNotBlank(lotQueryParameterDto.getMaterialLotId())) {
                paramSql.append(" and mater.unit_alias_2 like ? ");
                args.add(lotQueryParameterDto.getMaterialLotId());
            }

            if (StringUtils.isNotBlank(lotQueryParameterDto.getMySpecialLot())) {
                paramSql.append("and l.lot_rrn in (select ts.lot_rrn from t_user_special_lot ts where ts.user_rrn = ? )");
                args.add(lotQueryParameterDto.getUserRrn());
            }
            //for operator panel
            setConditionsForOperatorPanel(lotQueryParameterDto,paramSql,args);

            // --------------------select--------------------------------

            StringBuffer sqlBuffer = new StringBuffer();
            sqlBuffer.append("SELECT");
            sqlBuffer.append(" l.lot_type,l.Step_Sequence,l.RECIPE_STRING,l.HOLD_TIMESTAMP,l.prev_operation_rrn, ");
            sqlBuffer.append(" l.CREATE_CATEGORY,");
            sqlBuffer.append(" l.REWORK_CATEGORY, e.SHIPPING_CODE, e.CUSTOMER_ID,");
            sqlBuffer.append(" e.OUT_ORDER_TYPE, e.CUSTOMER_LOT_ID,l.FLOW_SEQ,e.LOCATION,e.PLOCATION,");
            sqlBuffer.append(
                    " l.lot_rrn, l.lot_id, l.lot_status, l.hot_flag, l.priority, l.due_date, getlotqty1(l" + ".LOT_RRN) " +
                            "AS QTY1, l" + ".input_qty1,");
            sqlBuffer.append(" l.carrier_rrn, l.product_rrn, l.lot_owner, l.process_rrn, l.process_version, l" +
                                     ".process_step_version, l.process_location, ");
            sqlBuffer.append(
                    " l.route_seq, l.operation_rrn, l.operation_version, l.operation_seq, l" + ".process_step_id_version," +
                            " l.eqpt_rrn,");
            sqlBuffer.append(" l.queue_timestamp, l.stage_id,l.lot_comments, ");
            sqlBuffer.append(
                    " e.outer_order_no ,e.INNER_ORDER_NO , e.attribute_data1 as pollution_level,e" +
                            ".CURRENT_STEP_TIME_STRUCT,");
            sqlBuffer.append(
                    "TO_NUMBER((SYSDATE - CASE WHEN l.LOT_STATUS <> 'HOLD' AND l.LOT_STATUS <> 'RUNNINGHOLD' " + "THEN " +
                            "SYSDATE ELSE NVL(l.hold_timestamp, SYSDATE) END) + (SYSDATE - NVL(l" +
                            ".queue_timestamp, SYSDATE))" + ") TOTAL_WAITING_TIME,");
            sqlBuffer.append("mater.unit_alias_2, ");
            sqlBuffer.append(
                    " ROUND((GETMINREMAINTIMEBYLOTRRN(l.LOT_RRN, '" + Constants.TIME_LIMIT.TIME_TYPE_MAX + "') / " +
                            "3600), 2) AS Q_TIME, l.JOB_RRN ");
            sqlBuffer.append(" FROM (LOT l left join LOT_EXT e on l.lot_rrn = e.lot_rrn)  ");
            sqlBuffer.append("left join (SELECT listagg(unit_alias_2, ',') WITHIN GROUP ( ORDER BY unit_alias_2 ) as " +
                                     "unit_alias_2 , lot_rrn" +
                                     " FROM (SELECT DISTINCT unit_alias_2,lot_rrn from unit ) unn GROUP BY unn" +
                                     ".lot_rrn) mater");

            sqlBuffer.append(" on l.lot_rrn = mater.lot_rrn");
            sqlBuffer.append(" where  1=1 ");

            sqlBuffer.append(paramSql.toString());

            pro.setArgs(args);
            pro.setSqlBuffer(sqlBuffer);
            return pro;
        }

        private String getReferValus(String ref, String key_value) {
            return referenceFileManager.getReferenceDetailExchange(ref, key_value, "DATA_1_VALUE");
        }

        private Map<String, Object> getQtimeRemainTime(Long lotRrn) {
            long minEndTimeMillis = Long.MAX_VALUE;
            Map<String, Object> map = new HashMap<String, Object>();

            List<HashMap<String, String>> timeLimitList = this.getLotTimeLimitStatus(lotRrn);
            if (timeLimitList.size() > 0) {
                for (Map<String, String> timeMap : timeLimitList) {
                    // 获取设置的qtime信息中最小的endTime,转化为毫秒
                    long endTimeMillis = DateUtils.parse(timeMap.get("endTime"), DateUtils.DATE_FORMAT).getTime();
                    if (endTimeMillis < minEndTimeMillis) {
                        minEndTimeMillis = endTimeMillis;
                    }
                }

                // 批次qtime信息循环结束
                if (minEndTimeMillis < Long.MAX_VALUE) {
                    map.put("isRemainTime", "Y");
                    // qtime处理为小时，保留两位小数，第三位四舍五入
                    String time = (new java.text.DecimalFormat("#0.00")).format(
                            (minEndTimeMillis - System.currentTimeMillis()) / 60000f / 60f);
                    map.put("remainTime", time);
                    return map;
                }
            }

            map.put("isRemainTime", "N");
            map.put("remainTime", 0);
            return map;
        }

        private List<HashMap<String, String>> getLotTimeLimitStatus(Long lotRrn) {
            List<HashMap<String, String>> result = new ArrayList<>();
            List<TimelimitStatus> timeLimitStatusList = this.getLotTimeLimitStatusByLotRrn(lotRrn, "NO_CLOSE");
            if (!timeLimitStatusList.isEmpty()) {
                HashMap<String, String> lotTimeLimit;
                for (TimelimitStatus timeLimitStatus : timeLimitStatusList) {
                    // NORMAL对应的是qtime设置的结束时间小于当前时间, SPECIAL对应的是qtime设置的结束时间大于当前时间
                    lotTimeLimit = new HashMap<>();

                    String timeType = "0".equals(timeLimitStatus.getTimeType()) ? "MaxTime" : "MinTime";
                    String limitType = "0".equals(timeLimitStatus.getLimitType()) ? "TrackOut" : "TrackIn";

                    long endTime = timeLimitStatus.getStartTime().getTime() + (timeLimitStatus.getTimeLimitSec() * 1000);
                    lotTimeLimit.put("timeType", timeType);
                    lotTimeLimit.put("endTime", DateUtils.formatDate(new Timestamp(endTime)));
                    lotTimeLimit.put("limitType", limitType);
                    lotTimeLimit.put("endStepRrn", timeLimitStatus.getEndOperationRrn().toString());
                    result.add(lotTimeLimit);
                }
            }
            return result;
        }

        private int getQTBufferTime() {
            String refFileId = "$$QTIME_BUFFER_TIME";
            List<ReferenceFileDetail> datas = referenceFileManager.getRefFileValues(refFileId,
                                                                                    LocalContext.getFacilityRrn());
            int bufferTime = 0;
            for (ReferenceFileDetail data : datas) {
                bufferTime = Integer.parseInt(data.getData1Value());
            }
            bufferTime = bufferTime / 60;
            return bufferTime;
        }

        private String parseRecipeParam(String r) {
            StringBuffer sb = new StringBuffer();

            while ((r != null) && (r.length() != 0)) {
                int i = r.indexOf(",");

                if (i == -1) {
                    i = r.length();
                }

                int j = r.indexOf("|");

                String t = "";

                if (j == -1) {

                } else {
                    t = r.substring(j + 1, i);
                }

                sb.append(t);
                sb.append(",");

                r = r.substring(i + 1);
            }
            if (sb.length() > 1) {
                sb.deleteCharAt(sb.length() - 1);
            }
            return sb.toString();
        }

        private String parseRecipeId(String r) {
            StringBuffer sb = new StringBuffer();
            while ((r != null) && (r.length() != 0)) {
                int i = r.indexOf(",");

                if (i == -1) {
                    i = r.length();
                }

                int j = r.indexOf("|");

                String t = "";

                if (j == -1) {
                    t = r.substring(0, i);
                } else {
                    t = r.substring(0, j);
                }
                String id = "";

                id = namedObjectManager.getInstanceId(new Long(t));

                sb.append(id);
                sb.append(",");

                r = r.substring(i + 1);
            }
            sb.deleteCharAt(sb.length() - 1);

            return sb.toString();
        }

        private List<String> getProductOrProcessByRelationInLotAndLotPlan(String targetfield, String likeField,
                                                                          String likeValue) {
            List<String> result = lotQueryDAO.getProductOrProcessByRelationInLotAndLotPlan(targetfield, likeField,
                                                                                           likeValue);
            if (CollectionUtils.isEmpty(result)) {
                result = Collections.emptyList();
            }
            return result;
        }

        private List<String> getInstanceIdsInLotAndLotPlan(String field) {
            List<String> data = lotQueryDAO.getInstanceIdsInLotAndLotPlan(field);
            if (CollectionUtils.isEmpty(data)) {
                data = Collections.emptyList();
            }
            return data;
        }

        private void buildLotPortalConditionMap(Map<String, Object> lotPortalFormMap) {
            if (StringUtils.isNotBlank(MapUtils.getString(lotPortalFormMap, "lotId"))) {
                lotPortalFormMap.put("lotId",
                                     StringUtils.replace(MapUtils.getString(lotPortalFormMap, "lotId"), "*", "%").toString()
                                                .toUpperCase());
            }
            if (MapUtils.getObject(lotPortalFormMap, "lotStatus") != null) {
                String[] lotStatusArray = (String[]) MapUtils.getObject(lotPortalFormMap, "lotStatus");
                List<String> lotStatusArrayList = new ArrayList<>(Arrays.asList(lotStatusArray));
                for (String str : lotStatusArray) {
                    if (StringUtils.equalsIgnoreCase(LotStatus.HOLD, str)) {
                        lotStatusArrayList.add(LotStatus.RUNNINGHOLD);
                    }
                }
                lotStatusArray = lotStatusArrayList.toArray(new String[lotStatusArrayList.size()]);
                if (lotStatusArray != null && lotStatusArray.length > 0) {
                    if (lotStatusArray.length != 1 || StringUtils.isNotEmpty(lotStatusArray[0])) {
                        lotPortalFormMap.put("lotStatusArray", lotStatusArray);
                    }
                } else {
                    lotPortalFormMap.put("lotStatusArray", lotStatusArray);
                }
            }
            if (MapUtils.getObject(lotPortalFormMap, "lotCategory") != null) {
                String[] lotCategoryArray = (String[]) MapUtils.getObject(lotPortalFormMap, "lotCategory");
                lotPortalFormMap.put("lotCategoryArray", lotCategoryArray);
            } else {
                lotPortalFormMap.put("lotCategory", StringUtils.EMPTY);
            }
            if (StringUtils.isNotBlank(MapUtils.getString(lotPortalFormMap, "productId"))) {
                lotPortalFormMap.put("productId",
                                     MapUtils.getString(lotPortalFormMap, "productId").replace("*", "%").toUpperCase());
            }
            if (StringUtils.isNotBlank(MapUtils.getString(lotPortalFormMap, "processId"))) {
                lotPortalFormMap.put("processId",
                                     MapUtils.getString(lotPortalFormMap, "processId").replace("*", "%").toUpperCase());
            }
            if (StringUtils.isNotBlank(MapUtils.getString(lotPortalFormMap, "routeId"))) {
                lotPortalFormMap.put("routeId",
                                     MapUtils.getString(lotPortalFormMap, "routeId").replace("*", "%").toUpperCase());
            }
            if (StringUtils.isNotBlank(MapUtils.getString(lotPortalFormMap, "carrierId"))) {
                lotPortalFormMap.put("carrierId",
                                     StringUtils.replace(MapUtils.getString(lotPortalFormMap, "carrierId"), "*", "%")
                                                .toString().toUpperCase());
            }
            if (StringUtils.isNotBlank(MapUtils.getString(lotPortalFormMap, "stationId"))) {
                lotPortalFormMap.put("stationId",
                                     MapUtils.getString(lotPortalFormMap, "stationId").replace("*", "%").toUpperCase());
            }
            if (StringUtils.isNotBlank(MapUtils.getString(lotPortalFormMap, "eqptGroupId"))) {
                lotPortalFormMap.put("eqptGroupId",
                                     MapUtils.getString(lotPortalFormMap, "eqptGroupId").replace("*", "%").toUpperCase());
            }

        }

        private void buildfWflSeqForLot(Lot lot) {
            String wflStepPath = lot.getWflStepPath();
            if (StringUtils.isBlank(wflStepPath)) {
                return;
            }
            //TODO 改回原SP，待验证
            String operationSeq = workflowManager.getWflSeq(wflStepPath.substring(wflStepPath.indexOf("|") + 1), "1");
            String routeSeq = workflowManager.getWflSeq(wflStepPath.substring(0, Math.max(wflStepPath.indexOf("|"), 0)),
                                                        "0");

            String layerId = workflowManager.getWflSeq(wflStepPath.substring(0, Math.max(wflStepPath.indexOf("|"), 0)),
                                                       "3");
            lot.setOperationSeq(operationSeq);
            lot.setRouteSeq(routeSeq);
            lot.setProductLayer(layerId);
        }

        private String buildLotStatusByLotStatusReference(String lotStatusKey, Long facilityRrn) {
            List<ReferenceFileDetail> statusRef = referenceFileManager.getRefFileValues("$$LOT_STATUS",
                                                                                        namedObjectManager.getNamedSpace(
                                                                                                facilityRrn,
                                                                                                ObjectList.REFERENCE_FILE_KEY));
            if (CollectionUtils.isNotEmpty(statusRef)) {
                for (ReferenceFileDetail rfd : statusRef) {
                    if (rfd != null && StringUtils.isNotBlank(rfd.getKey1Value())) {
                        if (StringUtils.equalsIgnoreCase(lotStatusKey, rfd.getKey1Value())) {
                            if (StringUtils.isNotBlank(rfd.getData1Value())) {
                                return rfd.getData1Value();
                            } else {
                                return rfd.getKey1Value();
                            }
                        }
                    }
                }
            }
            return lotStatusKey;
        }

        private List<LotRecycledInfo> queryEndOfLotRecycledInfoByLot(Lot lot) {
            LotRecycledInfo lotRecycledInfo = new LotRecycledInfo();

            lotRecycledInfo.setLotRrn(lot.getLotRrn());
            lotRecycledInfo.setProcessRrn(lot.getProcessRrn());
            lotRecycledInfo.setProcessVersion(lot.getProcessVersion());
            lotRecycledInfo.setEndRouteRrn(lot.getRouteRrn());
            lotRecycledInfo.setEndOperationRrn(lot.getOperationRrn());

            return qryLotRecycledInfos(lotRecycledInfo, "N");
        }

        private boolean isNeedLoopAgain(int currentLoopCount, int maxLoopCount) {
            return currentLoopCount < maxLoopCount;
        }

        private void setValue(List<Map<String, Object>> lots, LotQueryParameterDto queryParameterDto) {
            StopWatch stopWatch = new StopWatch("lot add property");

            Map<String, String> stageIdKeyMap = attributeConvertManager.getStageIdKeyMap();

            if (CollectionUtils.isNotEmpty(lots)) {
                long qTBufferTime = getQTBufferTime();

                long recipeContextRrn = namedObjectManager.getNamedObjectRrn(ContextNames.RECIPE_CONTEXT,
                                                                             queryParameterDto.getFacilityRrn(),
                                                                             ObjectList.CONTEXT_KEY);
                long reticleContextRrn = namedObjectManager.getNamedObjectRrn(ContextNames.RETICLEFAMILY_CONTEXT,
                                                                              queryParameterDto.getFacilityRrn(),
                                                                              ObjectList.CONTEXT_KEY);
                long stepDescContextRrn = namedObjectManager.getNamedObjectRrn(ContextNames.PROCESS_OPERATION_DESC_CONTEXT,
                                                                               queryParameterDto.getFacilityRrn(),
                                                                               ObjectList.CONTEXT_KEY);

                QueryMapCache cache = new QueryMapCache(queryParameterDto.getFacilityRrn(), stepDescContextRrn,
                                                        recipeContextRrn, reticleContextRrn);
                for (Map<String, Object> lot : lots) {
                    long lotRrn = MapUtils.getLongValue(lot, "lotRRN");
                    String lotId = MapUtils.getString(lot, "lotID");

                    try {
                        lot.put("qTBufferTime", qTBufferTime);

                        // productId
                        stopWatch.start("productId");
                        long productRrn = MapUtils.getLongValue(lot, "productRrn");
                        lot.put("productID", cache.getInstanceIdCache().get(productRrn));
                        stopWatch.stop();

                        // process
                        stopWatch.start("process");
                        long processRrn = MapUtils.getLongValue(lot, "processRrn");
                        lot.put("processId", cache.getInstanceIdCache().get(processRrn));
                        stopWatch.stop();

                        // carrierId
                        stopWatch.start("carrier");
                        lot.put("carrierId", namedObjectManager.getInstanceId(MapUtils.getLongValue(lot, "carrierRrn")));
                        stopWatch.stop();

                        // DOOR POD
                        stopWatch.start("door");
                        if (MapUtils.getLongValue(lot, "carrierRrn") > 0L) {
                            lot.put("podID",
                                    cache.getCarrierCache().get(MapUtils.getLongValue(lot, "carrierRrn")).get("podID"));
                        }
                        stopWatch.stop();

                        // batchId
                        stopWatch.start("batch");
                        String batchId = diffBatchQueryManager.getLotBatchId(lotRrn);
                        // String batchId = lotQueryDAO.getBatchId(lotRrn);
                        if (StringUtils.isNotBlank(batchId)) {
                            lot.put("batchId", batchId);
                        }
                        stopWatch.stop();

                        stopWatch.start("location");
                        // location
                        //功能 #27147 location显示为running时批次所在设备id,plocation显示为批次在上一步骤作业的设备。
                        if (StringUtils.equalsIgnoreCase(MapUtils.getString(lot, "lotStatus"), LotStatus.RUNNING)) {
                            Map equipmentInfos = buildEquipInfoForLot(MapUtils.getString(lot, "lotStatus"),
                                                                      MapUtils.getLong(lot, "eqpRrn"));
                            if (equipmentInfos.size() > 0 && "AVAILABLE".equalsIgnoreCase(
                                    MapUtils.getString(equipmentInfos, "equipmentAvailable"))) {
                                lot.put("location", MapUtils.getString(equipmentInfos, "equipmentId"));
                            } else {
                                lot.put("location", "");
                            }
                        } else {
                            String locationId= locationInqManager
                                    .getLocationIdOrEquipmentId(MapUtils.getLong(lot, "locationRrn", 0L));
                            lot.put("location", locationId);
                        }
                        // pLocation
                        Long pLocationRrn = MapUtils.getLong(lot, "pLocationRrn");
                        if (pLocationRrn != null && pLocationRrn > 0) {
                            String pLocationId= locationInqManager
                                    .getLocationIdOrEquipmentId(pLocationRrn);
                            lot.put("pLocation", pLocationId);
                        } else {
                            lot.put("pLocation", Math.abs(pLocationRrn) == 0 ? "" : Math.abs(pLocationRrn));
                        }

                        stopWatch.stop();

                        //COMMETN
                        stopWatch.start("lotComment");
                        List commentList = qryLotHistoryCommentByTime(lotRrn);
                        StringBuilder commentStr = new StringBuilder();
                        //取commentList 第一条，即历史最新一条
                        for (Object o : commentList) {
                            Map m = (HashMap) o;
                            commentStr.append(MapUtils.getString(m, "stepComment"));
                            break;
                        }
                        lot.put("lotComment", commentStr);
                        stopWatch.stop();

                        // HOLD_DEPT HOLD_REASON
                        stopWatch.start("hold");
                        if (StringUtils.equals(LotStatus.HOLD, MapUtils.getString(lot, "lotStatus")) ||
                                StringUtils.equals(LotStatus.RUNCARD_HOLD, MapUtils.getString(lot, "lotStatus")) ||
                                StringUtils.equals(LotStatus.RUNNINGHOLD, MapUtils.getString(lot, "lotStatus")) ||
                                StringUtils.equals(LotStatus.BANKED, MapUtils.getString(lot, "lotStatus"))) {

                            long holdRrn = lotQueryDAO.getHoldTransRrn(lotRrn);
                            String holdReson = lotQueryDAO.getTransReasonByTrans(holdRrn, lotRrn);

                            if (StringUtils.isNotBlank(holdReson)) {
                                String dept = StringUtils.substringBefore(holdReson, "Reason:");
                                String comment = StringUtils.substringAfter(holdReson, "Reason:");
                                dept = StringUtils.isEmpty(dept) ? "SYSTEM" : dept;
                                lot.put("holdDept", dept.length() == holdReson.length() ? "SYSTEM" : dept);
                                lot.put("holdComment", comment.length() == 0 ? holdReson : comment);
                            }
                        }
                        stopWatch.stop();

                        //					 runcardId
                        stopWatch.start("runcard");
                        //功能 #26322 只要存在runcardId就显示
                        List<String> status = new ArrayList<String>();
                        status.add("PROCESSING");
                        lot.put("runcardId", "");
                        LotRunCard runcard = runCardQueryManager.getLotRunCardByMainLot(MapUtils.getLong(lot, "lotRRN"));
                        if (runcard != null) {
                            lot.put("runcardId", cache.getInstanceIdCache().get(runcard.getRunCardRrn()));
                        }
                        stopWatch.stop();

                        // LOT_RUN_TIME
                        stopWatch.start("LOT_RUN_TIME");
                        if (StringUtils.equalsIgnoreCase(LotStatus.RUNNING,
                                                         MapUtils.getString(lot, "lotStatus", StringUtils.EMPTY)) ||
                                StringUtils.endsWithIgnoreCase(LotStatus.RUNNINGHOLD,
                                                               MapUtils.getString(lot, "lotStatus", StringUtils.EMPTY))) {
                            List<Long> transRrns = lotQueryDAO.getLotTransRrnByLot(lotRrn, MapUtils.getIntValue(lot,
                                                                                                                "Step_Sequence"));
                            if (CollectionUtils.isNotEmpty(transRrns)) {
                                TransactionLog log = lotQueryDAO.getTransactionLogByRrn(transRrns.get(0));
                                if (log.getTransEndTimestamp() != null) {
                                    LocalDateTime transEndTime = log.getTransEndTimestamp().toLocalDateTime();
                                    Duration duration = Duration.between(transEndTime, LocalDateTime.now());
                                    long minutes = duration.toMinutes();

                                    String runTimeHr = (new java.text.DecimalFormat("#0.00")).format(minutes / 60f);
                                    // running状态批次才显示runTime
                                    lot.put("runTime", runTimeHr);
                                }
                            }
                        }
                        stopWatch.stop();

                        // qty1
                        stopWatch.start("qty");
                        if (StringUtils.equals(LotStatus.BONDED, MapUtils.getString(lot, "lotStatus", StringUtils.EMPTY))) {
                            int qty = lotQueryDAO.getLotWaferCount(MapUtils.getLongValue(lot, "lotRRN"));
                            lot.put("qty1", qty);
                        }
                        stopWatch.stop();

                        // route
                        stopWatch.start("route");
                        String processStepIdVersion = MapUtils.getString(lot, "processStepIdVersion");
                        String routeId = null;
                        if (processStepIdVersion != null) {
                            int firstSep = processStepIdVersion.indexOf("|");
                            int secondSep = processStepIdVersion.indexOf("|", firstSep + 1);
                            if (secondSep >= 0) {
                                routeId = processStepIdVersion.substring(firstSep + 1,
                                                                         processStepIdVersion.indexOf(",", firstSep));
                            } else {
                                routeId = processStepIdVersion.substring(0, processStepIdVersion.indexOf(","));
                            }
                        }

                        lot.put("routeID", routeId);
                        stopWatch.stop();

                        long operationRrn = MapUtils.getLongValue(lot, "stepRrn");
                        // step
                        //需求 #44059
                        //banked状态的lot显示prevOperationId而不是WAFER START BANK
                        if(StringUtils.equals(LotStatus.BANKED, MapUtils.getString(lot, "lotStatus"))){
                            operationRrn = lotInqManager.getLot(MapUtils.getLongValue(lot, "lotRRN")).getPrevOperationRrn();
                        }
                        if (operationRrn != 0) {
                            stopWatch.start("stepid");
                            // 旧的是截取的processStepIdVersion 但是按照Andy的意思 新的从namedobject查询
                            lot.put("stepID",
                                    //	                          LotUtils.getOperationIdByProcessStep(MapUtils
                                    //	                          .getString(lot, "processStepIdVersion")));
                                    cache.getInstanceIdCache().get(operationRrn));
                            stopWatch.stop();
                        }

                        if (RunCardUtils.checkLotIdIsRunCardLot(lotId)) {
                            LotRunCardStep stepInfo = runCardQueryManager.getLotRunCardStep(lotRrn);
                            if (Objects.isNull(stepInfo)) {
                                continue;
                            }

                            stopWatch.start("runcardspec");
                            // recipe
                            lot.put("recipeID", stepInfo.getRecipeId());
                            lot.put("stepDesc", stepInfo.getComments());
                            stopWatch.stop();

                            stopWatch.start("eqpgroup");
                            if (Objects.nonNull(stepInfo.getEquipmentGroupRrn()) &&
                                    stepInfo.getEquipmentGroupRrn().longValue() > 0) {
                                String eqptGroupId = cache.getInstanceIdCache().get(stepInfo.getEquipmentGroupRrn());
                                String eqpids = cache.getEqpGroupEqpIds().get(stepInfo.getEquipmentGroupRrn());
                                lot.put("eqptGroupId", eqptGroupId);
                                lot.put("eqptList", eqpids);
                                lot.put("eqptId", eqpids);
                            } else if (Objects.nonNull(stepInfo.getEquipmentRrn()) &&
                                    stepInfo.getEquipmentRrn().longValue() > 0) {
                                String eqptGroupIds = equipmentQueryManager.getEqpGroupIdsByEquipmentRrn(
                                        stepInfo.getEquipmentRrn());
                                String eqptId = cache.getInstanceIdCache().get(stepInfo.getEquipmentRrn());
                                lot.put("eqptGroupId", eqptGroupIds);
                                lot.put("eqptList", eqptId);
                                lot.put("eqptId", eqptId);
                            }
                            stopWatch.stop();

                            stopWatch.start("MFGEqptGroupId");
                            lot.put("MFGEqptGroupId",
                                    cache.getMfgEqpGroupCache().get(MapUtils.getString(lot, "eqptGroupId", "empty")));
                            stopWatch.stop();

                            // 没有设备就显示工步上设备组的所有设备
                            stopWatch.start("eqpid");
                            if (MapUtils.getLongValue(lot, "eqpRrn") > 0) {
                                lot.put("eqptId", cache.getInstanceIdCache().get(MapUtils.getLongValue(lot, "eqpRrn")));
                            }
                            stopWatch.stop();

                            stopWatch.start("reticle");
                            lot.put("reticles", cache.getInstanceIdCache().get(stepInfo.getReticleRrn()));
                            stopWatch.stop();

                            lot.put("workArea", stepInfo.getAreaId());
                            lot.put("stageID", stepInfo.getStageId());
                        } else if (lotAutoMonitorInqManager.checkLotIsAutoMonitorLot(lotRrn)) {
                            LotAutoMonitorInfo monitorInfo = lotAutoMonitorInqManager.getLotAutoMonitorInfo(lotRrn);
                            if (Objects.isNull(monitorInfo)) {
                                continue;
                            }

                            stopWatch.start("automonitorspec");
                            // recipe
                            lot.put("recipeID", monitorInfo.getRecipeId());
                            lot.put("stepDesc", monitorInfo.getOpeartionDesc());
                            stopWatch.stop();

                            stopWatch.start("eqpgroup");
                            if (Objects.nonNull(monitorInfo.getEqptGroupRrn()) &&
                                    monitorInfo.getEqptGroupRrn().longValue() > 0) {
                                String eqptGroupId = cache.getInstanceIdCache().get(monitorInfo.getEqptGroupRrn());
                                String eqpids = cache.getEqpGroupEqpIds().get(monitorInfo.getEqptGroupRrn());
                                lot.put("eqptGroupId", eqptGroupId);
                                lot.put("eqptList", eqpids);
                                lot.put("eqptId", eqpids);
                            } else if (Objects.nonNull(monitorInfo.getEqptRrn()) &&
                                    monitorInfo.getEqptRrn().longValue() > 0) {
                                String eqptGroupIds = equipmentQueryManager.getEqpGroupIdsByEquipmentRrn(
                                        monitorInfo.getEqptRrn());
                                String eqptId = cache.getInstanceIdCache().get(monitorInfo.getEqptRrn());
                                lot.put("eqptGroupId", eqptGroupIds);
                                lot.put("eqptList", eqptId);
                                lot.put("eqptId", eqptId);
                            }
                            stopWatch.stop();

                            stopWatch.start("MFGEqptGroupId");
                            lot.put("MFGEqptGroupId",
                                    cache.getMfgEqpGroupCache().get(MapUtils.getString(lot, "eqptGroupId", "empty")));
                            stopWatch.stop();

                            // 没有设备就显示工步上设备组的所有设备
                            stopWatch.start("eqpid");
                            if (MapUtils.getLongValue(lot, "eqpRrn") > 0) {
                                lot.put("eqptId", cache.getInstanceIdCache().get(MapUtils.getLongValue(lot, "eqpRrn")));
                            }
                            stopWatch.stop();

                            stopWatch.start("reticle");
                            lot.put("reticles", cache.getInstanceIdCache().get(monitorInfo.getReticleRrn()));
                            stopWatch.stop();

                            //lot.put("workArea", monitorInfo.get.getAreaId());
                            lot.put("workArea", monitorInfo.getEqptLocation());
                            lot.put("stageID", monitorInfo.getStageId());
                            if (LotStatus.isAutoMonitorMerge(MapUtils.getString(lot, "lotStatus"))) {
                                lot.put("stageID", AutoMonitorOperationConstants.PARENT_MERGE_STAGE);
                            }
                        } else {
                            // recipe
                            stopWatch.start("recipe");
                            Lot endLot = getLot(lotRrn);
                            int processVersion = MapUtils.getIntValue(lot, "processVersion");
                            int productVersion = endLot.getProductVersion();

                            String processStepVersion = MapUtils.getString(lot, "processStepVersion");
                            long routeRrn = 0L;
                            if (processStepVersion != null) {
                                int firstSep = processStepVersion.indexOf("|");
                                int secondSep = processStepVersion.indexOf("|", firstSep + 1);
                                if (secondSep >= 0) {
                                    routeRrn = new Long(processStepVersion.substring(firstSep + 1,
                                                                                     processStepVersion.indexOf(",",
                                                                                                                firstSep)));
                                } else {
                                    routeRrn = new Long(processStepVersion.substring(0, processStepVersion.indexOf(",")));
                                }
                            }

                            Map<String, Object> context = cache.getProContextCache()
                                                               .get(productRrn + "," + routeRrn + "," + processRrn + "," +
                                                                            processVersion + "," + operationRrn + "," +
                                                                            productVersion);

                            if (MapUtils.isNotEmpty(context)) {
                                if (MapUtils.getLongValue(context, "recipe_rrn") != 0L) {
                                    lot.put("recipeID",
                                            cache.getInstanceIdCache().get(MapUtils.getLongValue(context, "recipe_rrn")));
                                }

                                lot.put("stepDesc", MapUtils.getString(context, "operation_description"));
                            }
                            stopWatch.stop();
                            // eqpId eqpgroupid
                            stopWatch.start("eqpgroup");

                            String eqpGroupRrns = cache.getStepEqpGroupCache()
                                                       .get(processRrn + "," + processVersion + "," + routeRrn + "," +
                                                                    operationRrn);
                            if (StringUtils.isNotBlank(eqpGroupRrns)) {
                                String[] eqpGroupRrnArr = eqpGroupRrns.split(",");
                                List eqptGroupIdList = new ArrayList();
                                List eqptIdsList = new ArrayList();
                                for (String eqpGroupRrn : eqpGroupRrnArr) {
                                    String eqptGroupId = cache.getInstanceIdCache().get(Long.parseLong(eqpGroupRrn));
                                    String eqpids = cache.getEqpGroupEqpIds().get(Long.parseLong(eqpGroupRrn));
                                    eqptGroupIdList.add(eqptGroupId);
                                    eqptIdsList.add(eqpids);
                                }
                                lot.put("eqptGroupId", String.join(",", eqptGroupIdList));
                                lot.put("eqptList", String.join(",", eqptIdsList));
                                lot.put("eqptId", String.join(",", eqptIdsList));
                            }
                            stopWatch.stop();

                            stopWatch.start("MFGEqptGroupId");
                            lot.put("MFGEqptGroupId",
                                    cache.getMfgEqpGroupCache().get(MapUtils.getString(lot, "eqptGroupId", "empty")));
                            stopWatch.stop();

                            // 没有设备就显示工步上设备组的所有设备
                            stopWatch.start("eqpid");
                            if (MapUtils.getLongValue(lot, "eqpRrn") > 0) {
                                lot.put("eqptId", cache.getInstanceIdCache().get(MapUtils.getLongValue(lot, "eqpRrn")));
                            }
                            stopWatch.stop();

                            stopWatch.start("reticle");
                            lot.put("reticles", cache.getReticleCache()
                                                     .get(productRrn + "," + routeRrn + "," + processRrn + "," +
                                                                  processVersion + "," + operationRrn));
                            stopWatch.stop();

                            // workArea
                            stopWatch.start("workArea");
                            if (StringUtils.isNotBlank(queryParameterDto.getWorkArea())) {
                                lot.put("workArea", queryParameterDto.getWorkArea());
                            } else {
                                //构造必要查询条件
                                ProcessSpecItem processSpecItem = new ProcessSpecItem(processRrn, processVersion, routeRrn,
                                                                                      operationRrn);
                                lot.put("workArea", cache.getWorkAreaCache().get(processSpecItem));
                            }
                            stopWatch.stop();

                            // stageId
                            stopWatch.start("stageID");
                            if (StringUtils.isNotBlank(queryParameterDto.getStageId())) {
                                lot.put("stageID", stageIdKeyMap.get(queryParameterDto.getStageId()));
                            } else {
                                if(StringUtils.isEmpty(MapUtils.getString(lot,"stageID"))){
                                    //构造必要查询条件
                                    ProcessSpecItem processSpecItem = new ProcessSpecItem(processRrn, processVersion, routeRrn,
                                                                                          operationRrn);
                                String stageId = MapUtils
                                        .getString(stageIdKeyMap, cache.getStageIdCache().get(processSpecItem));

                                    lot.put("stageID", stageId);
                                }
                            }
                            stopWatch.stop();
                        }

                        if (logger.isDebugEnabled()) {
                            logger.debug(stopWatch.prettyPrint());
                        }

                    } catch (Exception e) {
                        logger.error("lotRrn: " + lotRrn);
                        throw new SystemIllegalStateException(Errors.create().content(e.getMessage()).build());
                    }
                }
            }
        }

        private Map buildEquipInfoForLot(String lotStatus, Long eqptRrn) {
            long facilityRrn = LocalContext.getFacilityRrn();
            Map<String, Object> equipmentInfo = new HashMap<>();
            if (eqptRrn != null) {
                Entity equipment = new Equipment();
                equipment.setInstanceRrn(eqptRrn);
                equipment = entityManager.getEntity(equipment);
                String equipmentId = equipment.getInstanceId();
                equipmentInfo.put("equipmentId", equipmentId);
                // check equipment status
                String equipmenStatus = entityManager.getEntityCurrentStatus(eqptRrn);
                equipmentInfo.put("equipmentStatus", equipmenStatus);
                if (equipmenStatus != null &&
                        (equipmenStatus.equals(EventName.DOWN) || equipmenStatus.equals(EventName.OFF) ||
                                equipmenStatus.equals(EventName.FACD)) &&
                        !((StringUtils.equals(lotStatus, LotStatus.RUNNING) ||
                                StringUtils.equals(lotStatus, LotStatus.DISPATCH) ||
                                StringUtils.equals(lotStatus, LotStatus.PROCESSED)) &&
                                StringUtils.equalsIgnoreCase(equipmenStatus, EventName.DOWN))) {
                    equipmentInfo.put("equipmentAvailable", "NOT_AVAILABLE");
                } else {
                    equipmentInfo.put("equipmentAvailable", "AVAILABLE");
                }
            }
            return equipmentInfo;
        }

        private String buildSqlForLotCount(Map conditionMap, List<Object> args) {
            StringBuilder sb = new StringBuilder();
            String selectRow = "";
            String selectTable = "";
            StringBuilder selectWhere = new StringBuilder();
            StringBuilder exceptWhere = new StringBuilder();
            String type = MapUtils.getString(conditionMap, "type", StringUtils.EMPTY);
            String level = MapUtils.getString(conditionMap, "level", StringUtils.EMPTY);
            String startTime = MapUtils.getString(conditionMap, "startTime", StringUtils.EMPTY);
            String endTime = MapUtils.getString(conditionMap, "endTime", StringUtils.EMPTY);
            if (StringUtils.equals("eqptConstrain", type)) {
                EquipmentConstrainInfo constrainInfo = (EquipmentConstrainInfo) MapUtils.getObject(conditionMap,
                                                                                                   "constrainInfo");
                if (constrainInfo != null && constrainInfo.getConstrainRrn() > 0) {
                    Entity entity = entityManager.getEntity(
                            namedObjectManager.getNamedObjectRrn(constrainInfo.getEquipmentId(),
                                                                 LocalContext.getFacilityRrn(), ObjectList.ENTITY_KEY));
                    boolean isChamber = entity.getParentEntityRrn() != null && entity.getParentEntityRrn() > 0;

                    boolean isWaferLevel = StringUtils.equalsIgnoreCase(level, EquipmentConstrainInfo.WAFER);
                    String subWhere = "";
                    String tableRowName = "";
                    String constrainFieldName = "";
                    String[] constrainFieldArr = null;

                    if (isChamber) {
                        selectTable = "ELOG_SHEET_CHAMBER T";
                        selectWhere.append(" AND T.CHAMBER_TYPE IS NOT NULL ");
                        if (isWaferLevel) {
                            selectRow = "SUM(CHAMBER_QTY)";
                        } else {
                            selectRow = "COUNT(1)";
                        }
                    } else {
                        selectTable = "EQUIPMENT_RUN_HISTORY T";
                        selectWhere.append(" AND T.RUN_TYPE = 'MOVEIN' AND T.RUN_MODE = 'EAP' ");
                        // 排除YESKIP和MISKIP的批次
                        selectWhere.append(
                                " AND T.EQUIPMENT_RUN_USER NOT LIKE 'YESKIP-%' AND T.EQUIPMENT_RUN_USER NOT LIKE " +
                                        "'MISKIP-%' ");
                        if (isWaferLevel) {
                            selectRow = "SUM(qty1)";
                        } else {
                            selectRow = "COUNT(1)";
                        }
                    }
                    // time
                    if (isChamber) {
                        tableRowName = "T.PROCESS_END_TIME";
                    } else {
                        tableRowName = "T.EQUIPMENT_RUN_TIME";
                    }
                    if (StringUtils.isNotEmpty(startTime)) {
                        selectWhere.append(" AND " + tableRowName + " > TO_DATE(?, 'yyyy-mm-dd hh24:mi:ss') ");
                        args.add(startTime);
                    }
                    if (StringUtils.isNotEmpty(endTime)) {
                        selectWhere.append(" AND " + tableRowName + " < TO_DATE(?, 'yyyy-mm-dd hh24:mi:ss') ");
                        args.add(endTime);
                    }

                    // equipment
                    constrainFieldName = constrainInfo.getEquipmentId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        if (isChamber) {
                            selectWhere.append(" AND T.EQUIPMENT_ID = ? AND T.CHAMBER_TYPE = ?");
                            args.add(namedObjectManager.getInstanceId(entity.getParentEntityRrn()));
                            args.add(entity.getChamberType());
                        } else {
                            selectWhere.append(" AND T.EQUIPMENT_ID = ? ");
                            args.add(constrainFieldName);
                        }
                    }
                    // product
                    constrainFieldName = constrainInfo.getProductId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " AND (";
                        for (String producId : constrainFieldArr) {
                            if (StringUtils.isEmpty(producId)) {
                                continue;
                            }
                            subWhere += " T.PRODUCT_ID LIKE ? OR";
                            args.add(MiscUtils.parseToFuzzySQL(producId));
                        }
                        selectWhere.append(StringUtils.substringBeforeLast(subWhere, "OR"));
                        selectWhere.append(")");
                    }
                    // process
                    constrainFieldName = constrainInfo.getProcessId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " AND (";
                        for (String processId : constrainFieldArr) {
                            if (StringUtils.isEmpty(processId)) {
                                continue;
                            }
                            subWhere += " T.PROCESS_ID LIKE ? OR";
                            args.add(MiscUtils.parseToFuzzySQL(processId));
                        }
                        selectWhere.append(StringUtils.substringBeforeLast(subWhere, "OR"));
                        selectWhere.append(")");
                    }
                    // lot
                    constrainFieldName = constrainInfo.getLotId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " AND (";
                        for (String lotId : constrainFieldArr) {
                            if (StringUtils.isEmpty(lotId)) {
                                continue;
                            }
                            subWhere += " T.LOT_ID LIKE ? OR";
                            args.add(MiscUtils.parseToFuzzySQL(lotId));
                        }
                        selectWhere.append(StringUtils.substringBeforeLast(subWhere, "OR"));
                        selectWhere.append(")");
                    }
                    // operation
                    constrainFieldName = constrainInfo.getOperationId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        if (isChamber) {
                            tableRowName = "T.STEP_ID";
                        } else {
                            tableRowName = "T.OPERATION_ID";
                        }
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " AND (";
                        for (String operationId : constrainFieldArr) {
                            if (StringUtils.isEmpty(operationId)) {
                                continue;
                            }
                            subWhere += tableRowName + " LIKE ? OR ";
                            args.add(MiscUtils.parseToFuzzySQL(operationId));
                        }
                        selectWhere.append(StringUtils.substringBeforeLast(subWhere, "OR"));
                        selectWhere.append(")");
                    }
                    // stage
                    constrainFieldName = constrainInfo.getStageId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " AND (";
                        for (String stageId : constrainFieldArr) {
                            if (StringUtils.isEmpty(stageId)) {
                                continue;
                            }
                            subWhere += " T.STAGE_ID LIKE ? OR";
                            args.add(MiscUtils.parseToFuzzySQL(stageId));
                        }
                        selectWhere.append(StringUtils.substringBeforeLast(subWhere, "OR"));
                        selectWhere.append(")");
                    }
                    // recipe
                    constrainFieldName = constrainInfo.getRecipeId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        if (isChamber) {
                            tableRowName = "T.RECIPE_ID";
                        } else {
                            tableRowName = "T.VALIDATE_RECIPE_ID";
                        }
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " AND (";
                        for (String recipeId : constrainFieldArr) {
                            if (StringUtils.isEmpty(recipeId)) {
                                continue;
                            }
                            subWhere += tableRowName + " LIKE ? OR ";
                            args.add(MiscUtils.parseToFuzzySQL(recipeId));
                        }
                        selectWhere.append(StringUtils.substringBeforeLast(subWhere, "OR"));
                        selectWhere.append(")");
                    }
                    // customer
                    constrainFieldName = constrainInfo.getCustomerId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " AND (";
                        for (String customerId : constrainFieldArr) {
                            if (StringUtils.isEmpty(customerId)) {
                                continue;
                            }
                            subWhere += " T.CUSTOMER_ID LIKE ? OR";
                            args.add(MiscUtils.parseToFuzzySQL(customerId));
                        }
                        selectWhere.append(StringUtils.substringBeforeLast(subWhere, "OR"));
                        selectWhere.append(")");
                    }
                    // lot type
                    constrainFieldName = constrainInfo.getLotType();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " AND (";
                        for (String lotType : constrainFieldArr) {
                            if (StringUtils.isEmpty(lotType)) {
                                continue;
                            }
                            subWhere += " T.LOT_TYPE LIKE ? OR";
                            args.add(MiscUtils.parseToFuzzySQL(lotType));
                        }
                        selectWhere.append(StringUtils.substringBeforeLast(subWhere, "OR"));
                        selectWhere.append(")");
                    }
                    // hot flag
                    constrainFieldName = constrainInfo.getLotPriority();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        if (isChamber) {
                            tableRowName = "T.PRIORITY";
                        } else {
                            tableRowName = "T.HOT_FLAG";
                        }
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " AND (";
                        for (String hotFlag : constrainFieldArr) {
                            if (StringUtils.isEmpty(hotFlag)) {
                                continue;
                            }
                            subWhere += tableRowName + " LIKE ? OR ";
                            args.add(MiscUtils.parseToFuzzySQL(hotFlag));
                        }
                        selectWhere.append(StringUtils.substringBeforeLast(subWhere, "OR"));
                        selectWhere.append(")");
                    }
                    // priority
                    constrainFieldName = constrainInfo.getInternalPriority();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        if (isChamber) {
                            tableRowName = "T.PRIORITY";
                        } else {
                            tableRowName = "T.HOT_FLAG";
                        }
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " AND (";
                        for (String priority : constrainFieldArr) {
                            if (StringUtils.isEmpty(priority)) {
                                continue;
                            }
                            subWhere += tableRowName + " LIKE ? OR ";
                            args.add(MiscUtils.parseToFuzzySQL(priority));
                        }
                        selectWhere.append(StringUtils.substringBeforeLast(subWhere, "OR"));
                        selectWhere.append(")");
                    }
                    // equipment group
                    constrainFieldName = constrainInfo.getEqpGroupId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");

                        selectWhere.append(" AND ")
                                   .append(getEquipmentGroupFilterSQL(constrainFieldArr, args, isChamber, false));

                    }

                    // except product
                    constrainFieldName = constrainInfo.getExceptProductId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " OR (";
                        for (String producId : constrainFieldArr) {
                            if (StringUtils.isEmpty(producId)) {
                                continue;
                            }
                            subWhere += " T.PRODUCT_ID NOT LIKE ? AND";
                            args.add(MiscUtils.parseToFuzzySQL(producId));
                        }
                        exceptWhere.append(StringUtils.substringBeforeLast(subWhere, "AND"));
                        exceptWhere.append(")");
                    }
                    // except process
                    constrainFieldName = constrainInfo.getExceptProcessId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " OR (";
                        for (String processId : constrainFieldArr) {
                            if (StringUtils.isEmpty(processId)) {
                                continue;
                            }
                            subWhere += " T.PROCESS_ID NOT LIKE ? AND";
                            args.add(MiscUtils.parseToFuzzySQL(processId));
                        }
                        exceptWhere.append(StringUtils.substringBeforeLast(subWhere, "AND"));
                        exceptWhere.append(")");
                    }
                    // except lot
                    constrainFieldName = constrainInfo.getExceptLotId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " OR (";
                        for (String lotId : constrainFieldArr) {
                            if (StringUtils.isEmpty(lotId)) {
                                continue;
                            }
                            subWhere += " T.LOT_ID NOT LIKE ? AND";
                            args.add(MiscUtils.parseToFuzzySQL(lotId));
                        }
                        exceptWhere.append(StringUtils.substringBeforeLast(subWhere, "AND"));
                        exceptWhere.append(")");
                    }
                    // except operation
                    constrainFieldName = constrainInfo.getExceptOperationId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        if (isChamber) {
                            tableRowName = "T.STEP_ID";
                        } else {
                            tableRowName = "T.OPERATION_ID";
                        }
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " OR (";
                        for (String operationId : constrainFieldArr) {
                            if (StringUtils.isEmpty(operationId)) {
                                continue;
                            }
                            subWhere += tableRowName + " NOT LIKE ? AND ";
                            args.add(MiscUtils.parseToFuzzySQL(operationId));
                        }
                        exceptWhere.append(StringUtils.substringBeforeLast(subWhere, "AND"));
                        exceptWhere.append(")");
                    }
                    // except stage
                    constrainFieldName = constrainInfo.getExceptStageId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " OR (";
                        for (String stageId : constrainFieldArr) {
                            if (StringUtils.isEmpty(stageId)) {
                                continue;
                            }
                            subWhere += " T.STAGE_ID NOT LIKE ? AND";
                            args.add(MiscUtils.parseToFuzzySQL(stageId));
                        }
                        exceptWhere.append(StringUtils.substringBeforeLast(subWhere, "AND"));
                        exceptWhere.append(")");
                    }
                    // except recipe
                    constrainFieldName = constrainInfo.getExceptRecipeId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        if (isChamber) {
                            tableRowName = "T.RECIPE_ID";
                        } else {
                            tableRowName = "T.VALIDATE_RECIPE_ID";
                        }
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " OR (";
                        for (String recipeId : constrainFieldArr) {
                            if (StringUtils.isEmpty(recipeId)) {
                                continue;
                            }
                            subWhere += tableRowName + " NOT LIKE ? AND ";
                            args.add(MiscUtils.parseToFuzzySQL(recipeId));
                        }
                        exceptWhere.append(StringUtils.substringBeforeLast(subWhere, "AND"));
                        exceptWhere.append(")");
                    }
                    // except customer
                    constrainFieldName = constrainInfo.getExceptCustomerId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " OR (";
                        for (String customerId : constrainFieldArr) {
                            if (StringUtils.isEmpty(customerId)) {
                                continue;
                            }
                            subWhere += " T.CUSTOMER_ID NOT LIKE ? AND";
                            args.add(MiscUtils.parseToFuzzySQL(customerId));
                        }
                        exceptWhere.append(StringUtils.substringBeforeLast(subWhere, "AND"));
                        exceptWhere.append(")");
                    }
                    // except lot type
                    constrainFieldName = constrainInfo.getExceptLotType();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " OR (";
                        for (String lotType : constrainFieldArr) {
                            if (StringUtils.isEmpty(lotType)) {
                                continue;
                            }
                            subWhere += " T.LOT_TYPE NOT LIKE ? AND";
                            args.add(MiscUtils.parseToFuzzySQL(lotType));
                        }
                        exceptWhere.append(StringUtils.substringBeforeLast(subWhere, "AND"));
                        exceptWhere.append(")");
                    }
                    // except hot flag
                    constrainFieldName = constrainInfo.getExceptLotPriority();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        if (isChamber) {
                            tableRowName = "T.PRIORITY";
                        } else {
                            tableRowName = "T.HOT_FLAG";
                        }
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " OR (";
                        for (String hotFlag : constrainFieldArr) {
                            if (StringUtils.isEmpty(hotFlag)) {
                                continue;
                            }
                            subWhere += tableRowName + " NOT LIKE ? AND ";
                            args.add(MiscUtils.parseToFuzzySQL(hotFlag));
                        }
                        exceptWhere.append(StringUtils.substringBeforeLast(subWhere, "AND"));
                        exceptWhere.append(")");
                    }
                    // except priority
                    constrainFieldName = constrainInfo.getExceptInternalPriority();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        if (isChamber) {
                            tableRowName = "T.INTERNAL_PRIORITY";
                        } else {
                            tableRowName = "T.PRIORITY";
                        }
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        subWhere = " OR (";
                        for (String priority : constrainFieldArr) {
                            if (StringUtils.isEmpty(priority)) {
                                continue;
                            }
                            subWhere += tableRowName + " NOT LIKE ? AND ";
                            args.add(MiscUtils.parseToFuzzySQL(priority));
                        }
                        exceptWhere.append(StringUtils.substringBeforeLast(subWhere, "AND"));
                        exceptWhere.append(")");
                    }
                    // except equipment group
                    constrainFieldName = constrainInfo.getExceptEqpGroupId();
                    if (StringUtils.isNotEmpty(constrainFieldName) && !StringUtils.equals(constrainFieldName, "*")) {
                        constrainFieldArr = StringUtils.split(constrainFieldName, ",");
                        exceptWhere.append(" OR ( NOT ");
                        exceptWhere.append(getEquipmentGroupFilterSQL(constrainFieldArr, args, isChamber, true));
                        exceptWhere.append(")");
                    }

                }

            }
            if (StringUtils.isNotEmpty(selectRow) && StringUtils.isNotEmpty(selectTable)) {
                sb.append("SELECT ").append(selectRow).append(" FROM ").append(selectTable).append(" WHERE 1=1 ")
                  .append(selectWhere.toString());
                if (exceptWhere != null && exceptWhere.length() > 0) {
                    sb.append(exceptWhere.append(")").toString().replaceFirst("OR", "AND("));
                }
            }
            return sb.toString();

        }

        /**
         *  Special!! 为了operator panel 与 Lot query 统一， 以前的operator panel 的查询将与lot query 合并
         *  这里做一次特殊操作。如果发生修改请连同 operator panel 一并测试
         *  是否需要添加设备过滤 这里是为了给operator panel 的running 做的, lot query 不需要根据设备筛选
         * @param lotQueryParameterDto 这里只有查询run lot 的逻辑
         */
        private void setConditionsForOperatorPanel(LotQueryParameterDto lotQueryParameterDto,StringBuilder sql, List<Object> args){
            if(lotQueryParameterDto==null||sql==null||args==null){
                return;
            }
            if(lotQueryParameterDto.getOperatorPanelParam()==null){
                return;
            }
            LotQueryParameterDto.OperatorPanelParam operatorPanelParam= lotQueryParameterDto.getOperatorPanelParam();
            if(operatorPanelParam.getEqptRrn()!=null&&operatorPanelParam.getEqptRrn()>0){
                // 务必保证以下条件
                sql.append( "  AND EXISTS(SELECT 1 FROM JOB JB WHERE L.JOB_RRN = JB.JOB_RRN AND JB.EQPT_RRN=?) " );
                args.add(operatorPanelParam.getEqptRrn());
            }
            if(CollectionUtils.isNotEmpty(operatorPanelParam.getEqptGroupRrns())){
                List<Long> entityGroupsRrns =  operatorPanelParam.getEqptGroupRrns();
                String select =  entityGroupsRrns.stream().map(e->"?").collect(Collectors.joining(","));
                args.addAll(entityGroupsRrns);
                sql.append(" AND EXISTS (SELECT 1 FROM (SELECT T.LOT_ID, PROCESS_RRN, PROCESS_VERSION, ROUTE_RRN, ");
                sql.append(" OPERATION_RRN, REGEXP_SUBSTR(T.EQUIPMENT_GROUP_RRNS, '[^,]+', 1,LEVEL)");
                sql.append(" EQUIPMENT_GROUP_RRN FROM (SELECT L.LOT_ID, PSA.EQUIPMENT_GROUP_RRNS,");
                sql.append(" PSA.PROCESS_RRN, PSA.PROCESS_VERSION, PSA.ROUTE_RRN, PSA.OPERATION_RRN, ");
                sql.append(" ROWNUM NUM FROM PROCESS_SPEC_ITEM_ACTIVE PSA, LOT L WHERE PSA.PROCESS_RRN = ");
                sql.append(" L.PROCESS_RRN AND PSA.PROCESS_VERSION = L.PROCESS_VERSION AND PSA.OPERATION_RRN = ");
                sql.append(" L.OPERATION_RRN AND PSA.ROUTE_RRN = REGEXP_SUBSTR( L.PROCESS_STEP_VERSION, ");
                sql.append(" '[^,]+', INSTR(L.PROCESS_STEP_VERSION,'|',1,1)+1,1)) T CONNECT BY LEVEL <= ");
                sql.append(" REGEXP_COUNT(T.EQUIPMENT_GROUP_RRNS, '[^,]+') AND PRIOR NUM = NUM AND PRIOR ");
                sql.append(" DBMS_RANDOM.VALUE() IS NOT NULL) T WHERE EQUIPMENT_GROUP_RRN IN (" + select + ")");
                sql.append(" AND L.PROCESS_RRN = T.PROCESS_RRN AND L.PROCESS_VERSION = T.PROCESS_VERSION ");
                sql.append(" AND L.OPERATION_RRN = T.OPERATION_RRN  AND T.ROUTE_RRN = REGEXP_SUBSTR ");
                sql.append(" (L.PROCESS_STEP_VERSION, '[^,]+', INSTR(L.PROCESS_STEP_VERSION,'|',1,1 )+1,1)) ");
            }
            //移除runcard hold
            if(sql.indexOf("'"+LotStatus.RUNCARD_HOLD+"',")!=-1){
                sql.replace(sql.indexOf("'"+LotStatus.RUNCARD_HOLD+"',"),sql.indexOf("'"+LotStatus.RUNCARD_HOLD+"',")+("'"+LotStatus.RUNCARD_HOLD+"',").length(),"");
                args.remove(LotStatus.RUNCARD_HOLD);
            }
        }

        private String getEquipmentGroupFilterSQL(String[] constrainFieldArr, List args, boolean isChamber,
                                                  boolean except) {
            String condition = except ? "AND" : "OR";
            String subWhere = "";
            StringBuilder sb = new StringBuilder(" EXISTS( SELECT 1 FROM ");
            if (isChamber) {
                sb.append(" (SELECT ELOG_SHEET_RRN, REGEXP_SUBSTR( H.EQUIPMENT_GROUP_ID,'[^,]+',1,LEVEL) ");
                sb.append(" EQUIPMENT_GROUP_ID FROM (SELECT ELOG_SHEET_RRN, EQUIPMENT_GROUP_ID, ROWNUM NUM ");
                sb.append(
                        " FROM ELOG_SHEET_CHAMBER) H CONNECT BY LEVEL <= REGEXP_COUNT ( H.EQUIPMENT_GROUP_ID, '[^,]+' ) ");
                sb.append(" AND PRIOR NUM = NUM AND PRIOR DBMS_RANDOM.VALUE() IS NOT NULL) H1 WHERE  ");
                sb.append(" H1.ELOG_SHEET_RRN = T.ELOG_SHEET_RRN AND ( ");
                for (String eqpGroup : constrainFieldArr) {
                    if (StringUtils.isEmpty(eqpGroup)) {
                        continue;
                    }
                    subWhere += " H1.EQUIPMENT_GROUP_ID LIKE ? " + condition;
                    args.add(MiscUtils.parseToFuzzySQL(eqpGroup));
                }
            } else {
                sb.append("(SELECT EQUIPMENT_RUN_RRN, REGEXP_SUBSTR( H.EQUIPMENT_GROUP_ID,'[^,]+',1,LEVEL) ");
                sb.append(" EQUIPMENT_GROUP_ID FROM (select EQUIPMENT_RUN_RRN, EQUIPMENT_GROUP_ID,ROWNUM NUM ");
                sb.append(
                        " FROM EQUIPMENT_RUN_HISTORY) H CONNECT BY LEVEL <= REGEXP_COUNT (H.EQUIPMENT_GROUP_ID,'[^,]+') ");
                sb.append(" AND PRIOR NUM = NUM AND PRIOR DBMS_RANDOM.VALUE() IS NOT NULL) H1 WHERE ");
                sb.append(" H1.EQUIPMENT_RUN_RRN = T.EQUIPMENT_RUN_RRN AND ( ");
                for (String eqpGroup : constrainFieldArr) {
                    if (StringUtils.isEmpty(eqpGroup)) {
                        continue;
                    }
                    subWhere += " H1.EQUIPMENT_GROUP_ID LIKE ? " + condition;
                    args.add(MiscUtils.parseToFuzzySQL(eqpGroup));
                }
            }
            sb.append(StringUtils.substringBeforeLast(subWhere, condition));
            sb.append("))");

            return sb.toString();
        }

        class QueryLotInfoProp {
            List<Object> args;

            private StringBuffer sqlBuffer;

            public StringBuffer getSqlBuffer() {
                return sqlBuffer;
            }

            public void setSqlBuffer(StringBuffer sqlBuffer) {
                this.sqlBuffer = sqlBuffer;
            }

            public List<Object> getArgs() {
                return args;
            }

            public void setArgs(List<Object> args) {
                this.args = args;
            }

        }

    }