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;
        }

    }

}