package jnpf.limsService.impl;
|
|
import jnpf.base.UserInfo;
|
import jnpf.exception.DataException;
|
import jnpf.limsEntity.JianyanStatus;
|
import jnpf.limsEntity.LimsWendingxingFenxiBatchParam;
|
import jnpf.limsEntity.LimsWendingxingFenxiCompletenessRecordVo;
|
import jnpf.limsEntity.LimsWendingxingFenxiCompletenessVo;
|
import jnpf.limsEntity.LimsWendingxingFenxiDataVo;
|
import jnpf.limsEntity.LimsWendingxingFenxiExpectedPeriodVo;
|
import jnpf.limsEntity.LimsWendingxingFenxiOptionVo;
|
import jnpf.limsEntity.LimsWendingxingFenxiOptionsVo;
|
import jnpf.limsEntity.LimsWendingxingFenxiParam;
|
import jnpf.limsEntity.LimsWendingxingFenxiRowVo;
|
import jnpf.limsMapper.LimsWendingxingFenxiMapper;
|
import jnpf.limsService.LimsWendingxingFenxiService;
|
import jnpf.limsService.support.LimsWendingxingFenxiSupport;
|
import jnpf.util.UserProvider;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.StringUtils;
|
|
import java.math.BigDecimal;
|
import java.util.ArrayList;
|
import java.util.Comparator;
|
import java.util.Date;
|
import java.util.HashSet;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
|
@Service
|
public class LimsWendingxingFenxiServiceImpl implements LimsWendingxingFenxiService {
|
|
@Autowired
|
private LimsWendingxingFenxiMapper fenxiMapper;
|
|
@Override
|
public LimsWendingxingFenxiOptionsVo listOptions(LimsWendingxingFenxiParam source) {
|
LimsWendingxingFenxiParam param = normalize(source);
|
String tenantId = currentTenantId();
|
LimsWendingxingFenxiOptionsVo result = new LimsWendingxingFenxiOptionsVo();
|
result.setFenleiList(fenxiMapper.selectCategories(tenantId));
|
if (!StringUtils.hasText(param.getFenleiBianma())) {
|
return result;
|
}
|
result.setYangpinList(fenxiMapper.selectProducts(tenantId, param.getFenleiBianma()));
|
if (!StringUtils.hasText(param.getYangpinId())) {
|
return result;
|
}
|
result.setXiangmuList(fenxiMapper.selectItems(
|
tenantId, param.getFenleiBianma(), param.getYangpinId()));
|
if (param.getXiangmuIds().isEmpty()) {
|
return result;
|
}
|
result.setJihuaList(fenxiMapper.selectPlans(
|
tenantId, param.getYangpinId(), param.getXiangmuIds()));
|
result.setPihaoList(fenxiMapper.selectBatches(
|
tenantId, param.getYangpinId(), param.getXiangmuIds(), param.getJihuaIds()));
|
return result;
|
}
|
|
@Override
|
public LimsWendingxingFenxiDataVo listData(LimsWendingxingFenxiParam source) {
|
validateRawFilters(source);
|
LimsWendingxingFenxiParam param = normalize(source);
|
validateRequired(param);
|
String tenantId = currentTenantId();
|
validateAuthorizedOptions(tenantId, param);
|
|
List<LimsWendingxingFenxiRowVo> rows = fenxiMapper.selectRows(tenantId, param);
|
for (LimsWendingxingFenxiRowVo row : rows) {
|
normalizeRow(row);
|
}
|
rows.sort(rowComparator());
|
|
LimsWendingxingFenxiDataVo result = new LimsWendingxingFenxiDataVo();
|
result.setRows(rows);
|
List<LimsWendingxingFenxiCompletenessRecordVo> completenessRecords =
|
fenxiMapper.selectCompleteness(tenantId, param);
|
result.setCompleteness(buildCompleteness(completenessRecords));
|
result.setExpectedPeriods(buildExpectedPeriods(completenessRecords));
|
return result;
|
}
|
|
private void validateRawFilters(LimsWendingxingFenxiParam source) {
|
if (source == null) {
|
return;
|
}
|
validateRawIds(source.getXiangmuIds(), "检验项目");
|
validateRawIds(source.getJihuaIds(), "稳定性考察编号");
|
Set<String> batchKeys = new HashSet<>();
|
if (source.getPihaoKeys() == null) {
|
return;
|
}
|
for (LimsWendingxingFenxiBatchParam batch : source.getPihaoKeys()) {
|
if (batch == null || !StringUtils.hasText(batch.getJihuaId())
|
|| !StringUtils.hasText(batch.getPihao())) {
|
throw new DataException("批号筛选项不完整");
|
}
|
String key = batch.getJihuaId().trim() + "::" + batch.getPihao().trim();
|
if (!batchKeys.add(key)) {
|
throw new DataException("批号筛选项不能重复");
|
}
|
}
|
}
|
|
private void validateRawIds(List<String> values, String label) {
|
if (values == null) {
|
return;
|
}
|
Set<String> unique = new HashSet<>();
|
for (String value : values) {
|
if (!StringUtils.hasText(value)) {
|
throw new DataException(label + "筛选项不能为空");
|
}
|
if (!unique.add(value.trim())) {
|
throw new DataException(label + "筛选项不能重复");
|
}
|
}
|
}
|
|
private void validateRequired(LimsWendingxingFenxiParam param) {
|
if (!StringUtils.hasText(param.getFenleiBianma())) {
|
throw new DataException("分类不能为空");
|
}
|
if (!StringUtils.hasText(param.getYangpinId())) {
|
throw new DataException("品名不能为空");
|
}
|
if (param.getXiangmuIds().isEmpty()) {
|
throw new DataException("检验项目不能为空");
|
}
|
}
|
|
private void validateAuthorizedOptions(String tenantId, LimsWendingxingFenxiParam param) {
|
requireContains(fenxiMapper.selectCategories(tenantId), param.getFenleiBianma(), "分类");
|
requireContains(fenxiMapper.selectProducts(tenantId, param.getFenleiBianma()), param.getYangpinId(), "品名");
|
requireContainsAll(fenxiMapper.selectItems(
|
tenantId, param.getFenleiBianma(), param.getYangpinId()), param.getXiangmuIds(), "检验项目");
|
|
List<LimsWendingxingFenxiOptionVo> planOptions = fenxiMapper.selectPlans(
|
tenantId, param.getYangpinId(), param.getXiangmuIds());
|
requireContainsAll(planOptions, param.getJihuaIds(), "稳定性考察编号");
|
|
List<LimsWendingxingFenxiOptionVo> batchOptions = fenxiMapper.selectBatches(
|
tenantId, param.getYangpinId(), param.getXiangmuIds(), param.getJihuaIds());
|
Set<String> allowedBatchKeys = optionKeys(batchOptions);
|
for (LimsWendingxingFenxiBatchParam batch : param.getPihaoKeys()) {
|
if (!allowedBatchKeys.contains(batchKey(batch))) {
|
throw new DataException("批号不属于当前筛选范围");
|
}
|
}
|
}
|
|
private void requireContains(List<LimsWendingxingFenxiOptionVo> options,
|
String value, String label) {
|
if (!optionKeys(options).contains(value)) {
|
throw new DataException(label + "不属于当前租户或筛选范围");
|
}
|
}
|
|
private void requireContainsAll(List<LimsWendingxingFenxiOptionVo> options,
|
List<String> values, String label) {
|
Set<String> allowed = optionKeys(options);
|
for (String value : values) {
|
if (!allowed.contains(value)) {
|
throw new DataException(label + "不属于当前租户或筛选范围");
|
}
|
}
|
}
|
|
private Set<String> optionKeys(List<LimsWendingxingFenxiOptionVo> options) {
|
Set<String> result = new HashSet<>();
|
for (LimsWendingxingFenxiOptionVo option : options) {
|
if (StringUtils.hasText(option.getKey())) {
|
result.add(option.getKey());
|
} else if (StringUtils.hasText(option.getId())) {
|
result.add(option.getId());
|
}
|
}
|
return result;
|
}
|
|
private void normalizeRow(LimsWendingxingFenxiRowVo row) {
|
BigDecimal value = LimsWendingxingFenxiSupport.strictDecimal(row.getRawResult());
|
BigDecimal lower = LimsWendingxingFenxiSupport.strictDecimal(row.getXiaxian());
|
BigDecimal upper = LimsWendingxingFenxiSupport.strictDecimal(row.getShangxian());
|
row.setNumericResult(value);
|
row.setXiaxianValue(lower);
|
row.setShangxianValue(upper);
|
try {
|
row.setZhouqiOrder(LimsWendingxingFenxiSupport.periodOrder(
|
new BigDecimal(row.getZhouqi()), row.getZhouqiDanwei()));
|
} catch (RuntimeException ignored) {
|
row.setZhouqiOrder(Double.MAX_VALUE);
|
}
|
row.setExceptionType(LimsWendingxingFenxiSupport.exceptionType(
|
row.getYichangDiaochaLeixing(), row.getJianyanJielun(), value, lower, upper));
|
row.setBatchKey(safe(row.getJihuaId()) + "::" + safe(row.getPihao()));
|
}
|
|
private Comparator<LimsWendingxingFenxiRowVo> rowComparator() {
|
Comparator<String> strings = Comparator.nullsLast(String::compareTo);
|
Comparator<Date> dates = Comparator.nullsLast(Date::compareTo);
|
return Comparator.comparing(LimsWendingxingFenxiRowVo::getXiangmuMingcheng, strings)
|
.thenComparing(LimsWendingxingFenxiRowVo::getXiangmuBianma, strings)
|
.thenComparing(LimsWendingxingFenxiRowVo::getJihuaBianhao, strings)
|
.thenComparing(LimsWendingxingFenxiRowVo::getJihuaId, strings)
|
.thenComparing(LimsWendingxingFenxiRowVo::getPihao, strings)
|
.thenComparing(LimsWendingxingFenxiRowVo::getZhouqiOrder,
|
Comparator.nullsLast(Double::compareTo))
|
.thenComparing(LimsWendingxingFenxiRowVo::getJieguoLuruRiqi, dates)
|
.thenComparing(LimsWendingxingFenxiRowVo::getXiangmuId, strings);
|
}
|
|
private LimsWendingxingFenxiCompletenessVo buildCompleteness(
|
List<LimsWendingxingFenxiCompletenessRecordVo> records) {
|
Map<String, Integer> states = new LinkedHashMap<>();
|
for (LimsWendingxingFenxiCompletenessRecordVo record : records) {
|
int state = record.getJianyanZhuangtai() == null ? 0
|
: JianyanStatus.AUDITED.getCode().equals(record.getJianyanZhuangtai()) ? 2 : 1;
|
states.merge(record.getExpectedKey(), state, Math::max);
|
}
|
LimsWendingxingFenxiCompletenessVo result = new LimsWendingxingFenxiCompletenessVo();
|
result.setExpectedCount(states.size());
|
for (Integer state : states.values()) {
|
if (state == 2) {
|
result.setAuditedCount(result.getAuditedCount() + 1);
|
} else if (state == 1) {
|
result.setPendingCount(result.getPendingCount() + 1);
|
} else {
|
result.setMissingCount(result.getMissingCount() + 1);
|
}
|
}
|
return result;
|
}
|
|
private List<LimsWendingxingFenxiExpectedPeriodVo> buildExpectedPeriods(
|
List<LimsWendingxingFenxiCompletenessRecordVo> records) {
|
Map<String, LimsWendingxingFenxiExpectedPeriodVo> periods = new LinkedHashMap<>();
|
for (LimsWendingxingFenxiCompletenessRecordVo record : records) {
|
String key = safe(record.getXiangmuId()) + "::" + safe(record.getZhouqi())
|
+ "::" + safe(record.getZhouqiDanwei());
|
if (periods.containsKey(key)) {
|
continue;
|
}
|
LimsWendingxingFenxiExpectedPeriodVo period =
|
new LimsWendingxingFenxiExpectedPeriodVo();
|
period.setXiangmuId(record.getXiangmuId());
|
period.setZhouqi(record.getZhouqi());
|
period.setZhouqiDanwei(record.getZhouqiDanwei());
|
try {
|
period.setZhouqiOrder(LimsWendingxingFenxiSupport.periodOrder(
|
new BigDecimal(record.getZhouqi()), record.getZhouqiDanwei()));
|
} catch (RuntimeException ignored) {
|
period.setZhouqiOrder(Double.MAX_VALUE);
|
}
|
periods.put(key, period);
|
}
|
List<LimsWendingxingFenxiExpectedPeriodVo> result =
|
new ArrayList<>(periods.values());
|
result.sort(Comparator.comparing(
|
LimsWendingxingFenxiExpectedPeriodVo::getZhouqiOrder,
|
Comparator.nullsLast(Double::compareTo)));
|
return result;
|
}
|
|
private LimsWendingxingFenxiParam normalize(LimsWendingxingFenxiParam source) {
|
LimsWendingxingFenxiParam result = source == null
|
? new LimsWendingxingFenxiParam() : source;
|
result.setFenleiBianma(trimToNull(result.getFenleiBianma()));
|
result.setYangpinId(trimToNull(result.getYangpinId()));
|
result.setXiangmuIds(LimsWendingxingFenxiSupport.normalizeIds(result.getXiangmuIds()));
|
result.setJihuaIds(LimsWendingxingFenxiSupport.normalizeIds(result.getJihuaIds()));
|
|
Map<String, LimsWendingxingFenxiBatchParam> batches = new LinkedHashMap<>();
|
if (result.getPihaoKeys() != null) {
|
for (LimsWendingxingFenxiBatchParam batch : result.getPihaoKeys()) {
|
if (batch == null) {
|
continue;
|
}
|
batch.setJihuaId(trimToNull(batch.getJihuaId()));
|
batch.setPihao(trimToNull(batch.getPihao()));
|
if (batch.getJihuaId() != null && batch.getPihao() != null) {
|
batches.putIfAbsent(batchKey(batch), batch);
|
}
|
}
|
}
|
result.setPihaoKeys(new ArrayList<>(batches.values()));
|
return result;
|
}
|
|
private String batchKey(LimsWendingxingFenxiBatchParam batch) {
|
return safe(batch.getJihuaId()) + "::" + safe(batch.getPihao());
|
}
|
|
private String safe(String value) {
|
return value == null ? "" : value;
|
}
|
|
private String trimToNull(String value) {
|
return StringUtils.hasText(value) ? value.trim() : null;
|
}
|
|
private String currentTenantId() {
|
UserInfo user = UserProvider.getUser();
|
return user == null || !StringUtils.hasText(user.getTenantId())
|
? "0" : user.getTenantId();
|
}
|
}
|