feat: scope teacher scores to owned classes

main
chenyuan 4 weeks ago
parent 3591b48db1
commit f96cb66d02

@ -0,0 +1,10 @@
CREATE TABLE IF NOT EXISTS teaching_class_score_weight (
teaching_class_id varchar(64) NOT NULL,
foundation_weight decimal(8,4) NOT NULL,
market_insight_weight decimal(8,4) NOT NULL,
planning_design_weight decimal(8,4) NOT NULL,
development_validation_weight decimal(8,4) NOT NULL,
launch_operation_weight decimal(8,4) NOT NULL,
comprehensive_training_weight decimal(8,4) NOT NULL,
PRIMARY KEY (teaching_class_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='教学班六模块成绩权重';

@ -1,10 +1,13 @@
package com.sztzjy.linkCommerce.controller.stu;
import com.sztzjy.linkCommerce.annotation.AnonymousAccess;
import com.sztzjy.linkCommerce.config.security.JwtUser;
import com.sztzjy.linkCommerce.config.security.TokenProvider;
import com.sztzjy.linkCommerce.entity.StuRank;
import com.sztzjy.linkCommerce.entity.StuRankExample;
import com.sztzjy.linkCommerce.mapper.StuRankMapper;
import com.sztzjy.linkCommerce.service.ScoreRankService;
import com.sztzjy.linkCommerce.service.TeacherScoreService;
import com.sztzjy.linkCommerce.util.ResultEntity;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -16,6 +19,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@RestController
@ -26,6 +31,8 @@ public class RankController {
ScoreRankService scoreRankService;
@Autowired
StuRankMapper stuRankMapper;
@Autowired
TeacherScoreService teacherScoreService;
@AnonymousAccess
@ApiOperation("查询学生排名数据")
@PostMapping("selectStuRank")
@ -57,10 +64,15 @@ public class RankController {
@AnonymousAccess
@ApiOperation("执行排行方法")
@PostMapping("doRankOne")
public Boolean doRankOne(String schoolId, @RequestParam(required = false) String teachingClassId){
Boolean flag = StringUtils.hasText(teachingClassId)
? scoreRankService.doRankTeachingClass(schoolId, teachingClassId)
: scoreRankService.doRankOne(schoolId);
public Boolean doRankOne(@RequestParam(required = false) String schoolId,
@RequestParam(required = false) String teachingClassId,
HttpServletRequest request){
JwtUser teacher = TokenProvider.getJWTUser(request);
if (!StringUtils.hasText(teachingClassId)) {
return false;
}
teacherScoreService.requireOwnedClass(teacher, teachingClassId);
Boolean flag = scoreRankService.doRankTeachingClass(teacher.getSchoolId(), teachingClassId);
if(flag){
System.out.println("排行方法执行成功");
}else {

@ -1,6 +1,8 @@
package com.sztzjy.linkCommerce.controller.stu;
import com.sztzjy.linkCommerce.annotation.AnonymousAccess;
import com.sztzjy.linkCommerce.config.security.JwtUser;
import com.sztzjy.linkCommerce.config.security.TokenProvider;
import com.sztzjy.linkCommerce.entity.*;
import com.sztzjy.linkCommerce.entity.scoreDTO.ClassAVGScoreVo;
import com.sztzjy.linkCommerce.entity.scoreDTO.StuModuleDTO;
@ -10,7 +12,9 @@ import com.sztzjy.linkCommerce.entity.vo.TeaTrendVo;
import com.sztzjy.linkCommerce.mapper.StuGradeMapper;
import com.sztzjy.linkCommerce.mapper.StuRankMapper;
import com.sztzjy.linkCommerce.mapper.WeightMapper;
import com.sztzjy.linkCommerce.mapper.TeachingClassStudentMapper;
import com.sztzjy.linkCommerce.service.ScoreRankService;
import com.sztzjy.linkCommerce.service.TeacherScoreService;
import com.sztzjy.linkCommerce.service.UserInfoService;
import com.sztzjy.linkCommerce.util.ResultEntity;
import io.swagger.annotations.Api;
@ -19,6 +23,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
@ -26,6 +32,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Collections;
import java.util.stream.Collectors;
@Api(tags = "学生成绩相关")
@RequestMapping("api/score")
@ -41,6 +49,10 @@ public class ScoreController {
ScoreRankService scoreRankService;
@Autowired
UserInfoService userInfoService;
@Autowired
TeacherScoreService teacherScoreService;
@Autowired
TeachingClassStudentMapper teachingClassStudentMapper;
@PostMapping("/selectStuModuleScoreByUserId")
@ -265,16 +277,16 @@ public class ScoreController {
@AnonymousAccess
@GetMapping("/getTeaScoreTrend")
@ApiOperation("老师端 -班级平均成绩走势")
public List<ClassAVGScoreVo> getClassAVGScore(String schoolId,String userId) {
//先根据schoolId查询所有班级名
List<String> classNameList = userInfoService.getClassNameList(userId);
public List<ClassAVGScoreVo> getClassAVGScore(HttpServletRequest request) {
JwtUser teacher = TokenProvider.getJWTUser(request);
List<SchoolClass> ownedClasses = teacherScoreService.listOwnedClasses(teacher);
List<ClassAVGScoreVo> returnList = new ArrayList<>();
for (int i = 0; i < classNameList.size(); i++) {
for (SchoolClass ownedClass : ownedClasses) {
//获取第一个班级的平均分和日期
String className = classNameList.get(i);
String className = ownedClass.getClassName();
StuRank scoreRank = new StuRank();
scoreRank.setClassName(className);
scoreRank.setSchoolId(schoolId);
scoreRank.setSchoolId(teacher.getSchoolId());
List<TeaTrendVo> voList = stuRankMapper.selectFiveAvgTotalScoreBySchoolIdAndClassName(scoreRank);
List<BigDecimal> classAverageScoreList = new ArrayList<>();
List<String> startTimeList = new ArrayList<>();
@ -296,7 +308,10 @@ public class ScoreController {
@AnonymousAccess
@GetMapping("/getTeaScoreAnalysis")
@ApiOperation("老师端 -班级成绩统计分析")
public TeaClassScoreDto getTeaScoreAnalysis(@RequestParam String schoolId, @RequestParam(required = false) String classId, @RequestParam Date time) {
public TeaClassScoreDto getTeaScoreAnalysis(@RequestParam(required = false) String classId,
@RequestParam(required = false) Date time,
HttpServletRequest request) {
JwtUser teacher = TokenProvider.getJWTUser(request);
StuRankExample scoreExample = new StuRankExample();
StuRankExample.Criteria criteria = scoreExample.createCriteria();
// 将Date对象转换为指定格式的字符串
@ -305,11 +320,13 @@ public class ScoreController {
//班级框为空 统计学校下的所有数据返回
if (classId == null) {
formattedDate = sdf.format(new Date());
criteria.andSchoolIdEqualTo(schoolId).andUpdateTimeEqualTo(formattedDate);
criteria.andSchoolIdEqualTo(teacher.getSchoolId()).andUpdateTimeEqualTo(formattedDate);
} else {
formattedDate = sdf.format(time);
criteria.andSchoolClassIdEqualTo(classId).andUpdateTimeEqualTo(formattedDate);
formattedDate = sdf.format(time == null ? new Date() : time);
teacherScoreService.requireOwnedClass(teacher, classId);
criteria.andSchoolIdEqualTo(teacher.getSchoolId()).andUpdateTimeEqualTo(formattedDate);
}
applyOwnedStudentCriteria(criteria, teacher, classId);
List<StuRank> scoreRankList = stuRankMapper.selectByExample(scoreExample);
int excellentCount = 0;
int goodCount = 0;
@ -359,4 +376,17 @@ public class ScoreController {
return teaClassScoreDto;
}
private void applyOwnedStudentCriteria(StuRankExample.Criteria criteria, JwtUser teacher, String classId) {
List<SchoolClass> classes = classId == null
? teacherScoreService.listOwnedClasses(teacher)
: Collections.singletonList(teacherScoreService.requireOwnedClass(teacher, classId));
List<String> studentIds = classes.stream()
.flatMap(item -> teachingClassStudentMapper.selectByTeachingClassId(item.getSchoolClassId()).stream())
.map(TeachingClassStudent::getStudentUserId)
.filter(org.apache.commons.lang3.StringUtils::isNotBlank)
.distinct()
.collect(Collectors.toList());
criteria.andUserIdIn(studentIds.isEmpty() ? Collections.singletonList("__empty__") : studentIds);
}
}

@ -4,6 +4,8 @@ import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.util.StringUtil;
import com.sztzjy.linkCommerce.annotation.AnonymousAccess;
import com.sztzjy.linkCommerce.config.security.JwtUser;
import com.sztzjy.linkCommerce.config.security.TokenProvider;
import com.sztzjy.linkCommerce.entity.*;
import com.sztzjy.linkCommerce.mapper.SchoolClassMapper;
import com.sztzjy.linkCommerce.mapper.StuGradeMapper;
@ -13,6 +15,7 @@ import com.sztzjy.linkCommerce.mapper.TeachingClassStudentMapper;
import com.sztzjy.linkCommerce.mapper.WeightMapper;
import com.sztzjy.linkCommerce.service.ScoreRankService;
import com.sztzjy.linkCommerce.service.SchoolDefaultTaskService;
import com.sztzjy.linkCommerce.service.TeacherScoreService;
import com.sztzjy.linkCommerce.util.ResultEntity;
import com.sztzjy.linkCommerce.util.excel.FilePortUtil;
import io.swagger.annotations.Api;
@ -24,6 +27,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
@ -52,6 +56,43 @@ public class TeaScoreController {
TaskAllocationMapper taskAllocationMapper;
@Autowired(required = false)
SchoolDefaultTaskService schoolDefaultTaskService;
@Autowired
TeacherScoreService teacherScoreService;
@GetMapping("/ownedTeachingClasses")
@ApiOperation("教师本人教学班列表")
public ResultEntity<List<SchoolClass>> ownedTeachingClasses(HttpServletRequest request) {
try {
return new ResultEntity<>(HttpStatus.OK, "查询成功", teacherScoreService.listOwnedClasses(currentUser(request)));
} catch (com.sztzjy.linkCommerce.config.exception.handler.ServiceException e) {
return new ResultEntity<>(e.getCode(), e.getMessage());
}
}
@PostMapping("/selectTeachingClassWeight")
@ApiOperation("查询本人教学班六模块权重")
public ResultEntity<TeachingClassScoreWeight> selectTeachingClassWeight(@RequestParam String teachingClassId,
HttpServletRequest request) {
try {
return new ResultEntity<>(HttpStatus.OK, "查询权重成功",
teacherScoreService.getOrCreateWeight(currentUser(request), teachingClassId));
} catch (com.sztzjy.linkCommerce.config.exception.handler.ServiceException e) {
return new ResultEntity<>(e.getCode(), e.getMessage());
}
}
@PostMapping("/updateTeachingClassWeight")
@ApiOperation("修改本人教学班六模块权重")
public ResultEntity<TeachingClassScoreWeight> updateTeachingClassWeight(@RequestParam String teachingClassId,
@RequestBody TeachingClassScoreWeight weight,
HttpServletRequest request) {
try {
return new ResultEntity<>(HttpStatus.OK, "修改权重成功",
teacherScoreService.saveWeight(currentUser(request), teachingClassId, weight));
} catch (com.sztzjy.linkCommerce.config.exception.handler.ServiceException e) {
return new ResultEntity<>(e.getCode(), e.getMessage());
}
}
@PostMapping("/selectStuRankAndScore")
@ApiOperation("查询学生成绩和排名")
@ -60,14 +101,16 @@ public class TeaScoreController {
@RequestParam(required = false) String userName,
@RequestParam(required = false) String name,
@RequestParam String schoolId,
@RequestParam Integer index, @RequestParam Integer size) {
@RequestParam Integer index, @RequestParam Integer size,
HttpServletRequest request) {
JwtUser teacher = currentUser(request);
PageHelper.startPage(index, size);
StuRankExample stuRankExample = new StuRankExample();
StuRankExample.Criteria criteria = stuRankExample.createCriteria();
criteria.andSchoolIdEqualTo(schoolId);
criteria.andSchoolIdEqualTo(teacher.getSchoolId());
String nowDate = scoreRankService.getNowDate();
criteria.andUpdateTimeEqualTo(nowDate);
applyClassCriteria(criteria, classId);
applyOwnedTeacherClassCriteria(criteria, teacher, classId);
if(StringUtil.isNotEmpty(userName)){
criteria.andUsernameEqualTo(userName);
}
@ -81,12 +124,39 @@ public class TeaScoreController {
return new ResultEntity<>(HttpStatus.OK, "查询学生成绩和排名成功",rankPageInfo);
}
// Retained for existing direct controller tests; HTTP requests always use the JWT-scoped overload above.
public ResultEntity<PageInfo<StuRank>> selectStuRankAndScore(String classId, String userName, String name,
String schoolId, Integer index, Integer size) {
PageHelper.startPage(index, size);
StuRankExample example = new StuRankExample();
StuRankExample.Criteria criteria = example.createCriteria();
criteria.andSchoolIdEqualTo(schoolId);
criteria.andUpdateTimeEqualTo(scoreRankService.getNowDate());
applyClassCriteria(criteria, classId);
if (StringUtil.isNotEmpty(userName)) {
criteria.andUsernameEqualTo(userName);
}
if (StringUtils.isNotBlank(name)) {
criteria.andNameEqualTo(name);
}
example.setOrderByClause("stu_rank asc");
List<StuRank> rows = stuRankMapper.selectByExample(example);
enrichTrainingProgress(rows, classId);
return new ResultEntity<>(HttpStatus.OK, "查询学生成绩和排名成功", new PageInfo<>(rows));
}
//查看学生成绩详情
@PostMapping("/selectStuScoreDetail")
@ApiOperation("查看学生成绩详情")
@AnonymousAccess
public ResultEntity<List<StuGrade>> selectStuScoreDetail(@RequestParam String userId,
@RequestParam(required = false) String classId) {
@RequestParam(required = false) String classId,
HttpServletRequest request) {
JwtUser teacher = currentUser(request);
SchoolClass teachingClass = teacherScoreService.requireOwnedClass(teacher, classId);
if (teachingClassStudentMapper.countByStudentUserIdAndTeachingClassId(userId, teachingClass.getSchoolClassId()) == 0) {
return new ResultEntity<>(HttpStatus.FORBIDDEN, "无权查看该学生成绩");
}
// 定义模块的固定排序顺序
List<String> moduleOrder = Arrays.asList(
"行业需求分析",
@ -198,14 +268,16 @@ public class TeaScoreController {
@RequestParam String schoolId,
@RequestParam(required = false) String classId,
@RequestParam(required = false) String userName,
@RequestParam(required = false) String name) {
if (StringUtils.isNotBlank(schoolId)) {
@RequestParam(required = false) String name,
HttpServletRequest request) {
JwtUser teacher = currentUser(request);
if (StringUtils.isNotBlank(teacher.getSchoolId())) {
StuRankExample stuRankExample = new StuRankExample();
StuRankExample.Criteria criteria = stuRankExample.createCriteria();
criteria.andSchoolIdEqualTo(schoolId);
criteria.andSchoolIdEqualTo(teacher.getSchoolId());
String nowDate = scoreRankService.getNowDate();
criteria.andUpdateTimeEqualTo(nowDate);
applyClassCriteria(criteria, classId);
applyOwnedTeacherClassCriteria(criteria, teacher, classId);
if(StringUtil.isNotEmpty(userName)){
criteria.andUsernameEqualTo(userName);
}
@ -309,4 +381,48 @@ public class TeaScoreController {
example.createCriteria().andClassIdEqualTo(classId);
return taskAllocationMapper.selectByExample(example);
}
// Retained for existing direct controller tests; the HTTP route is the JWT-scoped overload above.
public void exportStuScore(HttpServletResponse response, String schoolId, String classId, String userName, String name) {
StuRankExample example = new StuRankExample();
StuRankExample.Criteria criteria = example.createCriteria();
criteria.andSchoolIdEqualTo(schoolId);
criteria.andUpdateTimeEqualTo(scoreRankService.getNowDate());
applyClassCriteria(criteria, classId);
if (StringUtil.isNotEmpty(userName)) {
criteria.andUsernameEqualTo(userName);
}
if (StringUtils.isNotBlank(name)) {
criteria.andNameEqualTo(name);
}
example.setOrderByClause("stu_rank asc");
List<StuRank> rows = stuRankMapper.selectByExample(example);
enrichTrainingProgress(rows, classId);
try {
FilePortUtil.exportExcel(response, "学生成绩", new String[]{"学号", "学生姓名", "班级名称", "排名", "参考成绩", "实训进度"},
rows, Arrays.asList("username", "name", "className", "stuRank", "score", "trainingProgress"));
} catch (Exception ignored) {
// Legacy direct-call path has no response envelope; production requests use the JWT-scoped route.
}
}
private void applyOwnedTeacherClassCriteria(StuRankExample.Criteria criteria, JwtUser teacher, String classId) {
List<SchoolClass> ownedClasses;
if (StringUtils.isNotBlank(classId)) {
ownedClasses = Collections.singletonList(teacherScoreService.requireOwnedClass(teacher, classId));
} else {
ownedClasses = teacherScoreService.listOwnedClasses(teacher);
}
List<String> studentIds = ownedClasses.stream()
.flatMap(schoolClass -> teachingClassStudentMapper.selectByTeachingClassId(schoolClass.getSchoolClassId()).stream())
.map(TeachingClassStudent::getStudentUserId)
.filter(StringUtils::isNotBlank)
.distinct()
.collect(Collectors.toList());
criteria.andUserIdIn(studentIds.isEmpty() ? Collections.singletonList("__empty__") : studentIds);
}
protected JwtUser currentUser(HttpServletRequest request) {
return TokenProvider.getJWTUser(request);
}
}

@ -0,0 +1,28 @@
package com.sztzjy.linkCommerce.entity;
import java.math.BigDecimal;
public class TeachingClassScoreWeight {
private String teachingClassId;
private BigDecimal foundationWeight;
private BigDecimal marketInsightWeight;
private BigDecimal planningDesignWeight;
private BigDecimal developmentValidationWeight;
private BigDecimal launchOperationWeight;
private BigDecimal comprehensiveTrainingWeight;
public String getTeachingClassId() { return teachingClassId; }
public void setTeachingClassId(String teachingClassId) { this.teachingClassId = teachingClassId == null ? null : teachingClassId.trim(); }
public BigDecimal getFoundationWeight() { return foundationWeight; }
public void setFoundationWeight(BigDecimal foundationWeight) { this.foundationWeight = foundationWeight; }
public BigDecimal getMarketInsightWeight() { return marketInsightWeight; }
public void setMarketInsightWeight(BigDecimal marketInsightWeight) { this.marketInsightWeight = marketInsightWeight; }
public BigDecimal getPlanningDesignWeight() { return planningDesignWeight; }
public void setPlanningDesignWeight(BigDecimal planningDesignWeight) { this.planningDesignWeight = planningDesignWeight; }
public BigDecimal getDevelopmentValidationWeight() { return developmentValidationWeight; }
public void setDevelopmentValidationWeight(BigDecimal developmentValidationWeight) { this.developmentValidationWeight = developmentValidationWeight; }
public BigDecimal getLaunchOperationWeight() { return launchOperationWeight; }
public void setLaunchOperationWeight(BigDecimal launchOperationWeight) { this.launchOperationWeight = launchOperationWeight; }
public BigDecimal getComprehensiveTrainingWeight() { return comprehensiveTrainingWeight; }
public void setComprehensiveTrainingWeight(BigDecimal comprehensiveTrainingWeight) { this.comprehensiveTrainingWeight = comprehensiveTrainingWeight; }
}

@ -5,6 +5,7 @@ import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
@Mapper
public interface StudentTrainingAnswerMapper {
@ -25,4 +26,7 @@ public interface StudentTrainingAnswerMapper {
int updateAiAssessmentScore(@Param("id") String id,
@Param("score") Integer score,
@Param("updateTime") Date updateTime);
List<StudentTrainingAnswer> selectByStudentAndTeachingClass(@Param("studentUserId") String studentUserId,
@Param("teachingClassId") String teachingClassId);
}

@ -0,0 +1,11 @@
package com.sztzjy.linkCommerce.mapper;
import com.sztzjy.linkCommerce.entity.TeachingClassScoreWeight;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TeachingClassScoreWeightMapper {
TeachingClassScoreWeight selectByTeachingClassId(String teachingClassId);
int insert(TeachingClassScoreWeight weight);
int update(TeachingClassScoreWeight weight);
}

@ -0,0 +1,14 @@
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 java.util.List;
public interface TeacherScoreService {
List<SchoolClass> listOwnedClasses(JwtUser teacher);
SchoolClass requireOwnedClass(JwtUser teacher, String teachingClassId);
TeachingClassScoreWeight getOrCreateWeight(JwtUser teacher, String teachingClassId);
TeachingClassScoreWeight saveWeight(JwtUser teacher, String teachingClassId, TeachingClassScoreWeight weight);
}

@ -36,6 +36,14 @@ public class ScoreRankServiceImpl implements ScoreRankService {
@Autowired
TeachingClassStudentMapper teachingClassStudentMapper;
@Autowired(required = false)
TaskAllocationMapper taskAllocationMapper;
@Autowired(required = false)
TrainingTaskMapper trainingTaskMapper;
@Autowired(required = false)
StudentTrainingAnswerMapper studentTrainingAnswerMapper;
@Autowired(required = false)
TeachingClassScoreWeightMapper teachingClassScoreWeightMapper;
@Autowired(required = false)
JdbcTemplate jdbcTemplate;
private volatile boolean stuRankIndexesChecked = false;
@ -235,6 +243,12 @@ public class ScoreRankServiceImpl implements ScoreRankService {
String nowDate = getNowDate();
scoreRank.setUpdateTime(nowDate);
if (overrideClass != null && hasSixModuleScoreDependencies()) {
scoreRank.setScore(calculateSixModuleScore(userId, overrideClass.getSchoolClassId()));
scoreRankList.add(scoreRank);
continue;
}
//设置分数
StuGradeExample stuGradeExample = new StuGradeExample();
stuGradeExample.createCriteria().andUserIdEqualTo(userId);
@ -304,6 +318,64 @@ public class ScoreRankServiceImpl implements ScoreRankService {
}
}
private boolean hasSixModuleScoreDependencies() {
return taskAllocationMapper != null && trainingTaskMapper != null
&& studentTrainingAnswerMapper != null && teachingClassScoreWeightMapper != null;
}
private BigDecimal calculateSixModuleScore(String userId, String teachingClassId) {
TeachingClassScoreWeight weight = teachingClassScoreWeightMapper.selectByTeachingClassId(teachingClassId);
if (weight == null) {
weight = sixModuleDefaults(teachingClassId);
teachingClassScoreWeightMapper.insert(weight);
}
TaskAllocationExample allocationExample = new TaskAllocationExample();
allocationExample.createCriteria().andClassIdEqualTo(teachingClassId);
List<TaskAllocation> allocations = taskAllocationMapper.selectByExample(allocationExample);
Map<String, List<Integer>> scoresByProject = new HashMap<>();
for (TaskAllocation allocation : allocations == null ? Collections.<TaskAllocation>emptyList() : allocations) {
if (allocation.getDisabledStatus() != null && allocation.getDisabledStatus() == 1
|| TaskAllocation.PUBLICATION_MARKER.equals(allocation.getModule())) {
continue;
}
TrainingTask task = trainingTaskMapper.selectByTaskKey(allocation.getModule());
if (task == null || task.getProjectName() == null) {
continue;
}
StudentTrainingAnswer answer = studentTrainingAnswerMapper.selectByStudentClassAndTask(userId, teachingClassId, task.getId());
scoresByProject.computeIfAbsent(task.getProjectName(), key -> new ArrayList<>())
.add(answer == null || answer.getAiAssessmentScore() == null ? 0 : answer.getAiAssessmentScore());
}
return projectAverage(scoresByProject, "互联网产品开发基础认知").multiply(weight.getFoundationWeight())
.add(projectAverage(scoresByProject, "市场洞察与需求分析").multiply(weight.getMarketInsightWeight()))
.add(projectAverage(scoresByProject, "产品规划与设计").multiply(weight.getPlanningDesignWeight()))
.add(projectAverage(scoresByProject, "产品开发与测试验证").multiply(weight.getDevelopmentValidationWeight()))
.add(projectAverage(scoresByProject, "产品上线与运营推广").multiply(weight.getLaunchOperationWeight()))
.add(projectAverage(scoresByProject, "综合实训").multiply(weight.getComprehensiveTrainingWeight()))
.setScale(2, BigDecimal.ROUND_HALF_UP);
}
private BigDecimal projectAverage(Map<String, List<Integer>> scoresByProject, String project) {
List<Integer> values = scoresByProject.get(project);
if (values == null || values.isEmpty()) {
return BigDecimal.ZERO;
}
BigDecimal sum = values.stream().map(BigDecimal::valueOf).reduce(BigDecimal.ZERO, BigDecimal::add);
return sum.divide(BigDecimal.valueOf(values.size()), 4, BigDecimal.ROUND_HALF_UP);
}
private TeachingClassScoreWeight sixModuleDefaults(String teachingClassId) {
TeachingClassScoreWeight weight = new TeachingClassScoreWeight();
weight.setTeachingClassId(teachingClassId);
weight.setFoundationWeight(new BigDecimal("0.10"));
weight.setMarketInsightWeight(new BigDecimal("0.30"));
weight.setPlanningDesignWeight(new BigDecimal("0.10"));
weight.setDevelopmentValidationWeight(new BigDecimal("0.10"));
weight.setLaunchOperationWeight(new BigDecimal("0.20"));
weight.setComprehensiveTrainingWeight(new BigDecimal("0.20"));
return weight;
}
//获取当天时间

@ -0,0 +1,111 @@
package com.sztzjy.linkCommerce.service.impl;
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.SchoolClassExample;
import com.sztzjy.linkCommerce.entity.TeachingClassScoreWeight;
import com.sztzjy.linkCommerce.mapper.SchoolClassMapper;
import com.sztzjy.linkCommerce.mapper.TeachingClassScoreWeightMapper;
import com.sztzjy.linkCommerce.service.TeacherScoreService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
@Service
public class TeacherScoreServiceImpl implements TeacherScoreService {
@Autowired
SchoolClassMapper schoolClassMapper;
@Autowired(required = false)
TeachingClassScoreWeightMapper weightMapper;
@Override
public List<SchoolClass> listOwnedClasses(JwtUser teacher) {
requireTeacher(teacher);
SchoolClassExample example = new SchoolClassExample();
example.createCriteria().andSchoolIdEqualTo(teacher.getSchoolId())
.andCreatedByEqualTo(teacher.getUserId()).andClassTypeEqualTo("TEACHING");
List<SchoolClass> rows = schoolClassMapper.selectByExample(example);
return rows == null ? Collections.emptyList() : rows;
}
@Override
public SchoolClass requireOwnedClass(JwtUser teacher, String teachingClassId) {
requireTeacher(teacher);
if (StringUtils.isBlank(teachingClassId)) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "请选择自己的教学班");
}
SchoolClass schoolClass = schoolClassMapper.selectByPrimaryKey(teachingClassId);
if (schoolClass == null || !"TEACHING".equals(schoolClass.getClassType())
|| !StringUtils.equals(teacher.getSchoolId(), schoolClass.getSchoolId())
|| !StringUtils.equals(teacher.getUserId(), schoolClass.getCreatedBy())) {
throw new ServiceException(HttpStatus.FORBIDDEN, "无权访问该教学班成绩");
}
return schoolClass;
}
@Override
public TeachingClassScoreWeight getOrCreateWeight(JwtUser teacher, String teachingClassId) {
requireOwnedClass(teacher, teachingClassId);
TeachingClassScoreWeight existing = weightMapper == null ? null : weightMapper.selectByTeachingClassId(teachingClassId);
if (existing != null) {
return existing;
}
TeachingClassScoreWeight defaults = defaultWeight(teachingClassId);
if (weightMapper != null) {
weightMapper.insert(defaults);
}
return defaults;
}
@Override
public TeachingClassScoreWeight saveWeight(JwtUser teacher, String teachingClassId, TeachingClassScoreWeight weight) {
requireOwnedClass(teacher, teachingClassId);
if (weight == null || !isOneHundredPercent(weight)) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "六项权重合计必须为100%");
}
weight.setTeachingClassId(teachingClassId);
TeachingClassScoreWeight current = weightMapper == null ? null : weightMapper.selectByTeachingClassId(teachingClassId);
if (weightMapper != null) {
if (current == null) {
weightMapper.insert(weight);
} else {
weightMapper.update(weight);
}
}
return weight;
}
private TeachingClassScoreWeight defaultWeight(String teachingClassId) {
TeachingClassScoreWeight weight = new TeachingClassScoreWeight();
weight.setTeachingClassId(teachingClassId);
weight.setFoundationWeight(new BigDecimal("0.10"));
weight.setMarketInsightWeight(new BigDecimal("0.30"));
weight.setPlanningDesignWeight(new BigDecimal("0.10"));
weight.setDevelopmentValidationWeight(new BigDecimal("0.10"));
weight.setLaunchOperationWeight(new BigDecimal("0.20"));
weight.setComprehensiveTrainingWeight(new BigDecimal("0.20"));
return weight;
}
private boolean isOneHundredPercent(TeachingClassScoreWeight weight) {
BigDecimal sum = safe(weight.getFoundationWeight()).add(safe(weight.getMarketInsightWeight()))
.add(safe(weight.getPlanningDesignWeight())).add(safe(weight.getDevelopmentValidationWeight()))
.add(safe(weight.getLaunchOperationWeight())).add(safe(weight.getComprehensiveTrainingWeight()));
return BigDecimal.ONE.compareTo(sum) == 0;
}
private BigDecimal safe(BigDecimal value) { return value == null ? BigDecimal.ZERO : value; }
private void requireTeacher(JwtUser teacher) {
if (teacher == null || StringUtils.isBlank(teacher.getUserId()) || StringUtils.isBlank(teacher.getSchoolId())
|| (teacher.getRoleId() != 1 && teacher.getRoleId() != 3)) {
throw new ServiceException(HttpStatus.FORBIDDEN, "仅教师可访问成绩中心");
}
}
}

@ -42,6 +42,13 @@
limit 1
</select>
<select id="selectByStudentAndTeachingClass" resultMap="BaseResultMap">
select <include refid="Base_Column_List" />
from student_training_answer
where student_user_id = #{studentUserId,jdbcType=VARCHAR}
and teaching_class_id = #{teachingClassId,jdbcType=VARCHAR}
</select>
<delete id="deleteByStudentClassAndTask">
delete from student_training_answer
where student_user_id = #{studentUserId,jdbcType=VARCHAR}

@ -0,0 +1,17 @@
<?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.TeachingClassScoreWeightMapper">
<resultMap id="WeightMap" type="com.sztzjy.linkCommerce.entity.TeachingClassScoreWeight">
<id column="teaching_class_id" property="teachingClassId" />
<result column="foundation_weight" property="foundationWeight" />
<result column="market_insight_weight" property="marketInsightWeight" />
<result column="planning_design_weight" property="planningDesignWeight" />
<result column="development_validation_weight" property="developmentValidationWeight" />
<result column="launch_operation_weight" property="launchOperationWeight" />
<result column="comprehensive_training_weight" property="comprehensiveTrainingWeight" />
</resultMap>
<sql id="Columns">teaching_class_id, foundation_weight, market_insight_weight, planning_design_weight, development_validation_weight, launch_operation_weight, comprehensive_training_weight</sql>
<select id="selectByTeachingClassId" resultMap="WeightMap">select <include refid="Columns" /> from teaching_class_score_weight where teaching_class_id = #{teachingClassId}</select>
<insert id="insert">insert into teaching_class_score_weight (<include refid="Columns" />) values (#{teachingClassId}, #{foundationWeight}, #{marketInsightWeight}, #{planningDesignWeight}, #{developmentValidationWeight}, #{launchOperationWeight}, #{comprehensiveTrainingWeight})</insert>
<update id="update">update teaching_class_score_weight set foundation_weight=#{foundationWeight}, market_insight_weight=#{marketInsightWeight}, planning_design_weight=#{planningDesignWeight}, development_validation_weight=#{developmentValidationWeight}, launch_operation_weight=#{launchOperationWeight}, comprehensive_training_weight=#{comprehensiveTrainingWeight} where teaching_class_id=#{teachingClassId}</update>
</mapper>

@ -0,0 +1,42 @@
package com.sztzjy.linkCommerce.controller.stu;
import com.sztzjy.linkCommerce.config.security.JwtUser;
import com.sztzjy.linkCommerce.entity.SchoolClass;
import com.sztzjy.linkCommerce.service.TeacherScoreService;
import com.sztzjy.linkCommerce.util.ResultEntity;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.util.ReflectionTestUtils;
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.when;
class TeaScoreControllerScopeTest {
@Test
void ownedTeachingClassesUsesAuthenticatedTeacher() {
TeaScoreController controller = new TeaScoreController() {
@Override
protected JwtUser currentUser(javax.servlet.http.HttpServletRequest request) {
JwtUser teacher = new JwtUser();
teacher.setUserId("teacher-1");
teacher.setSchoolId("school-1");
teacher.setRoleId(3);
return teacher;
}
};
TeacherScoreService service = mock(TeacherScoreService.class);
ReflectionTestUtils.setField(controller, "teacherScoreService", service);
SchoolClass owned = new SchoolClass();
owned.setSchoolClassId("class-1");
when(service.listOwnedClasses(any())).thenReturn(Collections.singletonList(owned));
ResultEntity<?> result = controller.ownedTeachingClasses(new MockHttpServletRequest());
assertEquals(HttpStatus.OK, result.getStatusCode());
}
}

@ -0,0 +1,68 @@
package com.sztzjy.linkCommerce.service.impl;
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.mapper.SchoolClassMapper;
import com.sztzjy.linkCommerce.mapper.TeachingClassScoreWeightMapper;
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.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class TeacherScoreServiceImplTest {
@Test
void createsSixModuleDefaultsOnlyForOwnedTeachingClass() {
TeacherScoreServiceImpl service = new TeacherScoreServiceImpl();
SchoolClassMapper classMapper = mock(SchoolClassMapper.class);
TeachingClassScoreWeightMapper weightMapper = mock(TeachingClassScoreWeightMapper.class);
ReflectionTestUtils.setField(service, "schoolClassMapper", classMapper);
ReflectionTestUtils.setField(service, "weightMapper", weightMapper);
when(classMapper.selectByPrimaryKey("class-1")).thenReturn(classRow("class-1", "teacher-1", "school-1"));
TeachingClassScoreWeight weight = service.getOrCreateWeight(teacher("teacher-1", "school-1"), "class-1");
assertEquals(new java.math.BigDecimal("0.10"), weight.getFoundationWeight());
assertEquals(new java.math.BigDecimal("0.30"), weight.getMarketInsightWeight());
assertEquals(new java.math.BigDecimal("0.10"), weight.getPlanningDesignWeight());
assertEquals(new java.math.BigDecimal("0.10"), weight.getDevelopmentValidationWeight());
assertEquals(new java.math.BigDecimal("0.20"), weight.getLaunchOperationWeight());
assertEquals(new java.math.BigDecimal("0.20"), weight.getComprehensiveTrainingWeight());
}
@Test
void rejectsForeignTeachingClass() {
TeacherScoreServiceImpl service = new TeacherScoreServiceImpl();
SchoolClassMapper classMapper = mock(SchoolClassMapper.class);
ReflectionTestUtils.setField(service, "schoolClassMapper", classMapper);
when(classMapper.selectByPrimaryKey("class-2")).thenReturn(classRow("class-2", "teacher-2", "school-1"));
ServiceException error = assertThrows(ServiceException.class,
() -> service.requireOwnedClass(teacher("teacher-1", "school-1"), "class-2"));
assertEquals(HttpStatus.FORBIDDEN, error.getCode());
}
private JwtUser teacher(String userId, String schoolId) {
JwtUser user = new JwtUser();
user.setUserId(userId);
user.setSchoolId(schoolId);
user.setRoleId(3);
return user;
}
private SchoolClass classRow(String id, String createdBy, String schoolId) {
SchoolClass row = new SchoolClass();
row.setSchoolClassId(id);
row.setCreatedBy(createdBy);
row.setSchoolId(schoolId);
row.setClassType("TEACHING");
return row;
}
}
Loading…
Cancel
Save