package com.bs.lithoframe.service.reticle.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bs.lithoframe.common.util.StringPermutations;
import com.bs.lithoframe.service.kpimaintaintable.entity.TMainOvlApply;
import com.bs.lithoframe.service.kpimaintaintable.mapper.TMainOvlApplyMapper;
import com.bs.lithoframe.service.reticle.commom.MarkSizeUtils;
import com.bs.lithoframe.service.reticle.dto.IBOCdsemDboSizeSummaryDTO;
import com.bs.lithoframe.service.reticle.dto.MarkAutoGenerateDTO;
import com.bs.lithoframe.service.reticle.dto.MarkAutoGenerateLayerDTO;
import com.bs.lithoframe.service.reticle.entity.*;
import com.bs.lithoframe.service.reticle.mapper.*;
import com.bs.lithoframe.service.reticle.service.ILfmsIboCdsemDboSizeSummaryService;
import com.bs.lithoframe.service.reticle.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
/**
* <p>
* 服务实现类
* </p>
*
* @author L3150243 PX
* @since 2025-07-07
*/
@Service
public class LfmsIboCdsemDboSizeSummaryServiceImpl extends ServiceImpl<LfmsIboCdsemDboSizeSummaryMapper, LfmsIboCdsemDboSizeSummary> implements ILfmsIboCdsemDboSizeSummaryService {
@Resource
private LfmsIboCdsemDboSizeSummaryMapper iboCdsemDboSizeSummaryMapper;
@Resource
private LfmsIboCdsemDboCdsemSizeMapper iboCdsemDboCdsemSizeMapper;
@Resource
private LfmsIboCdsemDboOvlMapper iboCdsemDboOvlMapper;
@Resource
private TMainOvlApplyMapper ovlApplyMapper;
@Resource
private MarkSizeUtils markSizeUtils;
@Resource
private LfmsDesignRecordMapper designRecordMapper;
@Resource
private LfmsReticleMapper reticleMapper;
@Resource
private LfmsIboCdsemDboCellValueMapper iboCellValueMapper;
/**
* IOB取两部分数据
* IBO mark: 同OVL sheet生成规则,取KPI系统数据。
* CDSEM mark生成时“OVL tree列”“mark size summary列” 信息为reference Prod mark本系统的数据
*/
@Override
public List<IboMarkAutoResultVO> markAutoGenerate(MarkAutoGenerateDTO markAutoGenerateDTO) {
List<IboMarkAutoResultVO> resultList = new ArrayList<>();
// 1. 统一获取参数
Map<String, String> currentMarkSizeParam = markSizeUtils.getMarkSizeParam(markAutoGenerateDTO.getCurrentProject(),
markAutoGenerateDTO.getCurrentProjectId(), markAutoGenerateDTO.getCurrentPart(),
markAutoGenerateDTO.getTypeName(), markAutoGenerateDTO.getMainVersion());
List<String> currentLayerNameList = markAutoGenerateDTO.getReferenceLayers().stream()
.map(MarkAutoGenerateLayerDTO::getCurrentLayer).collect(Collectors.toList());
//查询当前layer的OVL tree信息
LambdaQueryWrapper<LfmsIboCdsemDboOvl> ovlTreeSummaryQueryWrapper = new LambdaQueryWrapper<>();
ovlTreeSummaryQueryWrapper.eq(LfmsIboCdsemDboOvl::getReticleKey, currentMarkSizeParam.get("rKey"))
.eq(LfmsIboCdsemDboOvl::getSubVersion, markAutoGenerateDTO.getSubVersion())
.in(LfmsIboCdsemDboOvl::getLayerName, currentLayerNameList)
.eq(LfmsIboCdsemDboOvl::getOvlType, "OVL");
List<LfmsIboCdsemDboOvl> ovlTreeList = iboCdsemDboOvlMapper.selectList(ovlTreeSummaryQueryWrapper);
//将markTree由‘326A_633A’转换成‘326_633’,用于后续匹配数据
ovlTreeList.forEach(ovlSizeSummary -> ovlSizeSummary.setMarkTree(ovlSizeSummary.getMarkTree().replaceAll("[a-zA-Z]", "")));
//IBO mark: 同OVL sheet生成规则(取KPI)
List<LfmsIboCdsemDboOvl> ibo = ovlTreeList.stream().filter(item -> Objects.equals(item.getOiType(), "IBO"))
.collect(Collectors.toList());
//1.IBO
List<IboMarkAutoResultVO> iboMarkAutoResultVOList = iboSizeSummary(markAutoGenerateDTO, currentMarkSizeParam, ibo);
//CDSEM mark: 获取lfms系统mark size summary和ovl tree 信息
List<LfmsIboCdsemDboOvl> cdsem = ovlTreeList.stream().filter(item -> Objects.equals(item.getOiType(), "CDSEM"))
.collect(Collectors.toList());
//2.cdsem
List<LfmsIboCdsemDboOvl> iboCdsemDboOvlList = cdsemSizeSummary(markAutoGenerateDTO, cdsem);
Map<String,List<LfmsIboCdsemDboOvl>> lfmsIboCdsemDboOvlMap = iboCdsemDboOvlList.stream().collect(Collectors.groupingBy(LfmsIboCdsemDboOvl::getLayerName));
List<LfmsIboCdsemDboOvl> lfmsIboCdsemDboOvlList = this.coverLayerAutoGenerate(markAutoGenerateDTO);
//3.cover
Map<String,List<LfmsIboCdsemDboOvl>> coverCdsemDboOvlMap = lfmsIboCdsemDboOvlList.stream().collect(Collectors.groupingBy(LfmsIboCdsemDboOvl::getLayerName));
IboMarkAutoResultVO vo = new IboMarkAutoResultVO();
for (String currentLayer : currentLayerNameList) {
vo.setLayerName(currentLayer);
if(!CollectionUtils.isEmpty(iboMarkAutoResultVOList)){
for (IboMarkAutoResultVO iboMarkAutoResultVO : iboMarkAutoResultVOList) {
if(iboMarkAutoResultVO.getLayerName().equals(currentLayer)){
vo.setIboTreeSummaryList(iboMarkAutoResultVO.getIboTreeSummaryList());
}
}
}
if(lfmsIboCdsemDboOvlMap.containsKey(currentLayer)){
vo.setCdsemDboOvlList(lfmsIboCdsemDboOvlMap.get(currentLayer));
}
if(coverCdsemDboOvlMap.containsKey(currentLayer)){
vo.setCoverLayerList(coverCdsemDboOvlMap.get(currentLayer));
}
resultList.add(vo) ;
}
return resultList;
}
/**
* IOB取两部分数据
* IBO mark: 同OVL sheet生成规则,取KPI系统数据。
* CDSEM mark生成时“OVL tree列”“mark size summary列” 信息为reference Prod mark本系统的数据
*/
public List<IboMarkAutoResultVO> markAutoGenerate_old(MarkAutoGenerateDTO markAutoGenerateDTO) {
List<IboMarkAutoResultVO> resultList = new ArrayList<>();
Map<String, String> currentMarkSizeParam = markSizeUtils.getMarkSizeParam(markAutoGenerateDTO.getCurrentProject(),
markAutoGenerateDTO.getCurrentProjectId(), markAutoGenerateDTO.getCurrentPart(),
markAutoGenerateDTO.getTypeName(), markAutoGenerateDTO.getMainVersion());
List<String> currentLayerNameList = markAutoGenerateDTO.getReferenceLayers().stream()
.map(MarkAutoGenerateLayerDTO::getCurrentLayer).collect(Collectors.toList());
//查询当前layer的OVL tree信息
LambdaQueryWrapper<LfmsIboCdsemDboOvl> ovlTreeSummaryQueryWrapper = new LambdaQueryWrapper<>();
ovlTreeSummaryQueryWrapper.eq(LfmsIboCdsemDboOvl::getReticleKey, currentMarkSizeParam.get("rKey"))
.eq(LfmsIboCdsemDboOvl::getSubVersion, markAutoGenerateDTO.getSubVersion())
.in(LfmsIboCdsemDboOvl::getLayerName, currentLayerNameList)
.eq(LfmsIboCdsemDboOvl::getOvlType, "OVL");
List<LfmsIboCdsemDboOvl> ovlTreeList = iboCdsemDboOvlMapper.selectList(ovlTreeSummaryQueryWrapper);
//将markTree由‘326A_633A’转换成‘326_633’,用于后续匹配数据
ovlTreeList.forEach(ovlSizeSummary -> ovlSizeSummary.setMarkTree(ovlSizeSummary.getMarkTree().replaceAll("[a-zA-Z]", "")));
//IBO mark: 同OVL sheet生成规则(取KPI)
List<LfmsIboCdsemDboOvl> ibo = ovlTreeList.stream().filter(item -> Objects.equals(item.getOiType(), "IBO"))
.collect(Collectors.toList());
//1.IBO
List<IboMarkAutoResultVO> iboMarkAutoResultVOList = iboSizeSummary(markAutoGenerateDTO, currentMarkSizeParam, ibo);
//CDSEM mark: 获取lfms系统mark size summary和ovl tree 信息
List<LfmsIboCdsemDboOvl> cdsem = ovlTreeList.stream().filter(item -> Objects.equals(item.getOiType(), "CDSEM"))
.collect(Collectors.toList());
//2.cdsem
List<LfmsIboCdsemDboOvl> iboCdsemDboOvlList = cdsemSizeSummary(markAutoGenerateDTO, cdsem);
Map<String,List<LfmsIboCdsemDboOvl>> lfmsIboCdsemDboOvlMap = iboCdsemDboOvlList.stream().collect(Collectors.groupingBy(LfmsIboCdsemDboOvl::getLayerName));
List<LfmsIboCdsemDboOvl> lfmsIboCdsemDboOvlList = this.coverLayerAutoGenerate(markAutoGenerateDTO);
//3.cover
Map<String,List<LfmsIboCdsemDboOvl>> coverCdsemDboOvlMap = lfmsIboCdsemDboOvlList.stream().collect(Collectors.groupingBy(LfmsIboCdsemDboOvl::getLayerName));
IboMarkAutoResultVO vo = new IboMarkAutoResultVO();
for (String currentLayer : currentLayerNameList) {
vo.setLayerName(currentLayer);
if(!CollectionUtils.isEmpty(iboMarkAutoResultVOList)){
for (IboMarkAutoResultVO iboMarkAutoResultVO : iboMarkAutoResultVOList) {
if(iboMarkAutoResultVO.getLayerName().equals(currentLayer)){
vo.setIboTreeSummaryList(iboMarkAutoResultVO.getIboTreeSummaryList());
}
}
}
if(lfmsIboCdsemDboOvlMap.containsKey(currentLayer)){
vo.setCdsemDboOvlList(lfmsIboCdsemDboOvlMap.get(currentLayer));
}
if(coverCdsemDboOvlMap.containsKey(currentLayer)){
vo.setCoverLayerList(coverCdsemDboOvlMap.get(currentLayer));
}
resultList.add(vo) ;
}
return resultList;
}
/**
* 查询出所选的referenceLayer的sizeSummary,过滤出coverLayer,将coverLayer信息新增给对应的currentLayer
* coverLayer定义:LFMS_OVL_OVL_TREE_SUMMARY表OVL_TYPE=‘COVER’,OI_TYPE = ‘Special’
*
* @return highlight信息
*/
private List<LfmsIboCdsemDboOvl> coverLayerAutoGenerate(MarkAutoGenerateDTO markAutoGenerateDTO) {
List<String> referenceLayerNameList = markAutoGenerateDTO.getReferenceLayers().stream().map(MarkAutoGenerateLayerDTO::getReferenceLayer)
.collect(Collectors.toList());
//生成cover layer
String projectId = markSizeUtils.getProjectId(markAutoGenerateDTO.getProjectId());
Map<String, String> currentMarkSizeParam = markSizeUtils.getMarkSizeParam(markAutoGenerateDTO.getCurrentProject(),
markAutoGenerateDTO.getCurrentProjectId(), markAutoGenerateDTO.getCurrentPart(),
markAutoGenerateDTO.getTypeName(), markAutoGenerateDTO.getMainVersion());
//查询LfmsDesignRecord获取最新mainVersion和subVersion,然后拉取LFMS系统的ovlTree信息(coverLayer)
LambdaQueryWrapper<LfmsDesignRecord> designRecordQueryWrapper = new LambdaQueryWrapper<>();
designRecordQueryWrapper.eq(LfmsDesignRecord::getProjAbbr, markAutoGenerateDTO.getProject())
.eq(LfmsDesignRecord::getPart, markAutoGenerateDTO.getPart())
.eq(LfmsDesignRecord::getProjId, projectId)
.eq(LfmsDesignRecord::getProjType, markAutoGenerateDTO.getTypeName())
.eq(LfmsDesignRecord::getDesignTable, "RETICLE")
.orderByDesc(LfmsDesignRecord::getMainVersion);
List<LfmsDesignRecord> designRecords = designRecordMapper.selectList(designRecordQueryWrapper);
String mainVersion = designRecords.get(0).getMainVersion();
String subversion = designRecords.stream().filter(designRecord -> Objects.equals(mainVersion, designRecord.getMainVersion()))
.map(LfmsDesignRecord::getSubVersion).max(String::compareTo).get();
String rKey = String.join("@", markAutoGenerateDTO.getProject(), markAutoGenerateDTO.getPart(), mainVersion, projectId, markAutoGenerateDTO.getTypeName());
LambdaQueryWrapper<LfmsIboCdsemDboOvl> ovlTreeQueryWrapper = new LambdaQueryWrapper<>();
ovlTreeQueryWrapper.eq(LfmsIboCdsemDboOvl::getReticleKey, rKey).eq(LfmsIboCdsemDboOvl::getSubVersion, subversion)
.eq(LfmsIboCdsemDboOvl::getOvlType, "COVER").eq(LfmsIboCdsemDboOvl::getOiType, "Special")
.in(LfmsIboCdsemDboOvl::getLayerName, referenceLayerNameList);
List<LfmsIboCdsemDboOvl> ovlTreeList = iboCdsemDboOvlMapper.selectList(ovlTreeQueryWrapper);
if (CollectionUtils.isEmpty(ovlTreeList)) {
return new ArrayList<>();
}
//匹配到ovlTree信息,然后新增到数据库,其中四个字段使用当前系统的数据:reticleKey、markCountKey、layerName、subVersion
List<LfmsIboCdsemDboOvl> coverLayerList = new ArrayList<>();
for (MarkAutoGenerateLayerDTO referenceLayer : markAutoGenerateDTO.getReferenceLayers()) {
ovlTreeList.stream().filter(ovlTree -> Objects.equals(ovlTree.getLayerName(), referenceLayer.getReferenceLayer()))
.forEach(ovlTree -> {
LfmsIboCdsemDboOvl addOvlTree = new LfmsIboCdsemDboOvl();
BeanUtils.copyProperties(ovlTree, addOvlTree);
addOvlTree.setLayerName(referenceLayer.getCurrentLayer());
addOvlTree.setReticleKey(currentMarkSizeParam.get("rKey"));
addOvlTree.setMarkCountKey(String.join("@", markAutoGenerateDTO.getCurrentProjectId(), markAutoGenerateDTO.getMarkCountVersion()));
addOvlTree.setSubVersion(markAutoGenerateDTO.getSubVersion());
addOvlTree.setNo(new BigDecimal(1));
coverLayerList.add(addOvlTree);
});
}
return coverLayerList;
}
/**
* 判断页面上的If tape out or not = Y的数据中哪些是Dummy Block,GDS NO 去Reticel table 里查找If Dummy block 是Y,自动创建#_normal
* <p>
* 如何判断If tape out or not = Y?
* 查询LFMS_IBO_CDSEM_DBO_CELL_VALUE表里面的if_tape_out值 "IF_TAPE_OUT": "N" if len(df_dummy_value) == 0 else df_dummy_value["IF_TAPE_OUT"].iat[0],
* <p>
* 如何判断Dummy Block?
* 1、查询LFMS_DESIGN_RECORD,找到对应的小版本号或者最新的小版本号subversion
* 2、然后根据subversion匹配LFMS_RETICLE里相应的的数据,找到DUMMY_LAYER==Y的数据,即为Dummy block
*
* @param markAutoGenerateDTO
*/
@Override
public void dummyBlockAutoGenerate(MarkAutoGenerateDTO markAutoGenerateDTO) {
Map<String, String> markSizeParam = markSizeUtils.getMarkSizeParam(markAutoGenerateDTO.getCurrentProject(),
markAutoGenerateDTO.getCurrentProjectId(), markAutoGenerateDTO.getCurrentPart(),
markAutoGenerateDTO.getTypeName(), markAutoGenerateDTO.getMainVersion());
//取subversion,根据subversion查询出LfmsReticle的DUMMY_LAYER信息
String subversion = markAutoGenerateDTO.getSubVersion();
LambdaQueryWrapper<LfmsDesignRecord> designRecordQueryWrapper = new LambdaQueryWrapper<>();
designRecordQueryWrapper.eq(LfmsDesignRecord::getProjAbbr, markAutoGenerateDTO.getCurrentProject()).eq(LfmsDesignRecord::getPart, markAutoGenerateDTO.getCurrentPart())
.eq(LfmsDesignRecord::getProjId, markSizeParam.get("projectId")).eq(LfmsDesignRecord::getProjType, markAutoGenerateDTO.getTypeName())
.eq(LfmsDesignRecord::getMainVersion, markAutoGenerateDTO.getMainVersion()).eq(LfmsDesignRecord::getDesignTable, "RETICLE")
.select(LfmsDesignRecord::getSubVersion)
.orderByDesc(LfmsDesignRecord::getSubVersion);
List<LfmsDesignRecord> designRecords = designRecordMapper.selectList(designRecordQueryWrapper);
//如果没有对应的 subversion, 取最新的小版本号
boolean existSubversion = designRecords.stream().anyMatch(designRecord -> Objects.equals(designRecord.getSubVersion(), markAutoGenerateDTO.getSubVersion()));
if (!existSubversion) {
String reg = "^[1-9][0-9]{7}(_[0-9]{1,2})?$";
subversion = designRecords.stream().filter(designRecord -> designRecord.getSubVersion().matches(reg))
.map(LfmsDesignRecord::getSubVersion).findFirst().get();
}
LambdaQueryWrapper<LfmsReticle> reticleQueryWrapper = new LambdaQueryWrapper<>();
reticleQueryWrapper.eq(LfmsReticle::getSubVersion, subversion).eq(LfmsReticle::getDummyLayer, "Y")
.like(LfmsReticle::getIdx, markSizeParam.get("rKey"));
List<LfmsReticle> lfmsReticles = reticleMapper.selectList(reticleQueryWrapper);
if (CollectionUtils.isEmpty(lfmsReticles)) {
return;
}
// 找到dummy layer
LambdaQueryWrapper<LfmsIboCdsemDboCellValue> cellValueQueryWrapper = new LambdaQueryWrapper<>();
cellValueQueryWrapper.eq(LfmsIboCdsemDboCellValue::getReticleKey, markSizeParam.get("rKey"))
.eq(LfmsIboCdsemDboCellValue::getSubVersion, subversion)
.eq(LfmsIboCdsemDboCellValue::getIfTapeOut, "Y")
.select(LfmsIboCdsemDboCellValue::getLayerName);
List<LfmsIboCdsemDboCellValue> ovlCellValues = iboCellValueMapper.selectList(cellValueQueryWrapper);
if (CollectionUtils.isEmpty(ovlCellValues)) {
return;
}
//LfmsAsmlAlCellValue里的layerName值,示例M2_ARRAY_Dummy
List<String> cellValueLayers = ovlCellValues.stream().map(LfmsIboCdsemDboCellValue::getLayerName).collect(Collectors.toList());
List<String> dummyLayerNames = lfmsReticles.stream().filter(reticle -> cellValueLayers.contains(reticle.getLayerName() + "_Dummy"))
.map(reticle -> reticle.getLayerName() + "_Dummy").collect(Collectors.toList());
if (CollectionUtils.isEmpty(dummyLayerNames)) {
return;
}
//先删除dummySummary信息,再新增
LambdaQueryWrapper<LfmsIboCdsemDboOvl> dummySummaryQueryWrapper = new LambdaQueryWrapper<>();
dummySummaryQueryWrapper.eq(LfmsIboCdsemDboOvl::getReticleKey, markSizeParam.get("rKey"))
.eq(LfmsIboCdsemDboOvl::getSubVersion, subversion)
.eq(LfmsIboCdsemDboOvl::getOvlType, "NORMAL")
.in(LfmsIboCdsemDboOvl::getLayerName, dummyLayerNames);
iboCdsemDboOvlMapper.delete(dummySummaryQueryWrapper);
//新增dummySummary
String finalSubversion = subversion;
List<LfmsIboCdsemDboOvl> addDummySummaries = dummyLayerNames.stream().map(layer -> {
LfmsIboCdsemDboOvl dummySummary = new LfmsIboCdsemDboOvl();
dummySummary.setReticleKey(markSizeParam.get("rKey"));
dummySummary.setMarkCountKey(markSizeParam.get("mKey"));
dummySummary.setLayerName(layer);
dummySummary.setNo(new BigDecimal(1));
dummySummary.setOvlType("NORMAL");
dummySummary.setRefreshed("GREEN");
dummySummary.setSubVersion(finalSubversion);
dummySummary.setCol("");//todo
dummySummary.setRefreshed("green");
return dummySummary;
}).collect(Collectors.toList());
addDummySummaries.forEach(dummySummary -> iboCdsemDboOvlMapper.insert(dummySummary));
}
/**
* 从KPI系统拉取数据,生成IBO 类型的size summary信息
*
* @param markAutoGenerateDTO
* @param markSizeParam
* @return highlight提醒信息
*/
private List<IboMarkAutoResultVO> iboSizeSummary(MarkAutoGenerateDTO markAutoGenerateDTO, Map<String, String> markSizeParam, List<LfmsIboCdsemDboOvl> ovlTreeSummaries) {
List<String> currentLayerNameList = markAutoGenerateDTO.getReferenceLayers().stream()
.map(MarkAutoGenerateLayerDTO::getCurrentLayer).collect(Collectors.toList());
List<IboMarkAutoResultVO> resultList = new ArrayList<>();
//ovl和ibo需要判断有没有ovl tree,只对有ovl tree的数据进行auto mark size
if (CollectionUtils.isEmpty(ovlTreeSummaries)) {
log.warn("本地 tree 为空,不做处理");
return resultList;
}
//从KPI系统拉取alignment数据
LambdaQueryWrapper<TMainOvlApply> ovlQueryWrapper = new LambdaQueryWrapper<>();
String projectIdSql = String.format("PROJECT_ID = " +
"(SELECT ID FROM T_MAIN_TAIN_KPI_APPLY WHERE ARCHIVE = 0 AND PROJECT = '%s' AND lOOP_F = '%s' ORDER BY CREATE_TIME FETCH FIRST 1 ROW ONLY)",
markAutoGenerateDTO.getProject(),
markAutoGenerateDTO.getPart());
List<String> referenceLayerNameList = markAutoGenerateDTO.getReferenceLayers().stream()
.map(MarkAutoGenerateLayerDTO::getReferenceLayer).collect(Collectors.toList());
ovlQueryWrapper.eq(TMainOvlApply::getArchive, 0).in(TMainOvlApply::getLayerName, referenceLayerNameList)
.notLike(TMainOvlApply::getCellName, "CDSEM")
.eq(TMainOvlApply::getMarkType,"ibo-cdsem-dbo")
.ne(TMainOvlApply::getIfNeedRedesign, "Y")
.isNotNull(TMainOvlApply::getQnerutOutMs)
.isNotNull(TMainOvlApply::getQnerutInMs)
.apply(projectIdSql);
List<TMainOvlApply> mainOvlApplies = ovlApplyMapper.selectList(ovlQueryWrapper);
if(CollectionUtils.isEmpty(mainOvlApplies)){
log.warn("本地 kpi ovl 为空,不做处理");
return resultList;
}
//查现有的IBO Size Summary,为了获取NO
LambdaQueryWrapper<LfmsIboCdsemDboSizeSummary> iboSizeSummaryQueryWrapper = new LambdaQueryWrapper<>();
iboSizeSummaryQueryWrapper.eq(LfmsIboCdsemDboSizeSummary::getReticleKey, markSizeParam.get("rKey"))
.eq(LfmsIboCdsemDboSizeSummary::getSubVersion, markAutoGenerateDTO.getSubVersion())
.in(LfmsIboCdsemDboSizeSummary::getLayerName, currentLayerNameList)
.select(LfmsIboCdsemDboSizeSummary::getLayerName, LfmsIboCdsemDboSizeSummary::getNo);
List<LfmsIboCdsemDboSizeSummary> iboSizeSummaries = iboCdsemDboSizeSummaryMapper.selectList(iboSizeSummaryQueryWrapper);
//根据layer name分组,获取组内最新的maskVersion
Map<String, List<TMainOvlApply>> mainOvlMap = mainOvlApplies.stream().filter(f->
!(strToJson(f.getQnerutOutMs()).getInteger("X")>=4) && !(strToJson(f.getQnerutOutMs()).getInteger("Y")>=4)
&& !(strToJson(f.getQnerutInMs()).getDouble("X")>=3) && !(strToJson(f.getQnerutInMs()).getDouble("Y")>=3)
&& !(strToJson(f.getTisMs()).getDouble("X")>=4) && !(strToJson(f.getTisMs()).getDouble("Y")>=4)
).collect(Collectors.groupingBy(
TMainOvlApply::getLayerName,
Collectors.collectingAndThen(Collectors.toList(), list -> {
String newMaskVersion = list.stream().map(TMainOvlApply::getMaskVersion)
.max(String::compareTo).get();
return list.stream().filter(item -> Objects.equals(item.getMaskVersion(), newMaskVersion))
.collect(Collectors.toList());
}
)
));
return assembleSizeSummary(markAutoGenerateDTO.referenceLayers, mainOvlMap, ovlTreeSummaries, iboSizeSummaries);
}
public static JSONObject strToJson(String jsonStr) {
JSONObject jsonObject = JSONObject.parseObject(jsonStr);
return jsonObject;
}
/**
* 从本系统拉取数据,生成CDSEM 类型的size summary信息
*
* @param markAutoGenerateDTO auto接口入参
* @param currentRKey 当前sheet 的reticleKey
* @return highlight提醒信息
*/
private List<LfmsIboCdsemDboOvl> cdsemSizeSummary(MarkAutoGenerateDTO markAutoGenerateDTO,List<LfmsIboCdsemDboOvl> ovlTreeSummaries) {
List<LfmsIboCdsemDboOvl> result = new ArrayList<>();
if (CollectionUtils.isEmpty(ovlTreeSummaries)) {
return result;
}
//查当前layer的CDSEM Size Summary,为了获取NO
List<String> currentLayerNameList = markAutoGenerateDTO.getReferenceLayers().stream()
.map(MarkAutoGenerateLayerDTO::getCurrentLayer)
.collect(Collectors.toList());
List<String> referenceLayerNameList = markAutoGenerateDTO.getReferenceLayers().stream()
.map(MarkAutoGenerateLayerDTO::getReferenceLayer)
.collect(Collectors.toList());
//根据current layer拉取本系统的CDSEM ovl tree信息 和 size summary信息
String projectId = markSizeUtils.getProjectId(markAutoGenerateDTO.getProjectId());
LambdaQueryWrapper<LfmsDesignRecord> designRecordQueryWrapper = new LambdaQueryWrapper<>();
designRecordQueryWrapper.select(LfmsDesignRecord::getMainVersion, LfmsDesignRecord::getSubVersion)
.eq(LfmsDesignRecord::getProjAbbr, markAutoGenerateDTO.getProject())
.eq(LfmsDesignRecord::getProjId, projectId)
.eq(LfmsDesignRecord::getPart, markAutoGenerateDTO.getPart())
.eq(LfmsDesignRecord::getProjType, markAutoGenerateDTO.getTypeName());
//获取最新的mainVersion和subVersion
List<LfmsDesignRecord> lfmsDesignRecords = designRecordMapper.selectList(designRecordQueryWrapper);
String mainVersion = lfmsDesignRecords.stream().map(LfmsDesignRecord::getMainVersion)
.filter(Objects::nonNull).max(String::compareTo).orElse(null);
if (!StringUtils.hasText(mainVersion)) {
log.error("没有获取到refer layer最新mainVersion");
return result;
}
String subVersion = lfmsDesignRecords.stream().filter(item -> Objects.equals(mainVersion, item.getMainVersion()))
.map(LfmsDesignRecord::getSubVersion)
.filter(Objects::nonNull).max(String::compareTo).orElse(null);
if (!StringUtils.hasText(subVersion)) {
log.error("没有获取到refer layer最新subVersion");
return result;
}
String rKey = String.join("@", markAutoGenerateDTO.getProject(), markAutoGenerateDTO.getPart(),
mainVersion, projectId, markAutoGenerateDTO.getTypeName());
// 拉取本系统 的ovl tree信息
LambdaQueryWrapper<LfmsIboCdsemDboOvl> ovlQueryWrapper = new LambdaQueryWrapper<>();
ovlQueryWrapper.eq(LfmsIboCdsemDboOvl::getReticleKey, rKey)
.eq(LfmsIboCdsemDboOvl::getSubVersion, subVersion)
.eq(LfmsIboCdsemDboOvl::getOvlType, "OVL").eq(LfmsIboCdsemDboOvl::getOiType, "CDSEM")
.in(LfmsIboCdsemDboOvl::getLayerName, referenceLayerNameList)
.select(LfmsIboCdsemDboOvl::getLayerName, LfmsIboCdsemDboOvl::getMarkTree);
List<LfmsIboCdsemDboOvl> ovlTreeList = iboCdsemDboOvlMapper.selectList(ovlQueryWrapper);
if (CollectionUtils.isEmpty(ovlTreeList)) {
return result;
}
//current
Map<String, List<LfmsIboCdsemDboOvl>> currentOvlTreeSummarieMap = ovlTreeSummaries.stream().collect(Collectors.groupingBy(LfmsIboCdsemDboOvl::getLayerName));
//reference
Map<String, List<LfmsIboCdsemDboOvl>> ovlTreeSummarieMap = ovlTreeList.stream().collect(Collectors.groupingBy(LfmsIboCdsemDboOvl::getLayerName));
for (String s : currentLayerNameList) {
List<LfmsIboCdsemDboOvl> currentLfmsIboCdsemDboOvlList = currentOvlTreeSummarieMap.get(s);
if(CollectionUtils.isEmpty(currentLfmsIboCdsemDboOvlList)){
continue;
}
List<LfmsIboCdsemDboOvl> referenceLfmsIboCdsemDboOvlList = ovlTreeSummarieMap.get(s);
if(CollectionUtils.isEmpty(referenceLfmsIboCdsemDboOvlList)){
continue;
}
for (LfmsIboCdsemDboOvl lfmsIboCdsemDboOvl : currentLfmsIboCdsemDboOvlList) {
for (LfmsIboCdsemDboOvl iboCdsemDboOvl : referenceLfmsIboCdsemDboOvlList) {
if(lfmsIboCdsemDboOvl.getMarkTree().equals(iboCdsemDboOvl.getMarkTree().replaceAll("[a-zA-Z]", ""))){
lfmsIboCdsemDboOvl.setMarkTree(iboCdsemDboOvl.getMarkTree());
result.add(lfmsIboCdsemDboOvl);
}
}
}
}
return result;
}
private List<IboMarkAutoResultVO> assembleSizeSummary(List<MarkAutoGenerateLayerDTO> referenceLayers, Map<String, List<TMainOvlApply>> mainOvlMap,
List<LfmsIboCdsemDboOvl> ovlTreeSummaries, List<LfmsIboCdsemDboSizeSummary> iboSizeSummaries) {
List<IboMarkAutoResultVO> result = new ArrayList<>();
Map<String, List<LfmsIboCdsemDboOvl>> currentOvlTreeSummarieMap = ovlTreeSummaries.stream().collect(Collectors.groupingBy(LfmsIboCdsemDboOvl::getLayerName));
//优先级排序:BSL mark> backup mark > LM KPI数值
List<LfmsIboCdsemDboSizeSummary> ovlSizeSummaryList = new ArrayList<>();
IboMarkAutoResultVO iboMarkAutoResultVO;
for (int i = 0; i < referenceLayers.size(); i++) {
MarkAutoGenerateLayerDTO referenceLayer = referenceLayers.get(i);
iboMarkAutoResultVO = new IboMarkAutoResultVO();
iboMarkAutoResultVO.setLayerName(referenceLayer.getCurrentLayer());
List<LfmsIboCdsemDboOvl> ovlTreeSummarieList = currentOvlTreeSummarieMap.get(referenceLayer.getReferenceLayer());
if (CollectionUtils.isEmpty(ovlTreeSummarieList)) {
continue;
}
List<TMainOvlApply> tMainOvlApplyList = mainOvlMap.get(referenceLayer.getReferenceLayer());
for (LfmsIboCdsemDboOvl lfmsIboCdsemDboOvl : ovlTreeSummarieList) {
if (StringUtils.isEmpty(lfmsIboCdsemDboOvl.getMarkTree())) {
continue;
}
List<String> markTreeList = StringPermutations.generatePermutations(lfmsIboCdsemDboOvl.getMarkTree());
//首先markTree 完全匹配 //这个地方要修改为匹配
List<TMainOvlApply> matchOvlApplyList = tMainOvlApplyList.stream().filter(f -> markTreeList.contains(f.getOvlTree().replaceAll("[a-zA-Z]", ""))).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(matchOvlApplyList)) {
//完全匹配一条
if (matchOvlApplyList.size() == 1) {
TMainOvlApply minOvlApply = matchOvlApplyList.get(0);
fillSizeSummary(lfmsIboCdsemDboOvl, minOvlApply, iboMarkAutoResultVO,result);
} else {
//走规则
//规则1.[BSL mark]
List<TMainOvlApply> bslMarkOvlApplyList = tMainOvlApplyList.stream().filter(f -> !Objects.isNull(f.getIfBaselineMark()) && f.getIfBaselineMark().equals("Y")).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(bslMarkOvlApplyList) && bslMarkOvlApplyList.size() == 1) {
TMainOvlApply minOvlApply = bslMarkOvlApplyList.get(0);
fillSizeSummary(lfmsIboCdsemDboOvl, minOvlApply, iboMarkAutoResultVO,result);
continue;
}
//规则2.[Backup mark]
bslMarkOvlApplyList = tMainOvlApplyList.stream().filter(f -> !Objects.isNull(f.getIfBackUp()) && f.getIfBackUp().equals("Y")).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(bslMarkOvlApplyList) && bslMarkOvlApplyList.size() == 1) {
TMainOvlApply minOvlApply = bslMarkOvlApplyList.get(0);
fillSizeSummary(lfmsIboCdsemDboOvl, minOvlApply, iboMarkAutoResultVO,result);
continue;
}
//规则3.[LM KPI] 通过对比“ROPI”值, max(X,Y) 越小越好(对于在KPI系统中没有填数值或为NA的,当成KPI最差。) X:5,Y:8 取8 最后min
Optional<TMainOvlApply> optMarkTypeOvlApply = tMainOvlApplyList.stream().min((p1, p2) -> Double.compare(sumStrSymbol(p1.getQnerutOutMs(), "-") + sumStrSymbol(p1.getQnerutInMs(), "-"), sumStrSymbol(p2.getQnerutOutMs(), "-") + sumStrSymbol(p2.getQnerutInMs(), "-")));
TMainOvlApply minOvlApply = optMarkTypeOvlApply.get();
if (!Objects.isNull(minOvlApply)) {
fillSizeSummary(lfmsIboCdsemDboOvl, minOvlApply, iboMarkAutoResultVO,result);
}
}
}
}
}
return result;
}
public static double sumStrSymbol(String str, String symbol) {
String[] strings = str.split(symbol);
return Double.parseDouble(strings[0]) + Double.parseDouble(strings[1]);
}
@Autowired
private LfmsOvlTreeMarkSizeSummaryMapper lfmsOvlTreeMarkSizeSummaryMapper;
private void fillSizeSummary(LfmsIboCdsemDboOvl lfmsIboCdsemDboOvl, TMainOvlApply tMainOvlApply, IboMarkAutoResultVO ovlMarkAutoResultVO,List<IboMarkAutoResultVO> result) {
//1.set treeSummaryList
if(CollectionUtils.isEmpty(ovlMarkAutoResultVO.getIboTreeSummaryList())){
ovlMarkAutoResultVO.setIboTreeSummaryList(new ArrayList<>());
}
TreeSummaryVO treeSummaryVO = new TreeSummaryVO();
treeSummaryVO.setMarkTree(tMainOvlApply.getOvlTree());
LambdaQueryWrapper<LfmsOvlTreeMarkSizeSummary> ovlTreeMarkSizeSummaryWrapper = new LambdaQueryWrapper<>();
ovlTreeMarkSizeSummaryWrapper.eq(LfmsOvlTreeMarkSizeSummary::getMasterId,tMainOvlApply.getId());
ovlTreeMarkSizeSummaryWrapper.eq(LfmsOvlTreeMarkSizeSummary::getArchive,0);
List<LfmsOvlTreeMarkSizeSummary> lfmsOvlTreeMarkSizeSummaryList = lfmsOvlTreeMarkSizeSummaryMapper.selectList(ovlTreeMarkSizeSummaryWrapper);
List<SizeSummaryVO> sizeSummaryList = new ArrayList<>();
if(!CollectionUtils.isEmpty(lfmsOvlTreeMarkSizeSummaryList)){
for (LfmsOvlTreeMarkSizeSummary lfmsOvlTreeMarkSizeSummary : lfmsOvlTreeMarkSizeSummaryList) {
SizeSummaryVO target = new SizeSummaryVO();
// 复制同名属性(忽略不匹配属性)
BeanUtils.copyProperties(lfmsOvlTreeMarkSizeSummary, target);
sizeSummaryList.add(target);
}
}
//2.set sizeSummaryList
treeSummaryVO.setSizeSummaryList(sizeSummaryList);
ovlMarkAutoResultVO.getIboTreeSummaryList().add(treeSummaryVO);
result.add(ovlMarkAutoResultVO);
}
/**
* 组合sizeSummary
*
* @param ovlApply
* @param sizeSummary
*/
private void assemble(TMainOvlApply ovlApply, LfmsIboCdsemDboSizeSummary sizeSummary) {
sizeSummary.setCd(ovlApply.getMarkSizeCd());
sizeSummary.setPitch(ovlApply.getMarkSizePitch());
sizeSummary.setSegType(ovlApply.getMarkSizeSegType());
sizeSummary.setTone(ovlApply.getMarkSizeTone());
sizeSummary.setSizeType(ovlApply.getMarkSizeSizeType());
sizeSummary.setMarkType(ovlApply.getMarkSizeMarkType());
sizeSummary.setStdMarkType(ovlApply.getMarkSizeStdMarkType());
sizeSummary.setOvlSizeType("size");
sizeSummary.setAdditionRemark("'layer':" + ovlApply.getLayerName() + ",'mark':" + ovlApply.getCurrentMarkSize());
}
private String assembleSizeSummary2(List<MarkAutoGenerateLayerDTO> referenceLayers, Map<String, List<Map<String, Object>>> ovlTreeSizeMap,
List<LfmsIboCdsemDboOvl> ovlTreeSummaries, List<LfmsIboCdsemDboCdsemSize> existCdsemSizeSummaries) {
if (CollectionUtils.isEmpty(ovlTreeSummaries)) {
}
List<LfmsIboCdsemDboCdsemSize> sourceSizeSummaryList = new ArrayList<>();
//优先级排序:BSL mark> backup mark > LM KPI数值
List<LfmsIboCdsemDboCdsemSize> addSizeList = new ArrayList<>();
for (int i = 0; i < referenceLayers.size(); i++) {
MarkAutoGenerateLayerDTO referenceLayer = referenceLayers.get(i);
Set<String> markTreeSet = ovlTreeSummaries.stream().filter(ovlTree -> Objects.equals(ovlTree.getLayerName(), referenceLayer.getCurrentLayer()))
.map(LfmsIboCdsemDboOvl::getMarkTree).collect(Collectors.toSet());
//当前layer 的markTree 匹配对应KPI系统的ovlTree,匹配到的数据就做mark size summary新增操作,然后ovl tree数据做修改size type(eg:A、B、C)操作,
Map<String, Object> markTreeMap = ovlTreeSizeMap.get(referenceLayer.getReferenceLayer()).stream()
.filter(ovlTreeSize -> markTreeSet.contains(((String) ovlTreeSize.get("markTreeMap")).replaceAll("[a-zA-Z]", "")))
.findAny().orElse(null);
if (CollectionUtils.isEmpty(markTreeMap)) {
continue;
}
//获取sizeSummary最大NO,后续新增操作,NO依次递增
BigDecimal maxNo = existCdsemSizeSummaries.stream()
.filter(ovlSizeSummary -> Objects.equals(ovlSizeSummary.getLayerName(), referenceLayer.getCurrentLayer()))
.map(LfmsIboCdsemDboCdsemSize::getNo).max(BigDecimal::compareTo)
.orElse(new BigDecimal(0));
LfmsIboCdsemDboCdsemSize sizeSummary = new LfmsIboCdsemDboCdsemSize();
int j = 1;
if (null != markTreeMap.get("sizeSummary")) {
LfmsIboCdsemDboCdsemSize sourceSizeSummary = (LfmsIboCdsemDboCdsemSize) markTreeMap.get("sizeSummary");
BeanUtils.copyProperties(sourceSizeSummary, sizeSummary);
sizeSummary.setLayerName(referenceLayer.getCurrentLayer());
sizeSummary.setReticleKey(ovlTreeSummaries.get(0).getReticleKey());
sizeSummary.setMarkCountKey(ovlTreeSummaries.get(0).getMarkCountKey());
sizeSummary.setSubVersion(ovlTreeSummaries.get(0).getSubVersion());
sizeSummary.setNo(maxNo.add(new BigDecimal(j)));
sizeSummary.setAdditionRemark("'layer':" + referenceLayer.getReferenceLayer() + ",'project':" + sourceSizeSummary.getReticleKey());
sourceSizeSummaryList.add(sizeSummary);
j++;
}
//修改ovlTreeSummary里的markTree
String markTree = (String) markTreeMap.get("markTreeMap");
ovlTreeSummaries.stream().filter(ovlTree -> Objects.equals(ovlTree.getLayerName(), referenceLayer.getCurrentLayer()))
.filter(ovlTree -> Objects.equals(ovlTree.getMarkTree(), markTree.replaceAll("[a-zA-Z]", "")))
.findFirst()
.ifPresent(ovlTree -> ovlTree.setMarkTree(markTree));
}
addSizeList.forEach(markSize -> iboCdsemDboCdsemSizeMapper.insert(markSize));
iboCdsemDboOvlMapper.updateBatch(ovlTreeSummaries);
return "";
}
/**
* 根据T_MAIN_OVL_APPLY表ifBaselineMark字段判断
*
* @param mainOvlList
* @return
*/
private TMainOvlApply ovlBSLMark(List<TMainOvlApply> mainOvlList) {
List<TMainOvlApply> baseLineList = mainOvlList.stream().filter(kpiOvl -> Objects.equals("Y", kpiOvl.getIfBaselineMark())).collect(Collectors.toList());
if (CollectionUtils.isEmpty(baseLineList)) {
return ovlBackUpMark(mainOvlList);
} else if (baseLineList.size() == 1) {
return baseLineList.get(0);
} else {
return ovlBackUpMark(baseLineList);
}
}
/**
* 根据T_MAIN_OVL_APPLY表ifBackUp字段判断
*
* @param mainOvlList
* @return
*/
private TMainOvlApply ovlBackUpMark(List<TMainOvlApply> mainOvlList) {
List<TMainOvlApply> backUpList = mainOvlList.stream().filter(kpiOvl -> Objects.equals("Y", kpiOvl.getIfBackUp())).collect(Collectors.toList());
if (CollectionUtils.isEmpty(backUpList)) {
//todo 从系统对比“ROPI”值 qnerutOutMs/qnerutInMs
return mainOvlList.get(0);
} else if (backUpList.size() == 1) {
return backUpList.get(0);
} else {
//todo 从系统对比“ROPI”值
return backUpList.get(0);
}
}
}
markAutoGenerate将这个关联方法进行优化