fix: persist teacher scores for score details

bugfix/ai-assessment-evidence-rescore
chenyuan 1 month ago
parent 06bae933f2
commit 40498fac1d

@ -0,0 +1,28 @@
package com.sztzjy.linkCommerce.config;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/** Keeps existing deployments compatible with teacher-entered scores. */
@Component
public class TeachingClassTeacherScoreSchemaInitializer {
private final JdbcTemplate jdbcTemplate;
public TeachingClassTeacherScoreSchemaInitializer(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@PostConstruct
public void initialize() {
jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS teaching_class_teacher_score (" +
"teaching_class_id varchar(64) NOT NULL," +
"student_user_id varchar(64) NOT NULL," +
"teacher_score decimal(5,2) NOT NULL," +
"scored_by varchar(64) NOT NULL," +
"update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
"PRIMARY KEY (teaching_class_id, student_user_id)" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
}
}

@ -97,6 +97,20 @@ public class TeaScoreController {
}
}
@PostMapping("/saveTeacherScore")
@ApiOperation("保存老师对学生的人工评分")
public ResultEntity<?> saveTeacherScore(@RequestParam String classId,
@RequestParam String studentUserId,
@RequestParam BigDecimal teacherScore,
HttpServletRequest request) {
try {
return new ResultEntity<>(HttpStatus.OK, "老师评分保存成功",
teacherScoreService.saveTeacherScore(currentUser(request), classId, studentUserId, teacherScore));
} catch (com.sztzjy.linkCommerce.config.exception.handler.ServiceException e) {
return new ResultEntity<>(e.getCode(), e.getMessage());
}
}
@PostMapping("/selectStuRankAndScore")
@ApiOperation("查询学生成绩和排名")
@AnonymousAccess
@ -334,6 +348,7 @@ public class TeaScoreController {
}
for (StuRank rank : ranks) {
String classId = StringUtils.isNotBlank(requestedClassId) ? requestedClassId : rank.getSchoolClassId();
rank.setTeacherScore(teacherScoreService.getTeacherScore(classId, rank.getUserId()));
Set<String> enabledModules = resolveEnabledTaskModules(classId);
int totalTaskCount = enabledModules.size();
rank.setTotalTaskCount(totalTaskCount);

@ -49,6 +49,9 @@ public class StuRank {
@ApiModelProperty(notes = "实训进度百分比(查询时计算,不落库)")
private BigDecimal trainingProgress;
@ApiModelProperty(notes = "老师人工评分(查询时从教学班评分表读取)")
private BigDecimal teacherScore;
@ApiModelProperty(notes = "市场需求挖掘分数")
private BigDecimal scqxwjScore;
@ -189,6 +192,14 @@ public class StuRank {
this.trainingProgress = trainingProgress;
}
public BigDecimal getTeacherScore() {
return teacherScore;
}
public void setTeacherScore(BigDecimal teacherScore) {
this.teacherScore = teacherScore;
}
public BigDecimal getScqxwjScore() {
return scqxwjScore;
}

@ -0,0 +1,23 @@
package com.sztzjy.linkCommerce.entity;
import java.math.BigDecimal;
import java.util.Date;
public class TeachingClassTeacherScore {
private String teachingClassId;
private String studentUserId;
private BigDecimal teacherScore;
private String scoredBy;
private Date updateTime;
public String getTeachingClassId() { return teachingClassId; }
public void setTeachingClassId(String teachingClassId) { this.teachingClassId = teachingClassId; }
public String getStudentUserId() { return studentUserId; }
public void setStudentUserId(String studentUserId) { this.studentUserId = studentUserId; }
public BigDecimal getTeacherScore() { return teacherScore; }
public void setTeacherScore(BigDecimal teacherScore) { this.teacherScore = teacherScore; }
public String getScoredBy() { return scoredBy; }
public void setScoredBy(String scoredBy) { this.scoredBy = scoredBy; }
public Date getUpdateTime() { return updateTime; }
public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
}

@ -0,0 +1,12 @@
package com.sztzjy.linkCommerce.mapper;
import com.sztzjy.linkCommerce.entity.TeachingClassTeacherScore;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface TeachingClassTeacherScoreMapper {
TeachingClassTeacherScore selectByClassAndStudent(@Param("teachingClassId") String teachingClassId,
@Param("studentUserId") String studentUserId);
int upsert(TeachingClassTeacherScore record);
}

@ -3,7 +3,9 @@ package com.sztzjy.linkCommerce.service;
import com.sztzjy.linkCommerce.config.security.JwtUser;
import com.sztzjy.linkCommerce.entity.SchoolClass;
import com.sztzjy.linkCommerce.entity.TeachingClassScoreWeight;
import com.sztzjy.linkCommerce.entity.TeachingClassTeacherScore;
import java.math.BigDecimal;
import java.util.List;
public interface TeacherScoreService {
@ -11,4 +13,7 @@ public interface TeacherScoreService {
SchoolClass requireOwnedClass(JwtUser teacher, String teachingClassId);
TeachingClassScoreWeight getOrCreateWeight(JwtUser teacher, String teachingClassId);
TeachingClassScoreWeight saveWeight(JwtUser teacher, String teachingClassId, TeachingClassScoreWeight weight);
BigDecimal getTeacherScore(String teachingClassId, String studentUserId);
TeachingClassTeacherScore saveTeacherScore(JwtUser teacher, String teachingClassId,
String studentUserId, BigDecimal score);
}

@ -5,8 +5,11 @@ import com.sztzjy.linkCommerce.config.security.JwtUser;
import com.sztzjy.linkCommerce.entity.SchoolClass;
import com.sztzjy.linkCommerce.entity.SchoolClassExample;
import com.sztzjy.linkCommerce.entity.TeachingClassScoreWeight;
import com.sztzjy.linkCommerce.entity.TeachingClassTeacherScore;
import com.sztzjy.linkCommerce.mapper.SchoolClassMapper;
import com.sztzjy.linkCommerce.mapper.TeachingClassScoreWeightMapper;
import com.sztzjy.linkCommerce.mapper.TeachingClassStudentMapper;
import com.sztzjy.linkCommerce.mapper.TeachingClassTeacherScoreMapper;
import com.sztzjy.linkCommerce.service.TeacherScoreService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -14,6 +17,7 @@ import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.List;
@ -23,6 +27,10 @@ public class TeacherScoreServiceImpl implements TeacherScoreService {
SchoolClassMapper schoolClassMapper;
@Autowired(required = false)
TeachingClassScoreWeightMapper weightMapper;
@Autowired
TeachingClassTeacherScoreMapper teacherScoreMapper;
@Autowired
TeachingClassStudentMapper teachingClassStudentMapper;
@Override
public List<SchoolClass> listOwnedClasses(JwtUser teacher) {
@ -81,6 +89,35 @@ public class TeacherScoreServiceImpl implements TeacherScoreService {
return weight;
}
@Override
public BigDecimal getTeacherScore(String teachingClassId, String studentUserId) {
if (StringUtils.isBlank(teachingClassId) || StringUtils.isBlank(studentUserId)) {
return null;
}
TeachingClassTeacherScore stored = teacherScoreMapper.selectByClassAndStudent(teachingClassId, studentUserId);
return stored == null ? null : stored.getTeacherScore();
}
@Override
public TeachingClassTeacherScore saveTeacherScore(JwtUser teacher, String teachingClassId,
String studentUserId, BigDecimal score) {
requireOwnedClass(teacher, teachingClassId);
if (StringUtils.isBlank(studentUserId)
|| teachingClassStudentMapper.countByStudentUserIdAndTeachingClassId(studentUserId, teachingClassId) == 0) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "该学生不在当前教学班");
}
if (score == null || score.compareTo(BigDecimal.ZERO) < 0 || score.compareTo(new BigDecimal("100")) > 0) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "老师评分必须为0至100之间的数值");
}
TeachingClassTeacherScore record = new TeachingClassTeacherScore();
record.setTeachingClassId(teachingClassId);
record.setStudentUserId(studentUserId);
record.setTeacherScore(score.setScale(2, RoundingMode.HALF_UP));
record.setScoredBy(teacher.getUserId());
teacherScoreMapper.upsert(record);
return record;
}
private TeachingClassScoreWeight defaultWeight(String teachingClassId) {
TeachingClassScoreWeight weight = new TeachingClassScoreWeight();
weight.setTeachingClassId(teachingClassId);

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sztzjy.linkCommerce.mapper.TeachingClassTeacherScoreMapper">
<resultMap id="BaseResultMap" type="com.sztzjy.linkCommerce.entity.TeachingClassTeacherScore">
<id column="teaching_class_id" property="teachingClassId" />
<id column="student_user_id" property="studentUserId" />
<result column="teacher_score" property="teacherScore" />
<result column="scored_by" property="scoredBy" />
<result column="update_time" property="updateTime" />
</resultMap>
<select id="selectByClassAndStudent" resultMap="BaseResultMap">
select teaching_class_id, student_user_id, teacher_score, scored_by, update_time
from teaching_class_teacher_score
where teaching_class_id = #{teachingClassId}
and student_user_id = #{studentUserId}
</select>
<insert id="upsert" parameterType="com.sztzjy.linkCommerce.entity.TeachingClassTeacherScore">
insert into teaching_class_teacher_score
(teaching_class_id, student_user_id, teacher_score, scored_by, update_time)
values
(#{teachingClassId}, #{studentUserId}, #{teacherScore}, #{scoredBy}, current_timestamp)
on duplicate key update
teacher_score = values(teacher_score),
scored_by = values(scored_by),
update_time = current_timestamp
</insert>
</mapper>

@ -4,15 +4,20 @@ import com.sztzjy.linkCommerce.config.exception.handler.ServiceException;
import com.sztzjy.linkCommerce.config.security.JwtUser;
import com.sztzjy.linkCommerce.entity.SchoolClass;
import com.sztzjy.linkCommerce.entity.TeachingClassScoreWeight;
import com.sztzjy.linkCommerce.entity.TeachingClassTeacherScore;
import com.sztzjy.linkCommerce.mapper.SchoolClassMapper;
import com.sztzjy.linkCommerce.mapper.TeachingClassScoreWeightMapper;
import com.sztzjy.linkCommerce.mapper.TeachingClassStudentMapper;
import com.sztzjy.linkCommerce.mapper.TeachingClassTeacherScoreMapper;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class TeacherScoreServiceImplTest {
@ -49,6 +54,42 @@ class TeacherScoreServiceImplTest {
assertEquals(HttpStatus.FORBIDDEN, error.getCode());
}
@Test
void savesTeacherScoreForStudentInOwnedTeachingClass() {
TeacherScoreServiceImpl service = new TeacherScoreServiceImpl();
SchoolClassMapper classMapper = mock(SchoolClassMapper.class);
TeachingClassStudentMapper memberMapper = mock(TeachingClassStudentMapper.class);
TeachingClassTeacherScoreMapper scoreMapper = mock(TeachingClassTeacherScoreMapper.class);
ReflectionTestUtils.setField(service, "schoolClassMapper", classMapper);
ReflectionTestUtils.setField(service, "teachingClassStudentMapper", memberMapper);
ReflectionTestUtils.setField(service, "teacherScoreMapper", scoreMapper);
when(classMapper.selectByPrimaryKey("class-1")).thenReturn(classRow("class-1", "teacher-1", "school-1"));
when(memberMapper.countByStudentUserIdAndTeachingClassId("student-1", "class-1")).thenReturn(1L);
TeachingClassTeacherScore saved = service.saveTeacherScore(
teacher("teacher-1", "school-1"), "class-1", "student-1", new java.math.BigDecimal("88.126"));
assertEquals(new java.math.BigDecimal("88.13"), saved.getTeacherScore());
assertEquals("teacher-1", saved.getScoredBy());
verify(scoreMapper).upsert(saved);
}
@Test
void rejectsTeacherScoreOutsideZeroToOneHundred() {
TeacherScoreServiceImpl service = new TeacherScoreServiceImpl();
SchoolClassMapper classMapper = mock(SchoolClassMapper.class);
TeachingClassStudentMapper memberMapper = mock(TeachingClassStudentMapper.class);
ReflectionTestUtils.setField(service, "schoolClassMapper", classMapper);
ReflectionTestUtils.setField(service, "teachingClassStudentMapper", memberMapper);
when(classMapper.selectByPrimaryKey("class-1")).thenReturn(classRow("class-1", "teacher-1", "school-1"));
when(memberMapper.countByStudentUserIdAndTeachingClassId("student-1", "class-1")).thenReturn(1L);
ServiceException error = assertThrows(ServiceException.class, () -> service.saveTeacherScore(
teacher("teacher-1", "school-1"), "class-1", "student-1", new java.math.BigDecimal("100.01")));
assertTrue(error.getMessage().contains("0至100"));
}
private JwtUser teacher(String userId, String schoolId) {
JwtUser user = new JwtUser();
user.setUserId(userId);

Loading…
Cancel
Save