新增评价学生或班级接口

11111
winter 1 year ago
parent 6dffd636ec
commit 29d21f0233

@ -0,0 +1,9 @@
package cn.teammodel.common;
/**
* @author winter
* @create 2023-11-29 14:26
*/
public interface CommonConstant {
String DASH = "-";
}

@ -17,6 +17,7 @@ public interface PK {
* : 1 , : SchoolId
*/
String PK_APPRAISE_RECORD = "AppraiseRecord-%s";
String COMMON_BASE = "Base";
/**
*

@ -1,6 +1,6 @@
package cn.teammodel.dao;
import cn.teammodel.model.entity.appraise.Appraise;
import cn.teammodel.model.entity.appraise.AppraiseRecord;
import com.azure.spring.data.cosmos.repository.CosmosRepository;
import org.springframework.stereotype.Repository;
@ -15,6 +15,10 @@ import org.springframework.stereotype.Repository;
* List<User> findByLastname(String lastname, Pageable pageable);<br/>
*/
@Repository
public interface AppraiseRecordRepository extends CosmosRepository<Appraise, String> {
public interface AppraiseRecordRepository extends CosmosRepository<AppraiseRecord, String> {
/**
*
*/
AppraiseRecord findAppraiseRecordByTargetIdAndAcademicYearIdAndCode(String targetId, String academicYearId, String code);
}

@ -24,7 +24,7 @@ import java.util.List;
public interface AppraiseRepository extends CosmosRepository<Appraise, String> {
Appraise findBySchoolId(String schoolId, PartitionKey partitionKey);
Appraise findAppraiseBySchoolIdAndPeriodIdAndCode(String schoolId, String periodId, String code);
@Query("SELECT value n FROM School AS s join n in s.nodes where s.schoolId = @schoolId and s.periodId = @periodId and s.code = @code and n.id = @nodeId")
List<AppraiseTreeNode> findNodeById(@Param("schoolId") String schoolId, @Param("periodId") String periodId, @Param("code") String code, @Param("nodeId") String nodeId);
@Query("SELECT value n FROM School AS s join n in s.nodes where s.code = @code and n.id = @nodeId")
List<AppraiseTreeNode> findNodeById(@Param("code") String code, @Param("nodeId") String nodeId);
}

@ -2,14 +2,21 @@ package cn.teammodel.dao;
import cn.teammodel.model.entity.school.School;
import com.azure.spring.data.cosmos.repository.CosmosRepository;
import com.azure.spring.data.cosmos.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @author winter
* @create 2023-11-28 17:39
*/
@Repository
public interface SchoolRepository extends CosmosRepository<School, String> {
//@Query("select c.period.semesters from c where c.id = @id and c.code = @code")
//List<School.Semester> findSemestersById(@Param("id") String id, @Param("code") String code);
/**
* , ,
*/
@Query("select value p from School as s join p in s.period where s.id = @schoolId and s.code = 'Base' and p.id = @periodId")
List<School.Period> findPeriodById(@Param("schoolId") String schoolId, @Param("periodId") String periodId);
}

@ -1,5 +1,6 @@
package cn.teammodel.model.dto.Appraise;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@ -11,11 +12,23 @@ import javax.validation.constraints.NotNull;
@Data
public class AppraiseVoteDto {
@NotNull
private String studentId;
@NotNull // todo: semester 还是 period
private String semesterId;
@ApiModelProperty(value = "评价对象为班级 或 学生")
private String targetId;
@NotNull
@ApiModelProperty(value = "评价对象类型:", allowableValues = "student ,class")
private String targetType;
@ApiModelProperty(value = "评分是否传播到班级下的所有学生(字段仅在 targetType=class 时生效)")
private boolean spread;
/**
* id
*/
@NotNull
@ApiModelProperty(value = "评价项唯一 id", required = true)
private String appraiseId;
// 校区 id
@ApiModelProperty(value = "学段 id,用于拿到 semesterId", required = true)
@NotNull
private String periodId;
}

@ -10,7 +10,7 @@ import java.util.List;
/**
* (+ = ) <br/>
* : Id + semesterId
* : : academicYearId(-{semesterId}) + studentId + code(AppraiseRecord-{schoolId})
* @author winter
* @create 2023-11-27 11:02
*/
@ -23,7 +23,15 @@ public class AppraiseRecord extends BaseItem {
* id
*/
private String periodId;
private String studentId;
/**
* ( id: -semesterId -> 2023-{semesterId})
*/
private String academicYearId;
/**
* id
*/
private String targetId;
private String targetType;
/**
*
*/

@ -17,6 +17,10 @@ import java.time.LocalDateTime;
public class AppraiseRecordItem {
private String id;
private String appraiseNodeId;
/**
* , null
*/
private Boolean spread;
String creator;
String creatorId;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")

@ -3,8 +3,10 @@ package cn.teammodel.model.entity.school;
import cn.teammodel.model.entity.BaseItem;
import com.azure.spring.data.cosmos.core.mapping.Container;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.List;
@ -47,7 +49,16 @@ public class School extends BaseItem {
private List<String> grades;
private List<Subject> subjects;
private List<Semester> semesters;
private List<Semester> timetable;
private String name;
private String id;
private String gradeCount;
private String semesterCount;
private String subjectCount;
private String campusId;
private Analysis analysis;
// 学段类型
private String periodType;
}
@Data
@ -55,6 +66,26 @@ public class School extends BaseItem {
private String id;
private String name;
}
@Data
public static class Timetable {
private String id;
private String label;
private String time;
// todo: 待补充
//private String weeklies;
}
@Data
public static class Analysis {
private List<Type> type;
private Integer income;
private Integer eugenics;
private Integer touch;
}
@Data
public static class Type {
private String id;
private String name;
}
@Data
public static class Subject {
@ -66,13 +97,25 @@ public class School extends BaseItem {
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Semester {
private String id;
private String name;
/**
* start = 1
*/
private Integer start;
/**
*
*/
private Integer month;
/**
*
*/
private Integer day;
private String id;
}
@Data
public static class Campus {
private String name;

@ -1,30 +0,0 @@
package cn.teammodel.model.entity.school;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* ()
* @author winter
* @create 2023-11-28 10:39
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Semester {
private String id;
private String name;
/**
* start = 1
*/
private Integer start;
/**
*
*/
private Integer month;
/**
*
*/
private Integer day;
}

@ -4,13 +4,21 @@ import cn.hutool.core.lang.UUID;
import cn.teammodel.common.ErrorCode;
import cn.teammodel.common.PK;
import cn.teammodel.config.exception.ServiceException;
import cn.teammodel.dao.AppraiseRecordRepository;
import cn.teammodel.dao.AppraiseRepository;
import cn.teammodel.dao.SchoolRepository;
import cn.teammodel.model.dto.Appraise.*;
import cn.teammodel.model.entity.User;
import cn.teammodel.model.entity.appraise.Appraise;
import cn.teammodel.model.entity.appraise.AppraiseRecord;
import cn.teammodel.model.entity.appraise.AppraiseRecordItem;
import cn.teammodel.model.entity.appraise.AppraiseTreeNode;
import cn.teammodel.model.entity.User;
import cn.teammodel.model.entity.school.School;
import cn.teammodel.security.utils.SecurityUtil;
import cn.teammodel.service.EvaluationService;
import cn.teammodel.utils.RepositoryUtil;
import cn.teammodel.utils.SchoolDateUtil;
import com.azure.cosmos.models.CosmosPatchOperations;
import com.azure.spring.data.cosmos.core.CosmosTemplate;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
@ -18,8 +26,10 @@ import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@ -28,9 +38,18 @@ import java.util.List;
*/
@Service
public class EvaluationServiceImpl implements EvaluationService {
/**
*
*/
private final static String TARGET_STUDENT = "student";
private final static String TARGET_CLASS = "class";
@Resource
CosmosTemplate cosmosTemplate;
@Resource
private SchoolRepository schoolRepository;
@Resource
private AppraiseRecordRepository appraiseRecordRepository;
@Resource
private AppraiseRepository appraiseRepository;
/**
@ -98,6 +117,7 @@ public class EvaluationServiceImpl implements EvaluationService {
@Override
public Appraise insertNode(InsertNodeDto insertNodeDto) {
// todo: 如果不存在
Appraise appraise = findAppraise(insertNodeDto.getPeriodId());
User loginUser = SecurityUtil.getLoginUser();
@ -168,19 +188,74 @@ public class EvaluationServiceImpl implements EvaluationService {
@Override
public void vote(AppraiseVoteDto appraiseVoteDto) {
String studentId = appraiseVoteDto.getStudentId();
String targetId = appraiseVoteDto.getTargetId();
boolean spread = appraiseVoteDto.isSpread();
String targetType = appraiseVoteDto.getTargetType();
String appraiseId = appraiseVoteDto.getAppraiseId();
// 获取 school 中的 semesters
String periodId = appraiseVoteDto.getPeriodId();
periodId = StringUtils.isEmpty(periodId) ? "default" : periodId;
User loginUser = SecurityUtil.getLoginUser();
List<AppraiseTreeNode> nodes = appraiseRepository.findNodeById(loginUser.getSchoolId(), periodId, PK.PK_APPRAISE, appraiseId);
if (ObjectUtils.isEmpty(nodes) || nodes.size() > 1) {
throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "找不到该评价项");
}
AppraiseTreeNode node = nodes.get(0);
String schoolId = loginUser.getSchoolId();
// 组装 AppraiseRecord
List<AppraiseTreeNode> nodes = appraiseRepository.findNodeById(PK.PK_APPRAISE, appraiseId);
AppraiseTreeNode appraiseTreeNode = RepositoryUtil.findOne(nodes);
// 通过 periodId 获取 semesters
List<School.Period> periodById = schoolRepository.findPeriodById(schoolId, periodId);
School.Period period = RepositoryUtil.findOne(periodById);
List<School.Semester> semesters = period.getSemesters();
// 获取当前学年学期组合 ID
String academicYearId = SchoolDateUtil.generateAcademicId(semesters, LocalDate.now());
// 查询是否存在记录,不存在则创建一条新的,存在则处理一下分值后再向其 nodes 中插入一条 item
AppraiseRecord record = appraiseRecordRepository.findAppraiseRecordByTargetIdAndAcademicYearIdAndCode(
targetId,
academicYearId,
String.format(PK.PK_APPRAISE_RECORD,schoolId)
);
// 初始化新的评价节点
AppraiseRecordItem item = new AppraiseRecordItem();
item.setId(UUID.randomUUID().toString());
item.setAppraiseNodeId(appraiseId);
item.setCreator(loginUser.getName());
item.setCreatorId(loginUser.getId());
item.setCreateTime(LocalDateTime.now());
if (record == null) {
// 不存在, 创建新的 AppraiseRecord
List<AppraiseRecordItem> items = Collections.singletonList(item);
record = new AppraiseRecord();
if (targetType.equals(TARGET_STUDENT)) {
record.setTargetType(TARGET_STUDENT);
} else if (targetType.equals(TARGET_CLASS)){
record.setTargetType(TARGET_CLASS);
} else {
throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "不受支持的评价对象");
}
record.setTargetId(targetId);
record.setAcademicYearId(academicYearId);
record.setPraiseCount(0);
record.setScore(0);
record.setNodes(items);
record.setCode(String.format(PK.PK_APPRAISE_RECORD, schoolId));
appraiseRecordRepository.save(record);
} else {
// 处理学校与学生的差异
it
CosmosPatchOperations operations = CosmosPatchOperations.create();
operations.add("/nodes/0", item);
// 表扬
long praise = appraiseTreeNode.isPraise() ? 1 : -1;
operations.increment("/praiseCount", praise);
// 加分
int scoreToPlus = ObjectUtils.isEmpty(appraiseTreeNode.getScore()) ? 0 : appraiseTreeNode.getScore();
operations.increment("/score", scoreToPlus);
// patch doc
appraiseRecordRepository.save(record.getId(), PK.buildOf(PK.PK_APPRAISE_RECORD, schoolId), AppraiseRecord.class, operations);
}
}
/**

@ -0,0 +1,23 @@
package cn.teammodel.utils;
import cn.teammodel.common.ErrorCode;
import cn.teammodel.config.exception.ServiceException;
import org.apache.commons.lang3.ObjectUtils;
import java.util.List;
/**
* @author winter
* @create 2023-11-29 15:41
*/
public class RepositoryUtil {
/**
* ,listlist1,
*/
public static <T> T findOne(List<T> list) {
if (ObjectUtils.isEmpty(list) || list.size() > 1) {
throw new ServiceException(ErrorCode.PARAMS_ERROR);
}
return list.get(0);
}
}

@ -1,6 +1,8 @@
package cn.teammodel.utils;
import cn.teammodel.model.entity.school.Semester;
import cn.teammodel.common.CommonConstant;
import cn.teammodel.model.entity.school.School;
import org.apache.commons.lang3.tuple.Pair;
import java.time.LocalDate;
import java.util.Comparator;
@ -38,7 +40,7 @@ public class SchoolDateUtil {
* : -> 2024.1.1, 2023,,semesters
* </p>
*/
public static String getSemesterByNow(List<Semester> semesters, LocalDate date) {
public static Pair<String, LocalDate> getSemesterByNow(List<School.Semester> semesters, LocalDate date) {
if (semesters == null || semesters.isEmpty() || date == null) {
throw new IllegalArgumentException("Invalid input: semesters and date must not be null or empty.");
}
@ -49,19 +51,33 @@ public class SchoolDateUtil {
// i = 0 的日期是开学最早, i = size - 1 是开学最晚
int size = semesters.size();
// 拿到最晚开学的日期,将年份 - 1后,与头节点组成可跨年区间
Semester lastSemester = semesters.get(size - 1);
LocalDate tmpSemester = LocalDate.of(date.getYear() - 1, lastSemester.getMonth(), lastSemester.getDay());
for (Semester semester : semesters) {
School.Semester lastSemester = semesters.get(size - 1);
LocalDate lastSemesterStart = LocalDate.of(date.getYear() - 1, lastSemester.getMonth(), lastSemester.getDay());
String lastSemesterId = lastSemester.getId();
for (School.Semester semester : semesters) {
// 特判头尾的提起,分别将学期区间提前和延后一年(不用延后),例如 2023.3.1 与 2023.9.1 我们分别向添加一个节点,划分其为 3 个区间:
// 2022.9.1 - 2023.3.1, 2023.3.1 - 2023.9.1, 2023.9.1 - 2024.3.1
LocalDate curSemester = LocalDate.of(date.getYear(), semester.getMonth(), semester.getDay());
if (date.isEqual(tmpSemester) || date.isAfter(tmpSemester) && date.isBefore(curSemester)) {
return tmpSemester.toString();
LocalDate curSemesterStart = LocalDate.of(date.getYear(), semester.getMonth(), semester.getDay());
if (date.isEqual(lastSemesterStart) || date.isAfter(lastSemesterStart) && date.isBefore(curSemesterStart)) {
return Pair.of(lastSemesterId, lastSemesterStart);
}
tmpSemester = curSemester;
lastSemesterStart = curSemesterStart;
lastSemesterId = semester.getId();
}
// 剩下的时间段, 学年应该就是最后一个学年
return LocalDate.of(date.getYear(), lastSemester.getMonth(), lastSemester.getDay()).toString();
return Pair.of(lastSemester.getId(), LocalDate.of(date.getYear(), lastSemester.getMonth(), lastSemester.getDay()));
}
/**
* ID -> ( id: -semesterId -> 2023-{semesterId})
*/
public static String generateAcademicId(List<School.Semester> semesters, LocalDate date) {
Pair<String, LocalDate> pair = getSemesterByNow(semesters, date);
String semesterId = pair.getLeft();
LocalDate academicYear = pair.getRight();
return academicYear.getYear() + CommonConstant.DASH + semesterId;
}
}

@ -1,10 +1,13 @@
package cn.teammodel;
import cn.teammodel.common.PK;
import cn.teammodel.dao.AppraiseRecordRepository;
import cn.teammodel.dao.AppraiseRepository;
import cn.teammodel.dao.SchoolRepository;
import cn.teammodel.dao.StudentRepository;
import cn.teammodel.manager.DingAlertNotifier;
import cn.teammodel.model.entity.appraise.Appraise;
import cn.teammodel.model.entity.appraise.AppraiseRecord;
import cn.teammodel.model.entity.appraise.AppraiseTreeNode;
import cn.teammodel.service.EvaluationService;
import cn.teammodel.service.impl.EvaluationServiceImpl;
@ -27,6 +30,8 @@ class TeamModelExtensionApplicationTests {
@Autowired
private DingAlertNotifier notifier;
@Autowired
AppraiseRecordRepository appraiseRecordRepository;
@Autowired
StudentRepository studentRepository;
@Autowired
@ -83,7 +88,11 @@ class TeamModelExtensionApplicationTests {
//List<AppraiseTreeNode> nodeById = appraiseRepository.findNodeById("habook", "default", "Appraise", "43e23f03-288c-4012-b5f3-4d5c022739a2");
//System.out.println(nodeById);
System.out.println(schoolRepository.findSemestersById("hbcn", "Base"));
//System.out.println(schoolRepository.findSchoolByIdAndCode("hbcn", "Base", Semester.class));
AppraiseRecord record = appraiseRecordRepository.findAppraiseRecordByStudentIdAndAcademicYearIdAndCode("fakeStudentId1",
"2023-71fbd0bd-9a46-0490-f6b3-7d16cba4c017",
String.format(PK.PK_APPRAISE_RECORD,"habook")
);
}
@Test
public void testUpdate() {

@ -2,9 +2,8 @@ package cn.teammodel;
import cn.teammodel.model.entity.appraise.Appraise;
import cn.teammodel.model.entity.appraise.AppraiseTreeNode;
import cn.teammodel.model.entity.school.Semester;
import cn.teammodel.model.entity.school.School;
import cn.teammodel.service.impl.EvaluationServiceImpl;
import cn.teammodel.utils.SchoolDateUtil;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiRobotSendRequest;
@ -139,16 +138,16 @@ public class TestWithoutSpring {
@Test
public void testLocalDateTime() {
List<Semester> semesters = Arrays.asList(
new Semester("1", "上学期", 1, 2, 1),
new Semester("3", "下学期", 0, 8, 1),
new Semester("4", "下学期", 0, 11, 1),
new Semester("2", "下学期", 0, 5, 1)
List<School.Semester> semesters = Arrays.asList(
new School.Semester("1", "上学期", 1, 2, 1),
new School.Semester("3", "下学期", 0, 8, 1),
new School.Semester("4", "下学期", 0, 11, 1),
new School.Semester("2", "下学期", 0, 5, 1)
);
LocalDate currentDate = LocalDate.of(2024, 1, 1);
String currentSemester = SchoolDateUtil.getSemesterByNow(semesters, currentDate);
System.out.println(currentSemester);
//String currentSemester = SchoolDateUtil.getSemesterByNow(semesters, currentDate);
//System.out.println(currentSemester);
}
}

Loading…
Cancel
Save