diff --git a/src/oj/user/index.vue b/src/oj/user/index.vue index aa40c11..40703db 100644 --- a/src/oj/user/index.vue +++ b/src/oj/user/index.vue @@ -4,8 +4,9 @@ import { NH2, NH3 } from "naive-ui" import { getProfile } from "shared/api" import { useBreakpoints } from "shared/composables/breakpoints" import { durationToDays, parseTime } from "utils/functions" -import { Profile } from "utils/types" -import { getMetrics } from "../api" +import { Profile, UserBadge as UserBadgeType } from "utils/types" +import { getMetrics, getUserBadges } from "../api" +import GroupedUserBadge from "shared/components/GroupedUserBadge.vue" const route = useRoute() const router = useRouter() @@ -15,11 +16,46 @@ const firstSubmissionAt = ref("") const latestSubmissionAt = ref("") const toLatestAt = ref("") const learnDuration = ref("") +const userBadges = ref([]) const [loading, toggle] = useToggle() const [show, toggleShow] = useToggle(false) const { isDesktop } = useBreakpoints() +// 分组徽章接口 +interface GroupedBadge { + icon: string + count: number + badges: UserBadgeType[] + latestEarnedTime: Date +} + +// 按图标分组徽章 +function groupBadgesByIcon(badges: UserBadgeType[]): GroupedBadge[] { + const grouped = new Map() + + // 按图标分组 + badges.forEach((badge) => { + const icon = badge.badge.icon + if (!grouped.has(icon)) { + grouped.set(icon, []) + } + grouped.get(icon)!.push(badge) + }) + + // 转换为数组并排序 + return Array.from(grouped.entries()) + .map(([icon, badgeList]) => ({ + icon, + count: badgeList.length, + badges: badgeList, + latestEarnedTime: new Date( + Math.max(...badgeList.map((b) => new Date(b.earned_time).getTime())), + ), + })) + .sort((a, b) => a.icon.localeCompare(b.icon)) +} + async function init() { toggle(true) try { @@ -50,6 +86,9 @@ async function init() { metricsRes.data.latest, ) } + // 获取用户徽章 + const badgesRes = await getUserBadges() + userBadges.value = groupBadgesByIcon(badgesRes.data) } finally { toggle(false) } @@ -133,6 +172,24 @@ onMounted(init) + + + + + + + +