update 报告相关算法更新以及评价得批量操作

develop
hhb@hotmail.com 1 month ago
parent aef11a583c
commit c6c301c532

@ -233,7 +233,7 @@ public class LaborEducationServiceImpl implements LaborEducationService {
List<RecordVo> res;
try {
exams = examRepository.findExamByClassId(String.format(PK.EXAM, findDto.getTmdId()), findDto.getClassId(), findDto.getPeriodId(), findDto.getSubjectId());
res= appraiseRecordRepository.getRecords(String.format(PK.PK_APPRAISE_RECORD, findDto.getCode()),findDto.getAcademicYearId(), findDto.getClassId(), findDto.getStudentId());
res= appraiseRecordRepository.getRecords(String.format(PK.PK_APPRAISE_RECORD, findDto.getCode()),findDto.getAcademicYearId(), findDto.getClassId(), findDto.getStudentId(),"德育");
resMap.put("exams",exams);
resMap.put("res", res);
}catch (Exception e){
@ -1404,6 +1404,7 @@ public Map<String,List<Map<String, Object>>> getStudentMonthlyScores(LaborDto la
if (laborDto.getClassId() == null) {
res = appraiseRecordRepository.getStudentRecords(
String.format(PK.PK_APPRAISE_RECORD, schoolId),
laborDto.getAcademicYearId(),
laborDto.getStudentId(),
laborDto.getStartTime(),
laborDto.getEndTime(),
@ -1441,13 +1442,12 @@ public Map<String,List<Map<String, Object>>> getStudentMonthlyScores(LaborDto la
.findFirst()
.map(RGroupList::getName)
.orElse("未知班级"); // 如果未找到则返回默认值 "未知班级"*/
res = appraiseRecordRepository.latestRecords(
res = appraiseRecordRepository.getRecords(
String.format(PK.PK_APPRAISE_RECORD, schoolId),
laborDto.getAcademicYearId(),
laborDto.getStartTime(),
laborDto.getEndTime(),
"德育",
classIds
laborDto.getClassId(),
laborDto.getStudentId(),
"德育"
);
//表扬的次数
rightCount = (int) res.stream().filter(RecordVo::isPraise).count();

@ -231,7 +231,7 @@ public class MoralEducationServiceImpl implements MoralEducationService {
List<RecordVo> res;
try {
exams = examRepository.findExamByClassId(String.format(PK.EXAM, findDto.getTmdId()), findDto.getClassId(), findDto.getPeriodId(), findDto.getSubjectId());
res= appraiseRecordRepository.getRecords(String.format(PK.PK_APPRAISE_RECORD, findDto.getCode()),findDto.getAcademicYearId(), findDto.getClassId(), findDto.getStudentId());
res= appraiseRecordRepository.getRecords(String.format(PK.PK_APPRAISE_RECORD, findDto.getCode()),findDto.getAcademicYearId(), findDto.getClassId(), findDto.getStudentId(),"劳育");
resMap.put("exams",exams);
resMap.put("res", res);
}catch (Exception e){
@ -1342,6 +1342,7 @@ public class MoralEducationServiceImpl implements MoralEducationService {
if (laborDto.getClassId() == null) {
res = appraiseRecordRepository.getStudentRecords(
String.format(PK.PK_APPRAISE_RECORD, schoolId),
laborDto.getAcademicYearId(),
laborDto.getStudentId(),
laborDto.getStartTime(),
laborDto.getEndTime(),
@ -1379,13 +1380,12 @@ public class MoralEducationServiceImpl implements MoralEducationService {
.findFirst()
.map(RGroupList::getName)
.orElse("未知班级"); // 如果未找到则返回默认值 "未知班级"*/
res = appraiseRecordRepository.latestRecords(
res = appraiseRecordRepository.getRecords(
String.format(PK.PK_APPRAISE_RECORD, schoolId),
laborDto.getAcademicYearId(),
laborDto.getStartTime(),
laborDto.getEndTime(),
"劳育",
classIds
laborDto.getClassId(),
laborDto.getStudentId(),
"德育"
);
//表扬的次数
rightCount = (int) res.stream().filter(RecordVo::isPraise).count();

@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* @author winter
@ -13,7 +14,7 @@ import javax.validation.constraints.NotNull;
public class AppraiseVoteDto {
@NotNull
@ApiModelProperty(value = "评价对象 Id")
private String targetId;
private List<String> targetIds;
@NotNull
@ApiModelProperty(value = "评价对象类型:", allowableValues = "student ,class")
@ -25,11 +26,11 @@ public class AppraiseVoteDto {
@ApiModelProperty(value = "是否推送给家长(评价 STUDENT 时生效)")
private boolean pushParent;
/**
* id
* id
*/
@NotNull
@ApiModelProperty(value = "评价项唯一 id", required = true)
private String appraiseId;
private List<String> appraiseIds;
@ApiModelProperty(value = "评价来源")
private String device;
}

@ -88,21 +88,23 @@ public interface AppraiseRecordRepository extends CosmosRepository<AppraiseRecor
*/
@Query("select c.id as recordId, c.name as targetName, c.avatar, c.classId,c.className, n.id as recordNodeId, c.targetId, c.targetType, n.creator, n.createTime, n.appraiseNode.name as appraiseName, n.appraiseNode.isPraise, n.device,n.appraiseNode.path from Student as c join n in c.nodes where " +
"c.code = @code and " +
"c.academicYearId = @academicYearId and " +
"c.targetId = @studentId and " +
"(IS_NULL(@startTime) or n.createTime >= @startTime) and " +
"(IS_NULL(@endTime) or n.createTime <= @endTime) and " +
"(IS_NULL(@typeName) or array_contains(n.appraiseNode.path ,@typeName)) "
)
List<RecordVo> getStudentRecords(String code, String studentId, Long startTime, Long endTime,String typeName);
List<RecordVo> getStudentRecords(String code,String academicYearId ,String studentId, Long startTime, Long endTime,String typeName);
@Query("select c.id as recordId, c.name as targetName, c.avatar, c.classId,c.className, n.id as recordNodeId, c.targetId, c.targetType, n.creator, n.createTime, n.appraiseNode.name as appraiseName, n.appraiseNode.isPraise, n.device,n.appraiseNode.path from Student as c join n in c.nodes where " +
"c.code = @code and " +
"c.academicYearId = @academicYearId and " +
"c.classId = @classId and " +
"c.targetId = @studentId "
"(IS_NULL(@studentId) or c.targetId = @studentId) and " +
"(IS_NULL(@typeName) or array_contains(n.appraiseNode.path ,@typeName)) "
)
List<RecordVo> getRecords(String code, String academicYearId, String classId,String studentId);
List<RecordVo> getRecords(String code, String academicYearId, String classId,String studentId,String typeName);
@Query("select c.classId as id, count(1) as count from Student as c join n in c.nodes where( " +

@ -33,8 +33,8 @@ public interface AppraiseRepository extends CosmosRepository<Appraise, String> {
List<Appraise> findTemplateTree();
@Query("SELECT value n FROM School AS s join n in s.nodes where s.code = @code and n.id = @nodeId and s.periodId = @periodId")
List<AppraiseTreeNode> findNodeById(@Param("code") String code, @Param("nodeId") String nodeId,@Param("periodId") String periodId);
@Query("select n.id, n.name from School as c join n in c.nodes where c.code = @code and n.id in (@ids)")
List<AppraiseTreeNode> findAllByCodeAndIdIn(String code, Set<String> ids);
@Query("select value n from School as c join n in c.nodes where c.code = @code and n.id in (@ids) and c.periodId = @periodId")
List<AppraiseTreeNode> findAllByCodeAndIdIn(String code, Set<String> ids,String periodId);
@Query("SELECT c.id, c.achievementRules FROM School AS c where c.code = 'Appraise' and c.schoolId = @schoolId and c.periodId = @periodId")
List<Appraise> findRulesById(String schoolId, String periodId);
}

@ -18,7 +18,7 @@ public interface StudentRepository extends CosmosRepository<Student, String> {
@Query("select c.pk, c.code, c.id, c.name, c.gender, c.schoolId, c.periodId, c.year, c.createTime, c.picture, c.mail, c.mobile, c.country, c.classId, c.no, c.groupId, c.groupName, c.guardians, c.irs, c.salt from Student as c where c.id = @id and c.code = @code")
List<Student> findByIdAndCode(String id, String code);
@Query("select c.id, c.name, c.classId, c.picture, c.periodId from Student as c where c.code = @code and c.id in (@ids)")
@Query("select c.pk, c.code, c.id, c.name, c.gender, c.schoolId, c.periodId, c.year, c.createTime, c.picture, c.mail, c.mobile, c.country, c.classId, c.no, c.groupId, c.groupName, c.guardians, c.irs, c.salt from Student as c where c.code = @code and c.id in (@ids)")
List<Student> findAllByCodeAndIdIn(String code, Set<String> ids);
int countByClassIdAndCode(String classId, String code);

@ -30,6 +30,7 @@ import com.azure.spring.data.cosmos.core.query.CosmosPageRequest;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import lombok.Data;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.jfree.chart.ChartUtils;
@ -41,6 +42,7 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
@ -313,124 +315,178 @@ public class EvaluationServiceImpl implements EvaluationService {
return buildTree(appraiseRepository.save(appraise));
}
// 定义辅助类(可选)
@Data
private static class TargetInfo {
private String classId;
private String className;
private String periodId;
private String name;
private String avatar;
private String gender;
public TargetInfo(Student student) {
this.classId = student.getClassId();
this.periodId = student.getPeriodId();
this.name = student.getName();
this.avatar = student.getPicture();
this.gender = student.getGender();
}
public TargetInfo(ClassInfo classInfo) {
this.classId = classInfo.getId();
this.className = classInfo.getName();
this.periodId = classInfo.getPeriodId();
this.name = classInfo.getName();
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void vote(AppraiseVoteDto appraiseVoteDto) {
String targetId = appraiseVoteDto.getTargetId();
// 1. 获取基础参数
List<String> targetIds = appraiseVoteDto.getTargetIds();
List<String> appraiseIds = appraiseVoteDto.getAppraiseIds();
boolean spread = appraiseVoteDto.isSpread();
boolean pushParent = appraiseVoteDto.isPushParent();
String targetType = appraiseVoteDto.getTargetType();
String appraiseId = appraiseVoteDto.getAppraiseId();
String from = appraiseVoteDto.getDevice();
User loginUser = SecurityUtil.getLoginUser();
String schoolId = loginUser.getSchoolId();
String classId;
String className;
String periodId;
String name;
String avatar = null;
String gender = null;
// 分别对班级和学生的关键信息取值
// 2. 参数校验
if (targetIds == null || targetIds.isEmpty()) {
throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "目标ID列表不能为空");
}
if (appraiseIds == null || appraiseIds.isEmpty()) {
throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "评价项ID列表不能为空");
}
// 3. 批量查询目标信息
Map<String, TargetInfo> targetInfoMap = getTargetInfos(targetIds, targetType, schoolId);
// 4. 处理每个目标
for (String targetId : targetIds) {
TargetInfo targetInfo = targetInfoMap.get(targetId);
processSingleTarget(
targetId, targetInfo, appraiseIds, spread, pushParent, targetType,
schoolId, loginUser, from
);
}
}
private Map<String, TargetInfo> getTargetInfos(List<String> targetIds, String targetType, String schoolId) {
if (targetType.equals(TARGET_STUDENT)) {
List<Student> list = studentRepository.findByIdAndCode(targetId, String.format(PK.STUDENT, schoolId));
Student student = RepositoryUtil.findOne(list, "该学生不存在");
classId = student.getClassId();
periodId = student.getPeriodId();
name = student.getName();
avatar = student.getPicture();
gender = student.getGender();
// 获取班级信息
ClassInfo classInfo = classRepository.findClassByIdAndCode(classId, String.format(PK.CLASS, schoolId));
className = classInfo.getName();
Set<String> targetIdsSet = new HashSet<>(targetIds);
List<Student> students = studentRepository.findAllByCodeAndIdIn(String.format(PK.STUDENT, schoolId),targetIdsSet);
return students.stream().collect(Collectors.toMap(Student::getId, TargetInfo::new));
} else if (targetType.equals(TARGET_CLASS)) {
ClassInfo classInfo = classRepository.findClassByIdAndCode(targetId, String.format(PK.CLASS, schoolId));
if (classInfo == null) {
throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "班级不存在");
}
classId = targetId;
periodId = classInfo.getPeriodId();
name = classInfo.getName();
className = classInfo.getName();
List<ClassInfo> classes = classRepository.findAllByCodeAndIdIn(String.format(PK.CLASS, schoolId), targetIds);
return classes.stream().collect(Collectors.toMap(ClassInfo::getId, TargetInfo::new));
} else {
throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "不受支持的评价对象");
throw new ServiceException("不受支持的评价对象类型");
}
// 获取评价项节点
List<AppraiseTreeNode> nodes = appraiseRepository.findNodeById(PK.PK_APPRAISE, appraiseId,periodId);
AppraiseTreeNode appraiseTreeNode = RepositoryUtil.findOne(nodes, "该评价项不存在");
if (appraiseTreeNode.getPath() == null) {
throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "仅能评价三级评价项");
}
// 通过 periodId 获取 semesters
List<School.Period> periodById = schoolRepository.findPeriodById(schoolId, periodId);
private void processSingleTarget(
String targetId, TargetInfo targetInfo, List<String> appraiseIds,
boolean spread, boolean pushParent, String targetType,
String schoolId, User loginUser, String from
) {
// 1. 获取学段和学年学期信息
List<School.Period> periodById = schoolRepository.findPeriodById(schoolId, targetInfo.getPeriodId());
School.Period period = RepositoryUtil.findOne(periodById, "获取学段失败");
List<School.Semester> semesters = period.getSemesters();
// 获取当前学年学期组合 ID
String academicYearId = SchoolDateUtil.calculateAcademicYearId(semesters, LocalDate.now());
// 查询是否存在记录
AppraiseRecord record = appraiseRecordRepository.findAppraiseRecordByTargetIdAndClassIdAndAcademicYearIdAndCode(
targetId,
classId,
academicYearId,
String.format(PK.PK_APPRAISE_RECORD, schoolId)
);
// 2. 批量查询评价项节点
Set<String> appraiseIdsSet = new HashSet<>(appraiseIds);
List<AppraiseTreeNode> allNodes = appraiseRepository.findAllByCodeAndIdIn(PK.PK_APPRAISE, appraiseIdsSet, targetInfo.getPeriodId());
Map<String, AppraiseTreeNode> nodeMap = allNodes.stream()
.collect(Collectors.toMap(AppraiseTreeNode::getId, node -> node));
// 3. 校验评价项有效性
for (String appraiseId : appraiseIds) {
AppraiseTreeNode node = nodeMap.get(appraiseId);
//RepositoryUtil.findOne(nodeMap, "获取评价项失败: " + appraiseId)
if (node == null) {
throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "评价项不存在: " + appraiseId);
}
if (node.getPath() == null) {
throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "仅能评价三级评价项: " + appraiseId);
}
}
// 初始化新的评价节点
// 4. 构建评价记录项并统计值
int totalPraise = 0;
int totalCriticize = 0;
int totalScoreIncrement = 0;
List<AppraiseRecordItem> items = new ArrayList<>();
for (String appraiseId : appraiseIds) {
AppraiseTreeNode node = nodeMap.get(appraiseId);
AppraiseRecordItem item = new AppraiseRecordItem();
item.setId(UUID.randomUUID().toString());
item.setAppraiseNode(appraiseTreeNode);
item.setAppraiseNode(node);
item.setCreator(loginUser.getName());
item.setCreatorId(loginUser.getId());
item.setCreateTime(Instant.now().toEpochMilli());
item.setDevice(from);
// 处理学校与学生的差异
if (targetType.equals(TARGET_CLASS)) {
if (TARGET_CLASS.equals(targetType)) {
item.setSpread(spread);
} else {
item.setPushParent(pushParent);
}
items.add(item);
// 不存在或者学生的班级不一样则创建一条新的,存在则处理一下分值后再向其 nodes 中插入一条 item
if (record == null || !classId.equals(record.getClassId())) {
List<AppraiseRecordItem> items = Collections.singletonList(item);
if (node.isPraise()) {
totalPraise++;
totalScoreIncrement += 1;
} else {
totalCriticize++;
totalScoreIncrement -= 1;
}
}
// 5. 创建或更新评价记录
String classId = targetInfo.getClassId();
AppraiseRecord record = appraiseRecordRepository.findAppraiseRecordByTargetIdAndClassIdAndAcademicYearIdAndCode(
targetId, classId, academicYearId, String.format(PK.PK_APPRAISE_RECORD, schoolId)
);
if (record == null || !classId.equals(record.getClassId())) {
record = new AppraiseRecord();
record.setTargetId(targetId);
record.setTargetType(targetType);
record.setClassId(classId);
record.setClassName(className);
record.setName(name);
record.setAvatar(avatar);
record.setGender(gender);
record.setClassName(targetInfo.getClassName());
record.setName(targetInfo.getName());
record.setAvatar(targetInfo.getAvatar());
record.setGender(targetInfo.getGender());
record.setAcademicYearId(academicYearId);
record.setPraiseCount(appraiseTreeNode.isPraise() ? 1 : 0);
record.setCriticizeCount(appraiseTreeNode.isPraise() ? 0 : 1);
record.setScore(appraiseTreeNode.isPraise() ? 1 : 0);
record.setPraiseCount(totalPraise);
record.setCriticizeCount(totalCriticize);
record.setScore(Math.max(totalScoreIncrement, 0));
record.setNodes(items);
record.setCode(String.format(PK.PK_APPRAISE_RECORD, schoolId));
appraiseRecordRepository.save(record);
} else {
CosmosPatchOperations operations = CosmosPatchOperations.create();
for (AppraiseRecordItem item : items) {
operations.add("/nodes/-", item);
// 表扬 (待改进不会减少表扬数)
if (appraiseTreeNode.isPraise()) {
operations.increment("/praiseCount", 1);
}else {
operations.increment("/criticizeCount", 1);
}
// 加分
//nt scoreToPlus = ObjectUtils.isEmpty(appraiseTreeNode.getScore()) ? 0 : appraiseTreeNode.getScore();
int incrementValue = appraiseTreeNode.isPraise() ? 1 : -1;
if (record.getScore() + incrementValue < 0) {
operations.set("/score", 0);
}else {
operations.increment("/score", incrementValue);
}
// patch doc
operations.increment("/praiseCount", totalPraise);
operations.increment("/criticizeCount", totalCriticize);
int newScore = record.getScore() + totalScoreIncrement;
operations.set("/score", Math.max(newScore, 0));
appraiseRecordRepository.save(record.getId(), PK.buildOf(PK.PK_APPRAISE_RECORD, schoolId), AppraiseRecord.class, operations);
}
}

Loading…
Cancel
Save