From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master
---
jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsWendingxingFenxiServiceImpl.java | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 311 insertions(+), 0 deletions(-)
diff --git a/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsWendingxingFenxiServiceImpl.java b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsWendingxingFenxiServiceImpl.java
new file mode 100644
index 0000000..ba8190f
--- /dev/null
+++ b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsWendingxingFenxiServiceImpl.java
@@ -0,0 +1,311 @@
+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();
+ }
+}
--
Gitblit v1.8.0