重构逻辑:试剂公式可用变量逻辑

feature-wangxilei-dev
wxl 6 days ago
parent 2022c1612e
commit 798281fd17
  1. 5
      lab-service/lab-lims/pom.xml
  2. 35
      lab-service/lab-lims/src/main/java/org/springblade/lims/controller/ReagentFormulaController.java
  3. 8
      lab-service/lab-lims/src/main/java/org/springblade/lims/service/IOriginalRecordTemplateService.java
  4. 9
      lab-service/lab-lims/src/main/java/org/springblade/lims/service/ITemplateFieldService.java
  5. 8
      lab-service/lab-lims/src/main/java/org/springblade/lims/service/impl/OriginalRecordTemplateServiceImpl.java
  6. 17
      lab-service/lab-lims/src/main/java/org/springblade/lims/service/impl/TemplateFieldServiceImpl.java
  7. 32
      lab-service/lab-lims/src/test/java/org/springblade/lims/AssignRuleControllerTest.java
  8. 140
      lab-service/lab-lims/src/test/java/org/springblade/lims/controller/ReagentFormulaControllerTest.java

@ -271,6 +271,11 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
</project>

@ -15,10 +15,12 @@ import org.springblade.lims.entry.ExamineItem;
import org.springblade.lims.entry.Reagent;
import org.springblade.lims.entry.ReagentFormula;
import org.springblade.lims.entry.TemplateField;
import org.springblade.lims.entry.OriginalRecordTemplate;
import org.springblade.lims.service.IExamineItemService;
import org.springblade.lims.service.IReagentFormulaService;
import org.springblade.lims.service.IReagentService;
import org.springblade.lims.service.ITemplateFieldService;
import org.springblade.lims.service.IOriginalRecordTemplateService;
import org.springblade.lims.utils.FormulaValidationTool;
import org.springframework.web.bind.annotation.*;
@ -45,6 +47,7 @@ public class ReagentFormulaController extends BladeController {
private final IReagentService reagentService;
private final IExamineItemService examineItemService;
private final ITemplateFieldService templateFieldService;
private final IOriginalRecordTemplateService originalRecordTemplateService;
/**
* 分页查询
@ -130,22 +133,35 @@ public class ReagentFormulaController extends BladeController {
*/
@GetMapping("/variables")
@ApiOperation(value = "获取可用变量", notes = "根据试剂ID获取公式可用变量")
public R<List<String>> getVariables(@ApiParam(value = "试剂ID") @RequestParam Long reagentId) {
public R<List<Map<String, Object>>> getVariables(@ApiParam(value = "试剂ID") @RequestParam Long reagentId) {
if (reagentId == null) {
return R.data(new ArrayList<>());
}
// 1. 查找所有使用该试剂的检验项(reagentId 为逗号分隔字符串,使用 LIKE 匹配)
LambdaQueryWrapper<ExamineItem> wrapper = new LambdaQueryWrapper<>();
wrapper.like(ExamineItem::getReagentId, reagentId.toString());
List<ExamineItem> items = examineItemService.list(wrapper);
// 2. 从有模板的检验项中收集模板字段
Set<String> variables = new LinkedHashSet<>();
// 2. 从有模板的检验项中收集模板字段(返回 name/type/description 对象格式)
Map<String, Map<String, Object>> variableMap = new LinkedHashMap<>();
boolean hasTemplateFields = false;
for (ExamineItem item : items) {
if (item.getTemplateId() != null) {
List<TemplateField> fields = templateFieldService.getFieldsByTemplateId(item.getTemplateId());
List<OriginalRecordTemplate> templates = originalRecordTemplateService.getByExamineItemId(item.getId());
if (templates != null && !templates.isEmpty()) {
OriginalRecordTemplate template = templates.get(0);
List<TemplateField> fields = templateFieldService.getFieldsByTemplateIdAndType(template.getId(), "number");
if (fields != null && !fields.isEmpty()) {
hasTemplateFields = true;
for (TemplateField field : fields) {
variables.add(field.getFieldName());
String name = field.getFieldName();
if (!variableMap.containsKey(name)) {
Map<String, Object> v = new HashMap<>(3);
v.put("name", name);
v.put("type", field.getFieldType() != null ? field.getFieldType() : "number");
v.put("description", name);
variableMap.put(name, v);
}
}
}
}
@ -158,12 +174,15 @@ public class ReagentFormulaController extends BladeController {
String method = reagent.getResultDeterminationMethod();
List<Map<String, Object>> oldVars = extractVariables(method);
for (Map<String, Object> v : oldVars) {
variables.add((String) v.get("name"));
String name = (String) v.get("name");
if (name != null && !variableMap.containsKey(name)) {
variableMap.put(name, v);
}
}
}
}
return R.data(new ArrayList<>(variables));
return R.data(new ArrayList<>(variableMap.values()));
}
/**

@ -18,4 +18,12 @@ public interface IOriginalRecordTemplateService extends BaseService<OriginalReco
* @return 模板列表 fieldCount
*/
List<Map<String, Object>> listWithFieldCount();
/**
* 根据检测项目ID获取关联的原始记录模板列表
*
* @param examineItemId 检测项目ID
* @return 原始记录模板列表
*/
List<OriginalRecordTemplate> getByExamineItemId(Long examineItemId);
}

@ -21,6 +21,15 @@ public interface ITemplateFieldService extends BaseService<TemplateField> {
*/
List<TemplateField> getFieldsByTemplateId(Long templateId);
/**
* 根据模板ID和字段类型获取字段列表
*
* @param templateId 模板ID为null时查询字段库
* @param fieldType 字段类型"number"
* @return 字段列表
*/
List<TemplateField> getFieldsByTemplateIdAndType(Long templateId, String fieldType);
/**
* 保存字段
*

@ -54,4 +54,12 @@ public class OriginalRecordTemplateServiceImpl extends BaseServiceImpl<OriginalR
}
return result;
}
@Override
public List<OriginalRecordTemplate> getByExamineItemId(Long examineItemId) {
LambdaQueryWrapper<OriginalRecordTemplate> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(OriginalRecordTemplate::getExamineItemId, examineItemId)
.eq(OriginalRecordTemplate::getIsDeleted, 0);
return baseMapper.selectList(queryWrapper);
}
}

@ -43,6 +43,23 @@ public class TemplateFieldServiceImpl extends BaseServiceImpl<TemplateFieldMappe
return baseMapper.selectList(queryWrapper);
}
@Override
public List<TemplateField> getFieldsByTemplateIdAndType(Long templateId, String fieldType) {
if (templateId == null) {
LambdaQueryWrapper<TemplateField> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(TemplateField::getIsDeleted, 0)
.eq(TemplateField::getFieldType, fieldType);
return baseMapper.selectList(queryWrapper);
}
LambdaQueryWrapper<TemplateField> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(TemplateField::getIsDeleted, 0)
.eq(TemplateField::getFieldType, fieldType);
queryWrapper.inSql(TemplateField::getId,
"SELECT m.field_id FROM t_template_field_mapping m WHERE m.template_id = " + templateId + " ORDER BY m.sort_order ASC"
);
return baseMapper.selectList(queryWrapper);
}
@Override
public boolean saveField(TemplateField field) {
return baseMapper.insert(field) > 0;

@ -2,15 +2,20 @@ package org.springblade.lims;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springblade.lims.controller.AssignRuleController;
import org.springblade.lims.entry.AssignRule;
import org.springblade.lims.service.IAssignRuleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springblade.lims.service.IExamineService;
import org.springblade.system.feign.ISysClient;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.util.Collections;
import java.util.HashMap;
@ -23,18 +28,31 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(AssignRuleController.class)
@ExtendWith(MockitoExtension.class)
class AssignRuleControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@MockBean
@Mock
private IAssignRuleService service;
@Mock
private IExamineService examineService;
@Mock
private ISysClient sysClient;
@InjectMocks
private AssignRuleController controller;
@BeforeEach
void setUp() {
objectMapper = new ObjectMapper();
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
@Test
void testInsert() throws Exception {
AssignRule rule = new AssignRule();

@ -0,0 +1,140 @@
package org.springblade.lims.controller;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springblade.lims.entry.ExamineItem;
import org.springblade.lims.entry.OriginalRecordTemplate;
import org.springblade.lims.entry.Reagent;
import org.springblade.lims.entry.TemplateField;
import org.springblade.lims.service.IExamineItemService;
import org.springblade.lims.service.IOriginalRecordTemplateService;
import org.springblade.lims.service.IReagentFormulaService;
import org.springblade.lims.service.IReagentService;
import org.springblade.lims.service.ITemplateFieldService;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.util.Arrays;
import java.util.Collections;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ExtendWith(MockitoExtension.class)
class ReagentFormulaControllerTest {
private MockMvc mockMvc;
@Mock
private IReagentFormulaService reagentFormulaService;
@Mock
private IReagentService reagentService;
@Mock
private IExamineItemService examineItemService;
@Mock
private ITemplateFieldService templateFieldService;
@Mock
private IOriginalRecordTemplateService originalRecordTemplateService;
@InjectMocks
private ReagentFormulaController controller;
@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
@Test
void templatePath_ShouldReturnNumberTypeFieldNames() throws Exception {
ExamineItem item = new ExamineItem();
item.setId(1L);
item.setReagentId("5");
OriginalRecordTemplate template = new OriginalRecordTemplate();
template.setId(10L);
TemplateField field1 = new TemplateField();
field1.setFieldName("OD值");
field1.setFieldType("number");
TemplateField field2 = new TemplateField();
field2.setFieldName("临界值");
field2.setFieldType("number");
when(examineItemService.list(any())).thenReturn(Collections.singletonList(item));
when(originalRecordTemplateService.getByExamineItemId(1L)).thenReturn(Collections.singletonList(template));
when(templateFieldService.getFieldsByTemplateIdAndType(10L, "number"))
.thenReturn(Arrays.asList(field1, field2));
mockMvc.perform(get("/reagentFormula/variables")
.param("reagentId", "5"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isArray())
.andExpect(jsonPath("$.data.length()").value(2))
.andExpect(jsonPath("$.data[0].name").value("OD值"))
.andExpect(jsonPath("$.data[0].type").value("number"))
.andExpect(jsonPath("$.data[1].name").value("临界值"))
.andExpect(jsonPath("$.data[1].type").value("number"));
}
@Test
void fallback_WhenNoTemplateFields_ShouldUseResultDeterminationMethod() throws Exception {
ExamineItem item = new ExamineItem();
item.setId(1L);
item.setReagentId("5");
OriginalRecordTemplate template = new OriginalRecordTemplate();
template.setId(10L);
Reagent reagent = new Reagent();
reagent.setResultDeterminationMethod(
"{\"variables\":[{\"name\":\"OD值\",\"type\":\"number\"},{\"name\":\"临界值\",\"type\":\"number\"}]}"
);
when(examineItemService.list(any())).thenReturn(Collections.singletonList(item));
when(originalRecordTemplateService.getByExamineItemId(1L)).thenReturn(Collections.singletonList(template));
when(templateFieldService.getFieldsByTemplateIdAndType(10L, "number"))
.thenReturn(Collections.emptyList());
when(reagentService.getById(5L)).thenReturn(reagent);
mockMvc.perform(get("/reagentFormula/variables")
.param("reagentId", "5"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isArray())
.andExpect(jsonPath("$.data.length()").value(2))
.andExpect(jsonPath("$.data[0].name").value("OD值"))
.andExpect(jsonPath("$.data[0].type").value("number"))
.andExpect(jsonPath("$.data[1].name").value("临界值"))
.andExpect(jsonPath("$.data[1].type").value("number"));
}
@Test
void nullReagentId_ShouldReturn400() throws Exception {
mockMvc.perform(get("/reagentFormula/variables"))
.andExpect(status().isBadRequest());
}
@Test
void noMatchingItems_ShouldReturnEmptyList() throws Exception {
when(examineItemService.list(any())).thenReturn(Collections.emptyList());
mockMvc.perform(get("/reagentFormula/variables")
.param("reagentId", "999"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isArray())
.andExpect(jsonPath("$.data.length()").value(0));
}
}
Loading…
Cancel
Save