mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-05-09 12:17:29 +08:00
Merge pull request #454 from nagisa77/codex/update-medal-selection-logic-in-backend
feat: auto select medals and improve navigation
This commit is contained in:
@@ -82,6 +82,16 @@ public class MedalService {
|
|||||||
}
|
}
|
||||||
seedUserMedal.setSelected(selected == MedalType.SEED);
|
seedUserMedal.setSelected(selected == MedalType.SEED);
|
||||||
medals.add(seedUserMedal);
|
medals.add(seedUserMedal);
|
||||||
|
if (user != null && selected == null) {
|
||||||
|
for (MedalDto medal : medals) {
|
||||||
|
if (medal.isCompleted()) {
|
||||||
|
medal.setSelected(true);
|
||||||
|
user.setDisplayMedal(medal.getType());
|
||||||
|
userRepository.save(user);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return medals;
|
return medals;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,19 +41,20 @@ class MedalServiceTest {
|
|||||||
User user = new User();
|
User user = new User();
|
||||||
user.setId(1L);
|
user.setId(1L);
|
||||||
user.setCreatedAt(LocalDateTime.of(2025, 9, 15, 0, 0));
|
user.setCreatedAt(LocalDateTime.of(2025, 9, 15, 0, 0));
|
||||||
user.setDisplayMedal(MedalType.COMMENT);
|
|
||||||
when(userRepo.findById(1L)).thenReturn(Optional.of(user));
|
when(userRepo.findById(1L)).thenReturn(Optional.of(user));
|
||||||
when(userRepo.findByUsername("user")).thenReturn(Optional.of(user));
|
when(userRepo.findByUsername("user")).thenReturn(Optional.of(user));
|
||||||
|
|
||||||
MedalService service = new MedalService(commentRepo, postRepo, userRepo);
|
MedalService service = new MedalService(commentRepo, postRepo, userRepo);
|
||||||
List<MedalDto> medals = service.getMedals(1L);
|
List<MedalDto> medals = service.getMedals(1L);
|
||||||
|
|
||||||
|
assertEquals(MedalType.COMMENT, user.getDisplayMedal());
|
||||||
assertTrue(medals.stream().filter(m -> m.getType() == MedalType.COMMENT).findFirst().orElseThrow().isCompleted());
|
assertTrue(medals.stream().filter(m -> m.getType() == MedalType.COMMENT).findFirst().orElseThrow().isCompleted());
|
||||||
assertTrue(medals.stream().filter(m -> m.getType() == MedalType.COMMENT).findFirst().orElseThrow().isSelected());
|
assertTrue(medals.stream().filter(m -> m.getType() == MedalType.COMMENT).findFirst().orElseThrow().isSelected());
|
||||||
assertFalse(medals.stream().filter(m -> m.getType() == MedalType.POST).findFirst().orElseThrow().isCompleted());
|
assertFalse(medals.stream().filter(m -> m.getType() == MedalType.POST).findFirst().orElseThrow().isCompleted());
|
||||||
assertFalse(medals.stream().filter(m -> m.getType() == MedalType.POST).findFirst().orElseThrow().isSelected());
|
assertFalse(medals.stream().filter(m -> m.getType() == MedalType.POST).findFirst().orElseThrow().isSelected());
|
||||||
assertTrue(medals.stream().filter(m -> m.getType() == MedalType.SEED).findFirst().orElseThrow().isCompleted());
|
assertTrue(medals.stream().filter(m -> m.getType() == MedalType.SEED).findFirst().orElseThrow().isCompleted());
|
||||||
assertFalse(medals.stream().filter(m -> m.getType() == MedalType.SEED).findFirst().orElseThrow().isSelected());
|
assertFalse(medals.stream().filter(m -> m.getType() == MedalType.SEED).findFirst().orElseThrow().isSelected());
|
||||||
|
verify(userRepo).save(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div
|
<div
|
||||||
v-for="medal in sortedMedals"
|
v-for="medal in sortedMedals"
|
||||||
:key="medal.type"
|
:key="medal.type"
|
||||||
:class="['achievements-list-item', { select: medal.selected, clickable: canSelect }]"
|
:class="['achievements-list-item', { select: medal.selected && canSelect, clickable: canSelect }]"
|
||||||
@click="selectMedal(medal)"
|
@click="selectMedal(medal)"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
:alt="medal.title"
|
:alt="medal.title"
|
||||||
:class="['achievements-list-item-icon', { not_completed: !medal.completed }]"
|
:class="['achievements-list-item-icon', { not_completed: !medal.completed }]"
|
||||||
/>
|
/>
|
||||||
<div v-if="medal.selected" class="achievements-list-item-top-right-label">展示</div>
|
<div v-if="medal.selected && canSelect" class="achievements-list-item-top-right-label">展示</div>
|
||||||
<div class="achievements-list-item-title">{{ medal.title }}</div>
|
<div class="achievements-list-item-title">{{ medal.title }}</div>
|
||||||
<div class="achievements-list-item-description">
|
<div class="achievements-list-item-description">
|
||||||
{{ medal.description }}
|
{{ medal.description }}
|
||||||
|
|||||||
@@ -11,7 +11,11 @@
|
|||||||
<div class="common-info-content-header">
|
<div class="common-info-content-header">
|
||||||
<div class="info-content-header-left">
|
<div class="info-content-header-left">
|
||||||
<span class="user-name">{{ comment.userName }}</span>
|
<span class="user-name">{{ comment.userName }}</span>
|
||||||
<span v-if="comment.medal" class="medal-name">{{ getMedalTitle(comment.medal) }}</span>
|
<router-link
|
||||||
|
v-if="comment.medal"
|
||||||
|
class="medal-name"
|
||||||
|
:to="`/users/${comment.userId}?tab=achievements`"
|
||||||
|
>{{ getMedalTitle(comment.medal) }}</router-link>
|
||||||
<span v-if="level >= 2">
|
<span v-if="level >= 2">
|
||||||
<i class="fas fa-reply reply-icon"></i>
|
<i class="fas fa-reply reply-icon"></i>
|
||||||
<span class="user-name reply-user-name">{{ comment.parentUserName }}</span>
|
<span class="user-name reply-user-name">{{ comment.parentUserName }}</span>
|
||||||
@@ -289,6 +293,7 @@ export default CommentItem
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes highlight {
|
@keyframes highlight {
|
||||||
|
|||||||
@@ -43,7 +43,11 @@
|
|||||||
<div v-if="isMobile" class="info-content-header">
|
<div v-if="isMobile" class="info-content-header">
|
||||||
<div class="user-name">
|
<div class="user-name">
|
||||||
{{ author.username }}
|
{{ author.username }}
|
||||||
<span v-if="author.displayMedal" class="user-medal">{{ getMedalTitle(author.displayMedal) }}</span>
|
<router-link
|
||||||
|
v-if="author.displayMedal"
|
||||||
|
class="user-medal"
|
||||||
|
:to="`/users/${author.id}?tab=achievements`"
|
||||||
|
>{{ getMedalTitle(author.displayMedal) }}</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div class="post-time">{{ postTime }}</div>
|
<div class="post-time">{{ postTime }}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -53,7 +57,11 @@
|
|||||||
<div v-if="!isMobile" class="info-content-header">
|
<div v-if="!isMobile" class="info-content-header">
|
||||||
<div class="user-name">
|
<div class="user-name">
|
||||||
{{ author.username }}
|
{{ author.username }}
|
||||||
<span v-if="author.displayMedal" class="user-medal">{{ getMedalTitle(author.displayMedal) }}</span>
|
<router-link
|
||||||
|
v-if="author.displayMedal"
|
||||||
|
class="user-medal"
|
||||||
|
:to="`/users/${author.id}?tab=achievements`"
|
||||||
|
>{{ getMedalTitle(author.displayMedal) }}</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div class="post-time">{{ postTime }}</div>
|
<div class="post-time">{{ postTime }}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -236,6 +244,7 @@ export default {
|
|||||||
id: c.id,
|
id: c.id,
|
||||||
userName: c.author.username,
|
userName: c.author.username,
|
||||||
medal: c.author.displayMedal,
|
medal: c.author.displayMedal,
|
||||||
|
userId: c.author.id,
|
||||||
time: TimeManager.format(c.createdAt),
|
time: TimeManager.format(c.createdAt),
|
||||||
avatar: c.author.avatar,
|
avatar: c.author.avatar,
|
||||||
text: c.content,
|
text: c.content,
|
||||||
@@ -940,6 +949,7 @@ export default {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-time {
|
.post-time {
|
||||||
|
|||||||
Reference in New Issue
Block a user