feat: 支持教学班学生与演示排名

main
chenyuan 4 weeks ago
parent 23441b3797
commit 5dfb1a269a

@ -217,7 +217,10 @@ public class ScoreController {
scoreRankExample.setOrderByClause("score desc");
List<StuRank> scoreRankList = stuRankMapper.selectByExample(scoreRankExample);
if (scoreRankList.isEmpty()) { //代表成绩还没更新
scoreRankService.doRankOne(schoolId);
// 教学班(包含演示模式)必须按教学班成员计算排名;旧行政班才回退到全校排名。
if (!Boolean.TRUE.equals(scoreRankService.doRankTeachingClass(schoolId, classId))) {
scoreRankService.doRankOne(schoolId);
}
scoreRankList = stuRankMapper.selectByExample(scoreRankExample);
}
if(scoreRankList.isEmpty() || scoreRankList==null){

@ -859,6 +859,86 @@ public class UserController {
}
}
@PostMapping("/teacher-roster/students")
@ApiOperation("教师维护名单模式-新增学生档案")
@AnonymousAccess
public ResultEntity addTeacherRosterStudent(@RequestParam String name,
@RequestParam String userName,
@RequestParam String teachingClassId,
@RequestParam String operatorId) {
Userinfo operator = userinfoMapper.selectByPrimaryKey(operatorId);
if (!isSchoolTeacher(operator) || !isTeacherRosterMode(operator.getSchoolId())) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "无权维护学生名单");
}
SchoolClass teachingClass = schoolClassMapper.selectByPrimaryKey(teachingClassId);
if (!isOwnedTeachingClass(teachingClass, operatorId)) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "只能选择自己创建的教学班");
}
if (StringUtils.isAnyBlank(StringUtils.trimToNull(name), StringUtils.trimToNull(userName))) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生姓名和学号不能为空");
}
String normalizedUserName = StringUtils.trim(userName);
if (userinfoMapper.selectBySchoolIdAndUsername(operator.getSchoolId(), normalizedUserName) != null
|| userInfoService.existsByUserName(normalizedUserName)) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "账号已存在");
}
Userinfo student = new Userinfo();
student.setUserId(UUID.randomUUID().toString());
student.setName(StringUtils.trim(name));
student.setUsername(normalizedUserName);
student.setPassword("123qwe");
student.setRole(4);
student.setTeacherAdmin(false);
student.setSchoolId(operator.getSchoolId());
student.setCreateTime(new Date());
student.setCodeFrom("教师名单添加");
if (userinfoMapper.insertSelective(student) <= 0) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "新增学生失败");
}
teachingClassStudentMapper.exitActiveByStudentUserIdExceptClass(student.getUserId(), teachingClassId);
upsertActiveTeachingClassMember(teachingClassId, student, null, "TEACHER_ROSTER_MANUAL");
return new ResultEntity<>(HttpStatus.OK, "新增学生成功");
}
@PostMapping("/teacher-roster/students/{studentUserId}")
@ApiOperation("教师维护名单模式-编辑学生档案")
@AnonymousAccess
public ResultEntity updateTeacherRosterStudent(@PathVariable String studentUserId,
@RequestParam String name,
@RequestParam String userName,
@RequestParam String teachingClassId,
@RequestParam String operatorId) {
Userinfo operator = userinfoMapper.selectByPrimaryKey(operatorId);
Userinfo existingStudent = userinfoMapper.selectByPrimaryKey(studentUserId);
if (!isSchoolTeacher(operator) || !isTeacherRosterMode(operator.getSchoolId())
|| existingStudent == null || !Integer.valueOf(4).equals(existingStudent.getRole())
|| !StringUtils.equals(operator.getSchoolId(), existingStudent.getSchoolId())) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "无权维护该学生名单");
}
SchoolClass teachingClass = schoolClassMapper.selectByPrimaryKey(teachingClassId);
if (!isOwnedTeachingClass(teachingClass, operatorId)) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "只能选择自己创建的教学班");
}
if (StringUtils.isAnyBlank(StringUtils.trimToNull(name), StringUtils.trimToNull(userName))) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生姓名和学号不能为空");
}
String normalizedUserName = StringUtils.trim(userName);
if (!StringUtils.equals(normalizedUserName, existingStudent.getUsername())
&& userInfoService.existsByUserName(normalizedUserName)) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "账号已存在");
}
Userinfo update = new Userinfo();
update.setUserId(studentUserId);
update.setName(StringUtils.trim(name));
update.setUsername(normalizedUserName);
if (userinfoMapper.updateByPrimaryKeySelective(update) <= 0) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "编辑学生失败");
}
teachingClassStudentMapper.exitActiveByStudentUserIdExceptClass(studentUserId, teachingClassId);
upsertActiveTeachingClassMember(teachingClassId, existingStudent, null, "TEACHER_ROSTER_MANUAL");
return new ResultEntity<>(HttpStatus.OK, "编辑学生成功");
}
//查询
@PostMapping("/selectStudent")
@ApiOperation("学生管理-查询学生账号信息")
@ -905,9 +985,10 @@ public class UserController {
if (StringUtils.isNotBlank(schoolClassId)) {
userInfoList.get(i).setClassName(schoolClass.getClassName());
} else {
String schoolClassId1 = userInfoList.get(i).getSchoolClassId();
schoolClass = schoolClassMapper.selectByPrimaryKey(schoolClassId1);
userInfoList.get(i).setClassName(schoolClass.getClassName());
Userinfo student = userInfoList.get(i);
if (!populateTeacherRosterTeachingClass(student, schoolId)) {
student.setClassName(safeClassName(student.getSchoolClassId()));
}
}
} else {
String schoolId1 = userInfoList.get(i).getSchoolId();
@ -916,9 +997,10 @@ public class UserController {
if (StringUtils.isNotBlank(schoolClassId)) {
userInfoList.get(i).setClassName(schoolClass.getClassName());
} else {
String schoolClassId1 = userInfoList.get(i).getSchoolClassId();
schoolClass = schoolClassMapper.selectByPrimaryKey(schoolClassId1);
userInfoList.get(i).setClassName(schoolClass.getClassName());
Userinfo student = userInfoList.get(i);
if (!populateTeacherRosterTeachingClass(student, schoolId1)) {
student.setClassName(safeClassName(student.getSchoolClassId()));
}
}
}
}
@ -1499,6 +1581,23 @@ public class UserController {
return schoolClass == null ? "" : schoolClass.getClassName();
}
private boolean populateTeacherRosterTeachingClass(Userinfo student, String schoolId) {
if (!isTeacherRosterMode(schoolId) || teachingClassStudentMapper == null || student == null) {
return false;
}
TeachingClassStudent membership = teachingClassStudentMapper.selectActiveByStudentUserId(student.getUserId());
if (membership == null || StringUtils.isBlank(membership.getTeachingClassId())) {
return false;
}
SchoolClass teachingClass = schoolClassMapper.selectByPrimaryKey(membership.getTeachingClassId());
if (teachingClass == null || !"TEACHING".equals(teachingClass.getClassType())) {
return false;
}
student.setTeachingClassId(teachingClass.getSchoolClassId());
student.setClassName(teachingClass.getClassName());
return true;
}
private boolean hasMajorUnderFaculty(String schoolFacultyId) {
SchoolMajorExample example = new SchoolMajorExample();
example.createCriteria().andSchoolFacultyIdEqualTo(schoolFacultyId);

@ -72,6 +72,9 @@ public class Userinfo {
@ApiModelProperty(notes = "班级ID关联班级表教师账号为null")
private String schoolClassId;
@ApiModelProperty("当前教学班ID列表与编辑回显用")
private String teachingClassId;
@ApiModelProperty("班级名称 回显用")
private String className;
@ApiModelProperty("学校名称 回显用")
@ -260,4 +263,12 @@ public class Userinfo {
public void setSchoolClassId(String schoolClassId) {
this.schoolClassId = schoolClassId == null ? null : schoolClassId.trim();
}
public String getTeachingClassId() {
return teachingClassId;
}
public void setTeachingClassId(String teachingClassId) {
this.teachingClassId = teachingClassId == null ? null : teachingClassId.trim();
}
}

@ -0,0 +1,35 @@
package com.sztzjy.linkCommerce.controller.stu;
import com.sztzjy.linkCommerce.mapper.StuRankMapper;
import com.sztzjy.linkCommerce.service.ScoreRankService;
import com.sztzjy.linkCommerce.util.ResultEntity;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class ScoreControllerTeachingClassTrendTest {
@Test
void studentTrendBuildsRanksInsideTeachingClassBeforeFallingBackToLegacySchoolRanking() {
ScoreController controller = new ScoreController();
controller.stuRankMapper = mock(StuRankMapper.class);
controller.scoreRankService = mock(ScoreRankService.class);
when(controller.scoreRankService.getNowDate()).thenReturn("2026-07-31");
when(controller.stuRankMapper.selectByExample(any())).thenReturn(Collections.emptyList());
when(controller.scoreRankService.doRankTeachingClass("school-1", "teaching-1")).thenReturn(true);
ResultEntity result = controller.getStuScoreTrend("demo:session-1", "teaching-1", "school-1");
assertEquals(HttpStatus.OK, result.getStatusCode());
verify(controller.scoreRankService).doRankTeachingClass("school-1", "teaching-1");
verify(controller.scoreRankService, never()).doRankOne("school-1");
}
}

@ -19,6 +19,7 @@ import com.sztzjy.linkCommerce.entity.importDto.SchoolAdminStudentImportDTO;
import com.sztzjy.linkCommerce.entity.importDto.TeachingClassStudentImportDTO;
import com.sztzjy.linkCommerce.util.Pinyin4jUtil;
import com.sztzjy.linkCommerce.util.ResultEntity;
import com.github.pagehelper.PageInfo;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.http.HttpStatus;
@ -632,6 +633,69 @@ class UserControllerTeacherAdminTest {
assertEquals(userCaptor.getValue().getUserId(), memberCaptor.getValue().getStudentUserId());
}
@Test
void teacherCanCreateStudentRosterEntryInSelectedTeachingClassWithoutOrganizationFields() {
UserController controller = controllerWithCommonMocks();
controller.schoolProductConfigService = mock(SchoolProductConfigService.class);
SchoolClass teachingClass = classCreatedBy("teacher-1");
teachingClass.setSchoolClassId("teaching-1");
when(controller.userinfoMapper.selectByPrimaryKey("teacher-1")).thenReturn(teacher("teacher-1"));
when(controller.schoolProductConfigService.isTeacherRosterManaged("school-1")).thenReturn(true);
when(controller.schoolClassMapper.selectByPrimaryKey("teaching-1")).thenReturn(teachingClass);
when(controller.userinfoMapper.selectBySchoolIdAndUsername("school-1", "s001")).thenReturn(null);
when(controller.userInfoService.existsByUserName("s001")).thenReturn(false);
when(controller.userinfoMapper.insertSelective(any(Userinfo.class))).thenReturn(1);
when(controller.teachingClassStudentMapper.insertSelective(any(TeachingClassStudent.class))).thenReturn(1);
ResultEntity result = controller.addTeacherRosterStudent("学生", "s001", "teaching-1", "teacher-1");
ArgumentCaptor<Userinfo> captor = ArgumentCaptor.forClass(Userinfo.class);
ArgumentCaptor<TeachingClassStudent> memberCaptor = ArgumentCaptor.forClass(TeachingClassStudent.class);
verify(controller.userinfoMapper).insertSelective(captor.capture());
verify(controller.teachingClassStudentMapper).insertSelective(memberCaptor.capture());
assertEquals(HttpStatus.OK, result.getStatusCode());
assertEquals("school-1", captor.getValue().getSchoolId());
assertNull(captor.getValue().getSchoolFacultyId());
assertNull(captor.getValue().getSchoolMajorId());
assertNull(captor.getValue().getSchoolClassId());
assertEquals("teaching-1", memberCaptor.getValue().getTeachingClassId());
assertEquals(captor.getValue().getUserId(), memberCaptor.getValue().getStudentUserId());
}
@Test
void teacherCanMoveStudentRosterEntryToSelectedTeachingClass() {
UserController controller = controllerWithCommonMocks();
controller.schoolProductConfigService = mock(SchoolProductConfigService.class);
Userinfo student = new Userinfo();
student.setUserId("student-1");
student.setSchoolId("school-1");
student.setRole(4);
student.setName("旧姓名");
student.setUsername("old001");
SchoolClass teachingClass = classCreatedBy("teacher-1");
teachingClass.setSchoolClassId("teaching-2");
when(controller.userinfoMapper.selectByPrimaryKey("teacher-1")).thenReturn(teacher("teacher-1"));
when(controller.userinfoMapper.selectByPrimaryKey("student-1")).thenReturn(student);
when(controller.schoolProductConfigService.isTeacherRosterManaged("school-1")).thenReturn(true);
when(controller.schoolClassMapper.selectByPrimaryKey("teaching-2")).thenReturn(teachingClass);
when(controller.userInfoService.existsByUserName("new001")).thenReturn(false);
when(controller.userinfoMapper.updateByPrimaryKeySelective(any(Userinfo.class))).thenReturn(1);
when(controller.teachingClassStudentMapper.insertSelective(any(TeachingClassStudent.class))).thenReturn(1);
ResultEntity result = controller.updateTeacherRosterStudent("student-1", "新姓名", "new001", "teaching-2", "teacher-1");
ArgumentCaptor<Userinfo> captor = ArgumentCaptor.forClass(Userinfo.class);
ArgumentCaptor<TeachingClassStudent> memberCaptor = ArgumentCaptor.forClass(TeachingClassStudent.class);
verify(controller.userinfoMapper).updateByPrimaryKeySelective(captor.capture());
verify(controller.teachingClassStudentMapper).exitActiveByStudentUserIdExceptClass("student-1", "teaching-2");
verify(controller.teachingClassStudentMapper).insertSelective(memberCaptor.capture());
assertEquals(HttpStatus.OK, result.getStatusCode());
assertEquals("新姓名", captor.getValue().getName());
assertEquals("new001", captor.getValue().getUsername());
assertNull(captor.getValue().getSchoolClassId());
assertEquals("teaching-2", memberCaptor.getValue().getTeachingClassId());
}
@Test
void teacherCannotInitializeTeachingClassCreatedByAnotherTeacher() {
UserController controller = controllerWithCommonMocks();
@ -695,6 +759,37 @@ class UserControllerTeacherAdminTest {
verify(controller.teachingClassStudentMapper).selectByTeachingClassId("teaching-1");
}
@Test
void selectStudentAllowsStudentsWithoutAnAssignedClass() {
UserController controller = controllerWithCommonMocks();
Userinfo student = student("student-1", "student", "2024001", null);
when(controller.userinfoMapper.selectByExample(any())).thenReturn(Collections.singletonList(student));
ResultEntity<PageInfo<Userinfo>> result = controller.selectStudent("school-1", null, null, null, 1, 10);
assertEquals(HttpStatus.OK, result.getStatusCode());
assertEquals("", result.getBody().getData().getList().get(0).getClassName());
}
@Test
void selectStudentInTeacherRosterModeDisplaysActiveTeachingClass() {
UserController controller = controllerWithCommonMocks();
when(controller.schoolProductConfigService.isTeacherRosterManaged("school-1")).thenReturn(true);
Userinfo student = student("student-1", "student", "2024001", null);
TeachingClassStudent membership = new TeachingClassStudent();
membership.setTeachingClassId("teaching-1");
SchoolClass teachingClass = classCreatedBy("teacher-1");
teachingClass.setSchoolClassId("teaching-1");
teachingClass.setClassName("Teaching 1");
when(controller.userinfoMapper.selectByExample(any())).thenReturn(Collections.singletonList(student));
when(controller.teachingClassStudentMapper.selectActiveByStudentUserId("student-1")).thenReturn(membership);
when(controller.schoolClassMapper.selectByPrimaryKey("teaching-1")).thenReturn(teachingClass);
ResultEntity<PageInfo<Userinfo>> result = controller.selectStudent("school-1", null, null, null, 1, 10);
assertEquals("Teaching 1", result.getBody().getData().getList().get(0).getClassName());
}
@Test
void importTeachingClassStudentRowsCreatesMembershipForMatchedAdminStudents() {
UserController controller = controllerWithCommonMocks();

Loading…
Cancel
Save