diff --git a/src/main/java/cn/teammodel/admin/controller/IndexController.java b/src/main/java/cn/teammodel/admin/controller/IndexController.java new file mode 100644 index 0000000..38cf3dc --- /dev/null +++ b/src/main/java/cn/teammodel/admin/controller/IndexController.java @@ -0,0 +1,22 @@ +package cn.teammodel.admin.controller; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 管理员首页 + * @author winter + * @create 2023-12-06 14:37 + */ +@RestController +@RequestMapping("admin/index") +public class IndexController { + + + @RequestMapping("/") + public String index(){ + + return null; + } + +} diff --git a/src/main/java/cn/teammodel/admin/service/AdminAppraiseService.java b/src/main/java/cn/teammodel/admin/service/AdminAppraiseService.java new file mode 100644 index 0000000..d9c268e --- /dev/null +++ b/src/main/java/cn/teammodel/admin/service/AdminAppraiseService.java @@ -0,0 +1,12 @@ +package cn.teammodel.admin.service; + +import cn.teammodel.model.vo.admin.IndexData; + +/** + * @author winter + * @create 2023-12-06 14:45 + */ +public interface AdminAppraiseService { + IndexData getIndexData(String period, String academicYearId); + +} diff --git a/src/main/java/cn/teammodel/admin/service/impl/AdminAppraiseServiceImpl.java b/src/main/java/cn/teammodel/admin/service/impl/AdminAppraiseServiceImpl.java new file mode 100644 index 0000000..f2d3b46 --- /dev/null +++ b/src/main/java/cn/teammodel/admin/service/impl/AdminAppraiseServiceImpl.java @@ -0,0 +1,90 @@ +package cn.teammodel.admin.service.impl; + +import cn.teammodel.admin.service.AdminAppraiseService; +import cn.teammodel.common.PK; +import cn.teammodel.dao.AppraiseRecordRepository; +import cn.teammodel.dao.AppraiseRepository; +import cn.teammodel.model.vo.admin.IndexData; +import cn.teammodel.model.vo.appraise.RecordVo; +import com.azure.spring.data.cosmos.core.CosmosTemplate; +import com.azure.spring.data.cosmos.core.query.CosmosPageRequest; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.data.domain.Slice; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.temporal.WeekFields; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * @author winter + * @create 2023-12-06 14:46 + */ +@Service +public class AdminAppraiseServiceImpl implements AdminAppraiseService { + @Resource + private CosmosTemplate cosmosTemplate; + @Resource + private AppraiseRepository appraiseRepository; + @Resource + private AppraiseRecordRepository appraiseRecordRepository; + + @Override + public IndexData getIndexData(String period, String academicYearId) { + final IndexData indexData = new IndexData(); + int totalCount = 0; + int criticalCount = 0; + + //User loginUser = SecurityUtil.getLoginUser(); + String schoolId = "habook"; + + // slice 分段读取 + CosmosPageRequest pageRequest = new CosmosPageRequest(0, 10, null); + Slice slice; + Map countByWeek = new HashMap<>(); + + do { + slice = appraiseRecordRepository.findAllByAcademicYearId(String.format(PK.PK_APPRAISE_RECORD, schoolId), academicYearId, pageRequest); + List content = slice.getContent(); + if (ObjectUtils.isEmpty(content)) { + return indexData; + } + + // 分批次计算 + for (RecordVo item : content) { + // 处理每周的评价数 + int weekNum = calculateWeekNum(item.getCreateTime()); + countByWeek.put(weekNum, countByWeek.getOrDefault(weekNum, 0) + 1); + // 处理总评价数 + totalCount++; + // 处理批评数 + if (!item.isPraise()) { + criticalCount++; + } + } + + if (slice.hasNext()) { + pageRequest = (CosmosPageRequest) slice.nextPageable(); + } + } while (slice.hasNext()); + + // 组装数据 + indexData.setCountByWeek(countByWeek); + indexData.setTotalCount(totalCount); + indexData.setCriticalCount(criticalCount); + indexData.setPraiseCount(totalCount - criticalCount); + return indexData; + } + + private int calculateWeekNum(LocalDateTime localDateTime) { + // 获取周字段 todo: 时区或者周的计算 + WeekFields weekFields = WeekFields.of(Locale.getDefault()); + // 获取当前日期时间所在年的周数 + return localDateTime.get(weekFields.weekOfWeekBasedYear()); + } + +} diff --git a/src/main/java/cn/teammodel/dao/AppraiseRecordRepository.java b/src/main/java/cn/teammodel/dao/AppraiseRecordRepository.java index 40bdb7a..f141537 100644 --- a/src/main/java/cn/teammodel/dao/AppraiseRecordRepository.java +++ b/src/main/java/cn/teammodel/dao/AppraiseRecordRepository.java @@ -2,10 +2,12 @@ package cn.teammodel.dao; import cn.teammodel.model.entity.appraise.AppraiseRecord; import cn.teammodel.model.vo.appraise.AppraiseRecordVo; +import cn.teammodel.model.vo.appraise.RecordVo; import com.azure.spring.data.cosmos.repository.CosmosRepository; import com.azure.spring.data.cosmos.repository.Query; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.stereotype.Repository; import java.util.List; @@ -39,8 +41,34 @@ public interface AppraiseRecordRepository extends CosmosRepository searchNodesByCondition(String targetId, String targetType, String classId, String creatorId, String academicYearId, String code, Pageable pageable); + Page searchNodesByCondition(String targetId, + String targetType, + String classId, + String creatorId, + String academicYearId, + Boolean isPraise, + String code, + Pageable pageable); + /** + * 查询学校的评价总数, praise = null 时查询总数,否则查询当前学段对应是否表扬的评价总数 + */ + @Query("select value count(1) from Student as c join n in c.nodes where c.code = @code and" + + " (IS_NULL(@praise) or n.appraiseNode.isPraise = @praise)") + int countRecords(Boolean praise, String academicYearId, String code); + + + @Query("select n.createTime, n.appraiseNode.isPraise from Student as c join n in c.nodes where c.code = @code and c.academicYearId = @academicYearId") + Slice findAllByAcademicYearId(String code, String academicYearId, Pageable pageable); + + /** + * 最新的评价明细,分页 + */ + // todo: 调整一下数据结构 + @Query("select c.id as recordId, c.name, c.avatar, c.targetId, c.targetType, n as info from Student as c join n in c.nodes where c.code = @code" + + "order by c.createTime desc") + Page pageLatestRecords(String code, Pageable pageable); } diff --git a/src/main/java/cn/teammodel/model/dto/Appraise/FindVoteRecordDto.java b/src/main/java/cn/teammodel/model/dto/Appraise/FindVoteRecordDto.java index 2fd1492..e8bd5ec 100644 --- a/src/main/java/cn/teammodel/model/dto/Appraise/FindVoteRecordDto.java +++ b/src/main/java/cn/teammodel/model/dto/Appraise/FindVoteRecordDto.java @@ -27,4 +27,6 @@ public class FindVoteRecordDto extends PageableRequest { @ApiModelProperty(value = "按班级 id搜索") private String classId; + @ApiModelProperty(value = "是否为表扬") + private Boolean isPraise; } diff --git a/src/main/java/cn/teammodel/model/entity/appraise/AppraiseRecordItem.java b/src/main/java/cn/teammodel/model/entity/appraise/AppraiseRecordItem.java index 1c8e597..7fde2f4 100644 --- a/src/main/java/cn/teammodel/model/entity/appraise/AppraiseRecordItem.java +++ b/src/main/java/cn/teammodel/model/entity/appraise/AppraiseRecordItem.java @@ -24,6 +24,6 @@ public class AppraiseRecordItem { private Boolean pushParent; String creator; String creatorId; - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-ddTHH:mm:ss.fffffffZ") private LocalDateTime createTime; } diff --git a/src/main/java/cn/teammodel/model/vo/admin/IndexData.java b/src/main/java/cn/teammodel/model/vo/admin/IndexData.java new file mode 100644 index 0000000..29e96b0 --- /dev/null +++ b/src/main/java/cn/teammodel/model/vo/admin/IndexData.java @@ -0,0 +1,17 @@ +package cn.teammodel.model.vo.admin; + +import lombok.Data; + +import java.util.Map; + +/** + * @author winter + * @create 2023-12-06 14:47 + */ +@Data +public class IndexData { + private Integer totalCount; + private Integer praiseCount; + private Integer criticalCount; + private Map countByWeek; +} diff --git a/src/main/java/cn/teammodel/model/vo/appraise/RecordVo.java b/src/main/java/cn/teammodel/model/vo/appraise/RecordVo.java new file mode 100644 index 0000000..1b5e5bd --- /dev/null +++ b/src/main/java/cn/teammodel/model/vo/appraise/RecordVo.java @@ -0,0 +1,24 @@ +package cn.teammodel.model.vo.appraise; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * @author winter + * @create 2023-12-06 17:43 + */ +@Data +public class RecordVo { + private String recordId; + private String name; + private String avatar; + private String targetId; + private String targetType; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + @JsonProperty("isPraise") + private boolean isPraise; +} diff --git a/src/main/java/cn/teammodel/service/impl/EvaluationServiceImpl.java b/src/main/java/cn/teammodel/service/impl/EvaluationServiceImpl.java index 3a22255..feae83b 100644 --- a/src/main/java/cn/teammodel/service/impl/EvaluationServiceImpl.java +++ b/src/main/java/cn/teammodel/service/impl/EvaluationServiceImpl.java @@ -339,6 +339,7 @@ public class EvaluationServiceImpl implements EvaluationService { String targetId = StringUtils.isBlank(findVoteRecordDto.getTargetId()) ? null : findVoteRecordDto.getTargetId(); String targetType = StringUtils.isBlank(findVoteRecordDto.getTargetType()) ? null : findVoteRecordDto.getTargetType(); String classId = StringUtils.isBlank(findVoteRecordDto.getClassId()) ? null : findVoteRecordDto.getClassId(); + Boolean isPraise = findVoteRecordDto.getIsPraise(); User loginUser = SecurityUtil.getLoginUser(); String teacherId = loginUser.getId(); String schoolId = loginUser.getSchoolId(); @@ -354,6 +355,7 @@ public class EvaluationServiceImpl implements EvaluationService { classId, teacherId, academicYearId, + isPraise, String.format(PK.PK_APPRAISE_RECORD, schoolId), pageRequest ); diff --git a/src/test/java/cn/teammodel/TeamModelExtensionApplicationTests.java b/src/test/java/cn/teammodel/TeamModelExtensionApplicationTests.java index 3544fcc..4ec1db7 100644 --- a/src/test/java/cn/teammodel/TeamModelExtensionApplicationTests.java +++ b/src/test/java/cn/teammodel/TeamModelExtensionApplicationTests.java @@ -1,5 +1,6 @@ package cn.teammodel; +import cn.teammodel.admin.service.AdminAppraiseService; import cn.teammodel.dao.AppraiseRecordRepository; import cn.teammodel.dao.AppraiseRepository; import cn.teammodel.dao.SchoolRepository; @@ -8,18 +9,22 @@ import cn.teammodel.manager.DingAlertNotifier; import cn.teammodel.model.entity.appraise.Appraise; import cn.teammodel.model.entity.appraise.AppraiseTreeNode; import cn.teammodel.model.entity.school.School; +import cn.teammodel.model.vo.admin.IndexData; +import cn.teammodel.model.vo.appraise.RecordVo; import cn.teammodel.service.EvaluationService; import cn.teammodel.service.impl.EvaluationServiceImpl; import com.azure.cosmos.models.PartitionKey; import com.azure.spring.data.cosmos.core.CosmosTemplate; +import com.azure.spring.data.cosmos.core.query.CosmosPageRequest; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.Slice; import javax.annotation.Resource; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import java.time.LocalDateTime; +import java.time.temporal.WeekFields; +import java.util.*; @SpringBootTest class TeamModelExtensionApplicationTests { @@ -29,6 +34,8 @@ class TeamModelExtensionApplicationTests { @Autowired private DingAlertNotifier notifier; + @Autowired + AdminAppraiseService adminAppraiseService; @Autowired AppraiseRecordRepository appraiseRecordRepository; @Autowired @@ -128,6 +135,50 @@ class TeamModelExtensionApplicationTests { cosmosTemplate.upsert(appraise); } + @Test + public void testAggressiveFunc() { + long t1 = System.currentTimeMillis(); + //System.out.println(appraiseRecordRepository.countRecords(null, "AppraiseRecord-habook")); + //System.out.println(appraiseRecordRepository.countRecords(false, "AppraiseRecord-habook")); + long t2 = System.currentTimeMillis(); + System.out.println(t2 - t1); + } + + @Test + public void testSlice() { + CosmosPageRequest pageRequest = new CosmosPageRequest(0, 10, null); + Slice slice; + Map countByWeek = new HashMap<>(); + + do { + slice = appraiseRecordRepository.findAllByAcademicYearId("AppraiseRecord-habook", "2023-71fbd0bd-9a46-0490-f6b3-7d16cba4c017", pageRequest); + + slice.getContent().forEach(item -> { + int weekNum = calculateWeekNum(item.getCreateTime()); + countByWeek.put(weekNum, countByWeek.getOrDefault(weekNum, 0) + 1); + }); + + if (slice.hasNext()) { + pageRequest = (CosmosPageRequest) slice.nextPageable(); + } + } while (slice.hasNext()); + + countByWeek.forEach((item, count) -> System.out.println(item + ": " + count)); + } + + private int calculateWeekNum(LocalDateTime localDateTime) { + // 获取周字段 + WeekFields weekFields = WeekFields.of(Locale.getDefault()); + // 获取当前日期时间所在年的周数 + return localDateTime.get(weekFields.weekOfWeekBasedYear()); + } + + @Test + public void testIndexData() { + IndexData indexData = adminAppraiseService.getIndexData("", "2023-71fbd0bd-9a46-0490-f6b3-7d16cba4c017"); + System.out.println(indexData); + } + }