package jnpf.limsService.impl; import jnpf.lims.api.model.TestWorkItemSnapshotBatch; import jnpf.lims.api.model.TestWorkItemSnapshot; import jnpf.lims.api.model.TestWorkItemSnapshotProperty; import jnpf.lims.api.model.TestWorkItemSnapshotRequest; import jnpf.limsEntity.JianyanStatus; import jnpf.limsEntity.LimsJianyanXiangEntity; import jnpf.limsMapper.LimsJianyanXiangMapper; import jnpf.limsService.LimsTestWorkItemSnapshotService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @Service public class LimsTestWorkItemSnapshotServiceImpl implements LimsTestWorkItemSnapshotService { static final String TEST_BASIS = "test.basis"; private static final String LEGACY_INSPECTION_BASIS = "inspection.basis"; static final String SAMPLE_NAME = "sample.name"; static final String SAMPLE_BATCH_NO = "sample.batch_no"; static final String SAMPLE_PRODUCTION_DATE = "sample.production_date"; static final String QUALITY_STANDARD_SOURCE = "quality_standard.source"; static final String SAMPLE_SPECIFICATION = "sample.specification"; static final String TEST_TYPE = "test.type"; private static final String LEGACY_INSPECTION_TYPE = "inspection.type"; private static final String LIMS_TASK = "LIMS_TASK"; private static final String TEXT = "TEXT"; private static final String DATE = "DATE"; private static final List ALLOWED_STATUSES = Arrays.asList( JianyanStatus.PENDING_TEST.getCode(), JianyanStatus.AUDIT_REJECTED.getCode(), JianyanStatus.CANCELLED.getCode()); private final TaskLookup taskLookup; @Autowired public LimsTestWorkItemSnapshotServiceImpl(LimsJianyanXiangMapper mapper) { this(mapper::selectSnapshotTasks); } LimsTestWorkItemSnapshotServiceImpl(TaskLookup taskLookup) { this.taskLookup = taskLookup; } @Override public TestWorkItemSnapshotBatch resolve(TestWorkItemSnapshotRequest request, String tenantId, String userId) { List itemIds = requestedItemIds(request); List properties = requestedProperties(request); Map tasks = findTasks(tenantId, itemIds); TestWorkItemSnapshotBatch batch = new TestWorkItemSnapshotBatch(); for (String itemId : itemIds) { LimsJianyanXiangEntity task = tasks.get(itemId); TestWorkItemSnapshot item = item(itemId, task); boolean readable = false; if (task == null) { reject(item, "NOT_FOUND", "检验项不存在或无权访问"); } else if (isDeleted(task)) { reject(item, "DELETED", "检验项已删除"); } else if (!ALLOWED_STATUSES.contains(task.getJianyanZhuangtai())) { reject(item, "STATE_NOT_ALLOWED", "检验项当前状态不允许读取任务快照"); } else if (!isResponsible(task, userId)) { reject(item, "FORBIDDEN", "当前用户不是检验项负责人"); } else if (!StringUtils.hasText(task.getQingyandanId())) { reject(item, "TEST_REQUEST_INVALID", "检验项缺少请验单身份"); } else if (!hasUniqueTestDefinitionReference(task)) { reject(item, "TEST_DEFINITION_INVALID", "检验项缺少唯一检验项目关联"); } else { item.setTestRequestId(task.getQingyandanId().trim()); applyTestDefinitionReference(item, task); item.setOutcomeCode("SUCCESS"); readable = true; } addProperties(item, readable ? task : null, properties, readable); batch.getItems().add(item); } return batch; } private Map findTasks(String tenantId, List itemIds) { if (!StringUtils.hasText(tenantId) || itemIds.isEmpty()) { return Collections.emptyMap(); } Map tasks = new LinkedHashMap<>(); for (LimsJianyanXiangEntity task : taskLookup.find(tenantId, itemIds)) { if (task != null && StringUtils.hasText(task.getId()) && tenantId.equals(task.getTenantId())) { tasks.put(task.getId(), task); } } return tasks; } private static List requestedItemIds(TestWorkItemSnapshotRequest request) { if (request == null || request.getTestWorkItemIds() == null) { return Collections.emptyList(); } LinkedHashSet ids = new LinkedHashSet<>(); for (String id : request.getTestWorkItemIds()) { if (StringUtils.hasText(id)) { ids.add(id.trim()); } } return new ArrayList<>(ids); } private static List requestedProperties(TestWorkItemSnapshotRequest request) { return request == null || request.getProperties() == null ? Collections.emptyList() : request.getProperties(); } private static TestWorkItemSnapshot item(String itemId, LimsJianyanXiangEntity task) { TestWorkItemSnapshot item = new TestWorkItemSnapshot(); item.setTestWorkItemId(itemId); item.setTaskStatus(task == null ? null : task.getJianyanZhuangtai()); return item; } private static boolean hasUniqueTestDefinitionReference(LimsJianyanXiangEntity task) { return StringUtils.hasText(task.getTestDefinitionId()) && StringUtils.hasText(task.getJianyanXiangmuBianma()) && StringUtils.hasText(task.getJianyanXiangmuMingcheng()) && Long.valueOf(1L).equals(task.getTestDefinitionMatchCount()); } private static void applyTestDefinitionReference(TestWorkItemSnapshot item, LimsJianyanXiangEntity task) { item.setTestDefinitionId(task.getTestDefinitionId().trim()); item.setTestDefinitionCode(task.getJianyanXiangmuBianma().trim()); item.setTestDefinitionName(task.getJianyanXiangmuMingcheng().trim()); } private static void addProperties(TestWorkItemSnapshot item, LimsJianyanXiangEntity task, List requestedProperties, boolean readable) { for (String property : requestedProperties) { TestWorkItemSnapshotProperty result = new TestWorkItemSnapshotProperty(); result.setProperty(property); PropertySpec spec = propertySpec(property); if (spec == null) { result.setOutcomeCode("UNSUPPORTED_PROPERTY"); result.setReason("未支持的 LIMS_TASK property:" + property); } else { result.setDataType(spec.dataType); result.setSource(LIMS_TASK); result.setSourceRef(item.getTestWorkItemId()); if (!readable) { result.setOutcomeCode("NOT_AVAILABLE"); result.setReason("检验项任务快照不可读取"); } else if (!StringUtils.hasText(spec.value(task))) { result.setOutcomeCode("MISSING"); result.setReason("检验任务快照中缺少" + spec.label); } else { result.setValue(spec.value(task)); result.setOutcomeCode("SUCCESS"); } } item.getProperties().add(result); } } private static PropertySpec propertySpec(String property) { if (TEST_BASIS.equals(property) || LEGACY_INSPECTION_BASIS.equals(property)) { return new PropertySpec(TEXT, "检验依据", LimsJianyanXiangEntity::getBiaozhunGuiding); } if (SAMPLE_NAME.equals(property)) return new PropertySpec(TEXT, "供试品名称", LimsJianyanXiangEntity::getChanpinMingcheng); if (SAMPLE_BATCH_NO.equals(property)) return new PropertySpec(TEXT, "批号", LimsJianyanXiangEntity::getPihao); if (SAMPLE_PRODUCTION_DATE.equals(property)) return new PropertySpec(DATE, "生产日期", task -> formatDate(task.getShengchanRiqi())); if (QUALITY_STANDARD_SOURCE.equals(property)) return new PropertySpec(TEXT, "质量标准来源", LimsJianyanXiangEntity::getQualityStandardSource); if (SAMPLE_SPECIFICATION.equals(property)) return new PropertySpec(TEXT, "规格/浓度", LimsJianyanXiangEntity::getGuige); if (TEST_TYPE.equals(property) || LEGACY_INSPECTION_TYPE.equals(property)) { return new PropertySpec(TEXT, "检验类型", LimsJianyanXiangEntity::getJianyanLeixing); } return null; } private static String formatDate(java.util.Date value) { if (value == null) return null; return new java.text.SimpleDateFormat("yyyy-MM-dd").format(value); } private interface PropertyValue { String value(LimsJianyanXiangEntity task); } private static final class PropertySpec { private final String dataType; private final String label; private final PropertyValue value; private PropertySpec(String dataType, String label, PropertyValue value) { this.dataType = dataType; this.label = label; this.value = value; } private String value(LimsJianyanXiangEntity task) { return value.value(task); } } private static boolean isDeleted(LimsJianyanXiangEntity task) { return task.getDeleteMark() != null && task.getDeleteMark() == 1; } private static boolean isResponsible(LimsJianyanXiangEntity task, String userId) { if (!StringUtils.hasText(userId)) { return false; } String responsible = "yes".equalsIgnoreCase(task.getShifouWaijian()) ? task.getWaijianLururen() : task.getJianchaRen(); return userId.equals(responsible); } private static void reject(TestWorkItemSnapshot item, String code, String reason) { item.setOutcomeCode(code); item.setReason(reason); } @FunctionalInterface interface TaskLookup { List find(String tenantId, List ids); } }