Преглед на файлове

feat(report): /types/save 校验 expectedIndicators 为 JSON 字符串数组

Xiaogang Liao преди 3 дни
родител
ревизия
c86baa6945

+ 22 - 0
cfc-backend/src/main/java/com/etotem/cfc/controller/admin/ReportParserAdminController.java

@@ -83,6 +83,10 @@ public class ReportParserAdminController {
         if (type.getDisplayName() == null || type.getDisplayName().isEmpty()) {
             return Result.error("displayName 不能为空");
         }
+        if (type.getExpectedIndicators() != null && !type.getExpectedIndicators().trim().isEmpty()
+                && !isValidJsonStringArray(type.getExpectedIndicators())) {
+            return Result.error("expectedIndicators 必须为 JSON 字符串数组");
+        }
         if (type.getId() != null) {
             type.setUpdatedAt(new Date());
             typeRegistryMapper.updateById(type);
@@ -105,6 +109,24 @@ public class ReportParserAdminController {
         return Result.success();
     }
 
+    /** 校验字符串是否为 JSON 字符串数组,如 ["总分","百分位"] */
+    private boolean isValidJsonStringArray(String json) {
+        try {
+            com.fasterxml.jackson.databind.JsonNode node = objectMapper.readTree(json);
+            if (node == null || !node.isArray()) {
+                return false;
+            }
+            for (com.fasterxml.jackson.databind.JsonNode el : node) {
+                if (!el.isTextual()) {
+                    return false;
+                }
+            }
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
     @PostMapping("/types/toggle")
     public Result<Void> toggleType(@RequestBody Map<String, Object> params) {
         String typeId = (String) params.get("typeId");

+ 68 - 0
cfc-backend/src/test/java/com/etotem/cfc/controller/admin/ReportParserAdminControllerTest.java

@@ -0,0 +1,68 @@
+package com.etotem.cfc.controller.admin;
+
+import com.etotem.cfc.common.Result;
+import com.etotem.cfc.entity.ReportTypeRegistry;
+import com.etotem.cfc.mapper.ReportTypeRegistryMapper;
+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 static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+
+@ExtendWith(MockitoExtension.class)
+class ReportParserAdminControllerTest {
+
+    @Mock
+    private ReportTypeRegistryMapper typeRegistryMapper;
+
+    @InjectMocks
+    private ReportParserAdminController controller;
+
+    private ReportTypeRegistry baseType() {
+        ReportTypeRegistry t = new ReportTypeRegistry();
+        t.setId(1L);
+        t.setTypeId("dan_a1");
+        t.setDisplayName("素质测评A1");
+        return t;
+    }
+
+    @Test
+    void saveType_rejectsInvalidJsonArray() {
+        ReportTypeRegistry t = baseType();
+        t.setExpectedIndicators("not-json");
+
+        Result<Void> r = controller.saveType(t);
+
+        assertEquals(500, r.getCode());
+        assertTrue(r.getMessage().contains("expectedIndicators"));
+        verifyNoInteractions(typeRegistryMapper);
+    }
+
+    @Test
+    void saveType_rejectsJsonArrayWithNonStringElement() {
+        ReportTypeRegistry t = baseType();
+        t.setExpectedIndicators("[1,2,3]");
+
+        Result<Void> r = controller.saveType(t);
+
+        assertEquals(500, r.getCode());
+        verify(typeRegistryMapper, never()).updateById(t);
+    }
+
+    @Test
+    void saveType_acceptsValidJsonArray() {
+        ReportTypeRegistry t = baseType();
+        t.setExpectedIndicators("[\"总分\",\"百分位\"]");
+
+        Result<Void> r = controller.saveType(t);
+
+        assertEquals(200, r.getCode());
+        verify(typeRegistryMapper).updateById(t);
+    }
+}