diff --git a/src/main/java/com/sztzjy/linkCommerce/controller/stu/TeaScoreController.java b/src/main/java/com/sztzjy/linkCommerce/controller/stu/TeaScoreController.java index 08b3ba3..bdcd9d5 100644 --- a/src/main/java/com/sztzjy/linkCommerce/controller/stu/TeaScoreController.java +++ b/src/main/java/com/sztzjy/linkCommerce/controller/stu/TeaScoreController.java @@ -8,6 +8,7 @@ import com.sztzjy.linkCommerce.entity.*; import com.sztzjy.linkCommerce.mapper.SchoolClassMapper; import com.sztzjy.linkCommerce.mapper.StuGradeMapper; import com.sztzjy.linkCommerce.mapper.StuRankMapper; +import com.sztzjy.linkCommerce.mapper.TaskAllocationMapper; import com.sztzjy.linkCommerce.mapper.TeachingClassStudentMapper; import com.sztzjy.linkCommerce.mapper.WeightMapper; import com.sztzjy.linkCommerce.service.ScoreRankService; @@ -22,9 +23,11 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; +import java.math.BigDecimal; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; @@ -44,6 +47,8 @@ public class TeaScoreController { SchoolClassMapper schoolClassMapper; @Autowired TeachingClassStudentMapper teachingClassStudentMapper; + @Autowired + TaskAllocationMapper taskAllocationMapper; @PostMapping("/selectStuRankAndScore") @ApiOperation("查询学生成绩和排名") @@ -68,6 +73,7 @@ public class TeaScoreController { } stuRankExample.setOrderByClause("stu_rank asc"); List stuRankList = stuRankMapper.selectByExample(stuRankExample); + enrichTrainingProgress(stuRankList, classId); PageInfo rankPageInfo = new PageInfo<>(stuRankList); return new ResultEntity<>(HttpStatus.OK, "查询学生成绩和排名成功",rankPageInfo); } @@ -205,13 +211,14 @@ public class TeaScoreController { } stuRankExample.setOrderByClause("stu_rank asc"); List stuRankList = stuRankMapper.selectByExample(stuRankExample); + enrichTrainingProgress(stuRankList, classId); //导出的表名 String title = "学生成绩"; //表中第一行表头字段 - String[] headers = {"学号", "学生姓名", "班级名称", "排名", "总分数"}; + String[] headers = {"学号", "学生姓名", "班级名称", "排名", "参考成绩", "实训进度"}; //具体需要写入excel需要哪些字段,这些字段取自UserReward类,也就是上面的实际数据结果集的泛型 - List listColumn = Arrays.asList("username", "name", "className", "stuRank", "score"); + List listColumn = Arrays.asList("username", "name", "className", "stuRank", "score", "trainingProgress"); try { FilePortUtil.exportExcel(response, title, headers, stuRankList, listColumn); } catch (Exception e) { @@ -237,4 +244,58 @@ public class TeaScoreController { } criteria.andSchoolClassIdEqualTo(classId); } + + private void enrichTrainingProgress(List ranks, String requestedClassId) { + if (ranks == null || ranks.isEmpty()) { + return; + } + for (StuRank rank : ranks) { + String classId = StringUtils.isNotBlank(requestedClassId) ? requestedClassId : rank.getSchoolClassId(); + Set enabledModules = resolveEnabledTaskModules(classId); + int totalTaskCount = enabledModules.size(); + rank.setTotalTaskCount(totalTaskCount); + if (totalTaskCount == 0) { + rank.setCompletedTaskCount(0); + rank.setTrainingProgress(null); + continue; + } + + StuGradeExample gradeExample = new StuGradeExample(); + StuGradeExample.Criteria gradeCriteria = gradeExample.createCriteria().andUserIdEqualTo(rank.getUserId()); + if (StringUtils.isNotBlank(classId)) { + gradeCriteria.andSchoolClassIdEqualTo(classId); + } + List grades = stuGradeMapper == null ? Collections.emptyList() : stuGradeMapper.selectByExample(gradeExample); + int completedTaskCount = (int) (grades == null ? Collections.emptyList() : grades).stream() + .map(StuGrade::getModule) + .filter(enabledModules::contains) + .distinct() + .count(); + rank.setCompletedTaskCount(completedTaskCount); + rank.setTrainingProgress(BigDecimal.valueOf(completedTaskCount) + .multiply(BigDecimal.valueOf(100)) + .divide(BigDecimal.valueOf(totalTaskCount), 2, BigDecimal.ROUND_HALF_UP)); + } + } + + private Set resolveEnabledTaskModules(String classId) { + if (taskAllocationMapper == null || StringUtils.isBlank(classId)) { + return Collections.emptySet(); + } + List allocations = selectTaskAllocations(classId); + if ((allocations == null || allocations.isEmpty()) && !"999999999".equals(classId)) { + allocations = selectTaskAllocations("999999999"); + } + return (allocations == null ? Collections.emptyList() : allocations).stream() + .filter(allocation -> allocation.getDisabledStatus() == null || allocation.getDisabledStatus() != 1) + .map(TaskAllocation::getModule) + .filter(StringUtils::isNotBlank) + .collect(Collectors.toSet()); + } + + private List selectTaskAllocations(String classId) { + TaskAllocationExample example = new TaskAllocationExample(); + example.createCriteria().andClassIdEqualTo(classId); + return taskAllocationMapper.selectByExample(example); + } } diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/StuRank.java b/src/main/java/com/sztzjy/linkCommerce/entity/StuRank.java index f8e91d7..7caf246 100644 --- a/src/main/java/com/sztzjy/linkCommerce/entity/StuRank.java +++ b/src/main/java/com/sztzjy/linkCommerce/entity/StuRank.java @@ -40,6 +40,15 @@ public class StuRank { @ApiModelProperty(notes = "总分数") private BigDecimal score; + @ApiModelProperty(notes = "已完成实训任务数(查询时计算,不落库)") + private Integer completedTaskCount; + + @ApiModelProperty(notes = "已分配实训任务数(查询时计算,不落库)") + private Integer totalTaskCount; + + @ApiModelProperty(notes = "实训进度百分比(查询时计算,不落库)") + private BigDecimal trainingProgress; + @ApiModelProperty(notes = "市场需求挖掘分数") private BigDecimal scqxwjScore; @@ -156,6 +165,30 @@ public class StuRank { this.score = score; } + public Integer getCompletedTaskCount() { + return completedTaskCount; + } + + public void setCompletedTaskCount(Integer completedTaskCount) { + this.completedTaskCount = completedTaskCount; + } + + public Integer getTotalTaskCount() { + return totalTaskCount; + } + + public void setTotalTaskCount(Integer totalTaskCount) { + this.totalTaskCount = totalTaskCount; + } + + public BigDecimal getTrainingProgress() { + return trainingProgress; + } + + public void setTrainingProgress(BigDecimal trainingProgress) { + this.trainingProgress = trainingProgress; + } + public BigDecimal getScqxwjScore() { return scqxwjScore; } @@ -251,4 +284,4 @@ public class StuRank { public void setStudyTimeRank(Integer studyTimeRank) { this.studyTimeRank = studyTimeRank; } -} \ No newline at end of file +} diff --git a/src/test/java/com/sztzjy/linkCommerce/controller/stu/TeaScoreControllerProgressTest.java b/src/test/java/com/sztzjy/linkCommerce/controller/stu/TeaScoreControllerProgressTest.java new file mode 100644 index 0000000..0030781 --- /dev/null +++ b/src/test/java/com/sztzjy/linkCommerce/controller/stu/TeaScoreControllerProgressTest.java @@ -0,0 +1,101 @@ +package com.sztzjy.linkCommerce.controller.stu; + +import com.github.pagehelper.PageInfo; +import com.sztzjy.linkCommerce.entity.StuGrade; +import com.sztzjy.linkCommerce.entity.StuRank; +import com.sztzjy.linkCommerce.entity.TaskAllocation; +import com.sztzjy.linkCommerce.mapper.StuGradeMapper; +import com.sztzjy.linkCommerce.mapper.StuRankMapper; +import com.sztzjy.linkCommerce.mapper.TaskAllocationMapper; +import com.sztzjy.linkCommerce.mapper.SchoolClassMapper; +import com.sztzjy.linkCommerce.service.ScoreRankService; +import com.sztzjy.linkCommerce.util.ResultEntity; +import org.junit.jupiter.api.Test; +import org.springframework.test.util.ReflectionTestUtils; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class TeaScoreControllerProgressTest { + + @Test + void selectStuRankAndScoreCountsOnlyDistinctEnabledAllocatedTasks() { + TeaScoreController controller = controllerWithMocks(); + StuRankMapper rankMapper = field(controller, "stuRankMapper"); + TaskAllocationMapper taskMapper = field(controller, "taskAllocationMapper"); + StuGradeMapper gradeMapper = field(controller, "stuGradeMapper"); + StuRank rank = rank("student-1", "class-1"); + + when(rankMapper.selectByExample(any())).thenReturn(Collections.singletonList(rank)); + when(taskMapper.selectByExample(any())).thenReturn(Arrays.asList(task("任务A", (byte) 0), task("任务B", (byte) 0), task("任务C", (byte) 1))); + when(gradeMapper.selectByExample(any())).thenReturn(Arrays.asList(grade("任务A"), grade("任务A"), grade("任务C"))); + + ResultEntity> result = controller.selectStuRankAndScore("class-1", null, null, "school-1", 1, 10); + StuRank row = result.getBody().getData().getList().get(0); + + assertEquals(1, row.getCompletedTaskCount()); + assertEquals(2, row.getTotalTaskCount()); + assertEquals(new BigDecimal("50.00"), row.getTrainingProgress()); + } + + @Test + void selectStuRankAndScoreLeavesProgressEmptyWhenNoTaskIsAllocated() { + TeaScoreController controller = controllerWithMocks(); + StuRankMapper rankMapper = field(controller, "stuRankMapper"); + TaskAllocationMapper taskMapper = field(controller, "taskAllocationMapper"); + StuRank rank = rank("student-1", "class-1"); + + when(rankMapper.selectByExample(any())).thenReturn(Collections.singletonList(rank)); + when(taskMapper.selectByExample(any())).thenReturn(Collections.emptyList()); + + ResultEntity> result = controller.selectStuRankAndScore("class-1", null, null, "school-1", 1, 10); + StuRank row = result.getBody().getData().getList().get(0); + + assertEquals(0, row.getTotalTaskCount()); + assertNull(row.getTrainingProgress()); + } + + private TeaScoreController controllerWithMocks() { + TeaScoreController controller = new TeaScoreController(); + ReflectionTestUtils.setField(controller, "stuRankMapper", mock(StuRankMapper.class)); + ReflectionTestUtils.setField(controller, "stuGradeMapper", mock(StuGradeMapper.class)); + ReflectionTestUtils.setField(controller, "taskAllocationMapper", mock(TaskAllocationMapper.class)); + ReflectionTestUtils.setField(controller, "schoolClassMapper", mock(SchoolClassMapper.class)); + ScoreRankService scoreRankService = mock(ScoreRankService.class); + when(scoreRankService.getNowDate()).thenReturn("2026-07-30"); + ReflectionTestUtils.setField(controller, "scoreRankService", scoreRankService); + return controller; + } + + @SuppressWarnings("unchecked") + private T field(TeaScoreController controller, String name) { + return (T) ReflectionTestUtils.getField(controller, name); + } + + private StuRank rank(String userId, String classId) { + StuRank row = new StuRank(); + row.setUserId(userId); + row.setSchoolClassId(classId); + return row; + } + + private TaskAllocation task(String module, byte disabledStatus) { + TaskAllocation task = new TaskAllocation(); + task.setModule(module); + task.setDisabledStatus(disabledStatus); + return task; + } + + private StuGrade grade(String module) { + StuGrade grade = new StuGrade(); + grade.setModule(module); + return grade; + } +}