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

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> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId> <artifactId>maven-antrun-plugin</artifactId>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

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

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