feat: implement medal feature

This commit is contained in:
Tim
2025-08-09 02:08:02 +08:00
parent 9c1cedd172
commit 987fe0d885
11 changed files with 269 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
package com.openisle.controller;
import com.openisle.dto.MedalDto;
import com.openisle.service.MedalService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/api/medals")
@RequiredArgsConstructor
public class MedalController {
private final MedalService medalService;
@GetMapping
public List<MedalDto> getMedals(@RequestParam(value = "userId", required = false) Long userId) {
return medalService.getMedals(userId);
}
}

View File

@@ -0,0 +1,11 @@
package com.openisle.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class CommentMedalDto extends MedalDto {
private long currentCommentCount;
private long targetCommentCount;
}

View File

@@ -0,0 +1,13 @@
package com.openisle.dto;
import com.openisle.model.MedalType;
import lombok.Data;
@Data
public class MedalDto {
private String icon;
private String title;
private String description;
private MedalType type;
private boolean completed;
}

View File

@@ -0,0 +1,11 @@
package com.openisle.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class PostMedalDto extends MedalDto {
private long currentPostCount;
private long targetPostCount;
}

View File

@@ -0,0 +1,11 @@
package com.openisle.dto;
import java.time.LocalDateTime;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class SeedUserMedalDto extends MedalDto {
private LocalDateTime registerDate;
}

View File

@@ -0,0 +1,7 @@
package com.openisle.model;
public enum MedalType {
COMMENT,
POST,
SEED
}

View File

@@ -30,4 +30,6 @@ public interface CommentRepository extends JpaRepository<Comment, Long> {
@org.springframework.data.jpa.repository.Query("SELECT COUNT(c) FROM Comment c WHERE c.post.id = :postId")
long countByPostId(@org.springframework.data.repository.query.Param("postId") Long postId);
long countByAuthor_Id(Long userId);
}

View File

@@ -93,4 +93,6 @@ public interface PostRepository extends JpaRepository<Post, Long> {
long countByCategory_Id(Long categoryId);
long countDistinctByTags_Id(Long tagId);
long countByAuthor_Id(Long userId);
}

View File

@@ -0,0 +1,84 @@
package com.openisle.service;
import com.openisle.dto.CommentMedalDto;
import com.openisle.dto.MedalDto;
import com.openisle.dto.PostMedalDto;
import com.openisle.dto.SeedUserMedalDto;
import com.openisle.model.MedalType;
import com.openisle.repository.CommentRepository;
import com.openisle.repository.PostRepository;
import com.openisle.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Service
@RequiredArgsConstructor
public class MedalService {
private static final long COMMENT_TARGET = 100;
private static final long POST_TARGET = 100;
private static final LocalDateTime SEED_USER_DEADLINE = LocalDateTime.of(2025, 9, 16, 0, 0);
private final CommentRepository commentRepository;
private final PostRepository postRepository;
private final UserRepository userRepository;
public List<MedalDto> getMedals(Long userId) {
List<MedalDto> medals = new ArrayList<>();
CommentMedalDto commentMedal = new CommentMedalDto();
commentMedal.setIcon("comment.png");
commentMedal.setTitle("评论达人");
commentMedal.setDescription("评论超过100条");
commentMedal.setType(MedalType.COMMENT);
commentMedal.setTargetCommentCount(COMMENT_TARGET);
if (userId != null) {
long count = commentRepository.countByAuthor_Id(userId);
commentMedal.setCurrentCommentCount(count);
commentMedal.setCompleted(count >= COMMENT_TARGET);
} else {
commentMedal.setCurrentCommentCount(0);
commentMedal.setCompleted(false);
}
medals.add(commentMedal);
PostMedalDto postMedal = new PostMedalDto();
postMedal.setIcon("post.png");
postMedal.setTitle("发帖达人");
postMedal.setDescription("评论超过100条");
postMedal.setType(MedalType.POST);
postMedal.setTargetPostCount(POST_TARGET);
if (userId != null) {
long count = postRepository.countByAuthor_Id(userId);
postMedal.setCurrentPostCount(count);
postMedal.setCompleted(count >= POST_TARGET);
} else {
postMedal.setCurrentPostCount(0);
postMedal.setCompleted(false);
}
medals.add(postMedal);
SeedUserMedalDto seedUserMedal = new SeedUserMedalDto();
seedUserMedal.setIcon("seed.png");
seedUserMedal.setTitle("种子用户");
seedUserMedal.setDescription("2025.9.16前注册的用户");
seedUserMedal.setType(MedalType.SEED);
if (userId != null) {
userRepository.findById(userId).ifPresent(user -> {
seedUserMedal.setRegisterDate(user.getCreatedAt());
seedUserMedal.setCompleted(user.getCreatedAt().isBefore(SEED_USER_DEADLINE));
});
if (seedUserMedal.getRegisterDate() == null) {
seedUserMedal.setCompleted(false);
}
} else {
seedUserMedal.setCompleted(false);
}
medals.add(seedUserMedal);
return medals;
}
}