diff --git a/src/main/java/com/yunhai/bschclassmanage/controller/oapi/sch/OapiSchClassController.java b/src/main/java/com/yunhai/bschclassmanage/controller/oapi/sch/OapiSchClassController.java index 1c6f95c..db3993c 100644 --- a/src/main/java/com/yunhai/bschclassmanage/controller/oapi/sch/OapiSchClassController.java +++ b/src/main/java/com/yunhai/bschclassmanage/controller/oapi/sch/OapiSchClassController.java @@ -5,7 +5,10 @@ import com.yunhai.bschclassmanage.Repository.SchInfoRepository; import com.yunhai.bschclassmanage.config.Config; import com.yunhai.bschclassmanage.entity.SchClass; import com.yunhai.bschclassmanage.model.vo.sch.OapiClassVO; +import com.yunhai.bschclassmanage.model.vo.sch.OapiGradeNameVO; import com.yunhai.bschclassmanage.service.IBaseSchsystemGradeService; +import com.yunhai.bschclassmanage.service.IBaseSchsystemService; +import com.yunhai.bschclassmanage.service.ISchBinSchsystemService; import com.yunhai.bschclassmanage.service.ISchClassService; import com.yunhai.bschclassmanage.service.ISchTeacherService; import io.swagger.v3.oas.annotations.Operation; @@ -33,6 +36,10 @@ public class OapiSchClassController { private ISchTeacherService schTeacherService; @Autowired private IBaseSchsystemGradeService baseSchsystemGradeService; + @Autowired + private ISchBinSchsystemService schBinSchsystemService; + @Autowired + private IBaseSchsystemService baseSchsystemService; @GetMapping("getClassInfo") @Operation(summary = "获取班级信息", description = "按班级ID(班级组ID)查询班级信息,含班主任/副班主任ID与姓名;可传 schId 精确到学校") @@ -77,6 +84,53 @@ public class OapiSchClassController { return ResponseEntity.ok(toVOList(classes)); } + @GetMapping("getGradeName") + @Operation(summary = "获取年级名称", description = "按学校ID+入学年份+学段(1小学/2初中/3高中)查询学校年级字典名称(gradeNickname);" + + "年份按当前学年与年级序换算(与班级导入同口径),无匹配学制/年级返回 null,由调用方自行降级") + public ResponseEntity getGradeName(@RequestParam("schId") Integer schId, + @RequestParam("year") Integer year, + @RequestParam(value = "stage", required = false) Integer stage) { + if (schId == null || year == null) { + return ResponseEntity.ok(null); + } + // 学段 → 学制:按学校各学制记录的学段名(小学/初中/高中)匹配;不传 stage 时不限学段 + String stageName = stage == null ? null + : stage == 1 ? "小学" : stage == 2 ? "初中" : stage == 3 ? "高中" : null; + List targetSystems = new ArrayList<>(); + if (stageName == null) { + targetSystems.addAll(schBinSchsystemService.getSchBinSchsystemIds(schId)); + } else { + for (Integer schsystemId : schBinSchsystemService.getSchBinSchsystemIds(schId)) { + try { + String name = baseSchsystemService.getAcademicStageName(schsystemId); + if (name != null && name.contains(stageName)) { + targetSystems.add(schsystemId); + } + } catch (Exception e) { + // 单个学制学段名缺失(学制未找到等)跳过,不影响其余学制 + } + } + } + for (Integer schsystemId : targetSystems) { + // 年级→入学年份(当前学年-年级偏移,与班级导入 getNowYearGradeMap 同口径);再查字典别称 + Map yearMap = baseSchsystemGradeService.getNowYearGradeMap(schId, schsystemId); + if (yearMap == null || yearMap.isEmpty()) { + continue; + } + Map nameMap = baseSchsystemGradeService.getGradeNameMap(schId, schsystemId, null); + for (Map.Entry e : yearMap.entrySet()) { + if (year.equals(e.getValue()) && nameMap.get(e.getKey()) != null) { + OapiGradeNameVO vo = new OapiGradeNameVO(); + vo.setGradeId(e.getKey()); + vo.setGradeName(nameMap.get(e.getKey())); + vo.setYear(year); + return ResponseEntity.ok(vo); + } + } + } + return ResponseEntity.ok(null); + } + /** 批量转 VO:按学校分组后统一回填学校名/年级名/班主任姓名 */ private List toVOList(List classes) { if (classes == null || classes.isEmpty()) { diff --git a/src/main/java/com/yunhai/bschclassmanage/model/tool/SyncClassDTO.java b/src/main/java/com/yunhai/bschclassmanage/model/tool/SyncClassDTO.java index a213444..cbab58e 100644 --- a/src/main/java/com/yunhai/bschclassmanage/model/tool/SyncClassDTO.java +++ b/src/main/java/com/yunhai/bschclassmanage/model/tool/SyncClassDTO.java @@ -32,7 +32,8 @@ public class SyncClassDTO { /** 班号 1..N(=aca_assign_class.sort_order,决定 code 尾号与 sch_class.sort) */ private Integer sort; - /** 分班侧班名(可空;非空时写 cname 别名,name 统一按规则生成 sort+"班") */ + /** 分班侧班名(可空;非空时写 cname 别名,name 统一按规则生成 sort+"班")。 + * 分班侧口径(2026-10-21):仅语义班名(阳光班/苹果班)才传,序号生成的班名(1班/2班)不传,cname 留空 */ private String name; /** 班主任(平台教师 UserTeaSerID,可空)→ first_teacher_id */ diff --git a/src/main/java/com/yunhai/bschclassmanage/model/vo/sch/OapiGradeNameVO.java b/src/main/java/com/yunhai/bschclassmanage/model/vo/sch/OapiGradeNameVO.java new file mode 100644 index 0000000..2d1b517 --- /dev/null +++ b/src/main/java/com/yunhai/bschclassmanage/model/vo/sch/OapiGradeNameVO.java @@ -0,0 +1,20 @@ +package com.yunhai.bschclassmanage.model.vo.sch; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 年级名称 VO(开放接口 getGradeName 返回):学校年级字典名称 + 对应年级编码与入学年份。 + */ +@Data +public class OapiGradeNameVO { + + @Schema(description = "年级编码(K12 年级ID)") + private Integer gradeId; + + @Schema(description = "年级名称(学校年级字典别称,如 小一/一年级/初一)") + private String gradeName; + + @Schema(description = "入学年份") + private Integer year; +} diff --git a/src/test/java/com/yunhai/bschclassmanage/controller/oapi/sch/OapiGetGradeNameTest.java b/src/test/java/com/yunhai/bschclassmanage/controller/oapi/sch/OapiGetGradeNameTest.java new file mode 100644 index 0000000..ba12d4d --- /dev/null +++ b/src/test/java/com/yunhai/bschclassmanage/controller/oapi/sch/OapiGetGradeNameTest.java @@ -0,0 +1,114 @@ +package com.yunhai.bschclassmanage.controller.oapi.sch; + +import com.yunhai.bschclassmanage.model.vo.sch.OapiGradeNameVO; +import com.yunhai.bschclassmanage.service.IBaseSchsystemGradeService; +import com.yunhai.bschclassmanage.service.IBaseSchsystemService; +import com.yunhai.bschclassmanage.service.ISchBinSchsystemService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** getGradeName 开放接口单测:学段→学制匹配、学年反查年级字典名、无匹配返回 null */ +class OapiGetGradeNameTest { + + private OapiSchClassController controller; + private ISchBinSchsystemService schBinSchsystemService; + private IBaseSchsystemService baseSchsystemService; + private IBaseSchsystemGradeService baseSchsystemGradeService; + + @BeforeEach + void setUp() { + controller = new OapiSchClassController(); + schBinSchsystemService = Mockito.mock(ISchBinSchsystemService.class); + baseSchsystemService = Mockito.mock(IBaseSchsystemService.class); + baseSchsystemGradeService = Mockito.mock(IBaseSchsystemGradeService.class); + ReflectionTestUtils.setField(controller, "schClassRepository", + Mockito.mock(com.yunhai.bschclassmanage.Repository.SchClassRepository.class)); + ReflectionTestUtils.setField(controller, "schInfoRepository", + Mockito.mock(com.yunhai.bschclassmanage.Repository.SchInfoRepository.class)); + ReflectionTestUtils.setField(controller, "schClassService", + Mockito.mock(com.yunhai.bschclassmanage.service.ISchClassService.class)); + ReflectionTestUtils.setField(controller, "schTeacherService", + Mockito.mock(com.yunhai.bschclassmanage.service.ISchTeacherService.class)); + ReflectionTestUtils.setField(controller, "schBinSchsystemService", schBinSchsystemService); + ReflectionTestUtils.setField(controller, "baseSchsystemService", baseSchsystemService); + ReflectionTestUtils.setField(controller, "baseSchsystemGradeService", baseSchsystemGradeService); + + // 云海小学:双学段(小学+初中),各自年级字典与入学年份映射 + when(schBinSchsystemService.getSchBinSchsystemIds(27)).thenReturn(Arrays.asList(5, 9)); + when(baseSchsystemService.getAcademicStageName(5)).thenReturn("小学"); + when(baseSchsystemService.getAcademicStageName(9)).thenReturn("初中"); + + Map primaryYears = new LinkedHashMap<>(); + primaryYears.put(1, 2026); + primaryYears.put(2, 2025); + primaryYears.put(3, 2024); + when(baseSchsystemGradeService.getNowYearGradeMap(27, 5)).thenReturn(primaryYears); + Map primaryNames = new HashMap<>(); + primaryNames.put(1, "小一"); + primaryNames.put(2, "小二"); + primaryNames.put(3, "小三"); + when(baseSchsystemGradeService.getGradeNameMap(27, 5, null)).thenReturn(primaryNames); + + Map juniorYears = new LinkedHashMap<>(); + juniorYears.put(7, 2026); + juniorYears.put(8, 2025); + when(baseSchsystemGradeService.getNowYearGradeMap(27, 9)).thenReturn(juniorYears); + Map juniorNames = new HashMap<>(); + juniorNames.put(7, "初一"); + juniorNames.put(8, "初二"); + when(baseSchsystemGradeService.getGradeNameMap(27, 9, null)).thenReturn(juniorNames); + } + + @Test + void resolvesGradeNameByStageAndYear() { + // 小学 2026 级入学 → 小一(学校字典真实名称) + OapiGradeNameVO vo = controller.getGradeName(27, 2026, 1).getBody(); + assertEquals(1, vo.getGradeId()); + assertEquals("小一", vo.getGradeName()); + assertEquals(2026, vo.getYear()); + + // 初中 2026 → 初一(同校多学段按 stage 区分) + assertEquals("初一", controller.getGradeName(27, 2026, 2).getBody().getGradeName()); + + // 低年级已升学:2024 入学的小学年级 → 小三 + assertEquals("小三", controller.getGradeName(27, 2024, 1).getBody().getGradeName()); + } + + @Test + void returnsNullWhenNoMatch() { + // 年份无对应年级(超出字典范围) + assertNull(controller.getGradeName(27, 2020, 1).getBody()); + // 学段在学校未开设(高中不存在) + assertNull(controller.getGradeName(27, 2026, 3).getBody()); + // 参数缺失 + assertNull(controller.getGradeName(null, 2026, 1).getBody()); + assertNull(controller.getGradeName(27, null, 1).getBody()); + } + + @Test + void skipsBrokenSchsystemAndContinues() { + // 单个学制学段名缺失(学制未找到等)跳过,不影响其余学制匹配 + when(baseSchsystemService.getAcademicStageName(5)).thenThrow(new RuntimeException("学制未找到!")); + assertEquals("初一", controller.getGradeName(27, 2026, 2).getBody().getGradeName()); + assertNull(controller.getGradeName(27, 2026, 1).getBody()); + } + + @Test + void emptyYearMapReturnsNull() { + when(baseSchsystemGradeService.getNowYearGradeMap(eq(27), anyInt())).thenReturn(new HashMap<>()); + assertNull(controller.getGradeName(27, 2026, 1).getBody()); + } +}