mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-06-08 11:07:34 +08:00
feat: 新增贡献者勋章
This commit is contained in:
@@ -4,6 +4,7 @@ import com.openisle.model.ContributorConfig;
|
|||||||
import com.openisle.repository.ContributorConfigRepository;
|
import com.openisle.repository.ContributorConfigRepository;
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -12,10 +13,11 @@ import org.springframework.web.client.RestTemplate;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ContributorService {
|
public class ContributorService {
|
||||||
private static final String OWNER = "OpenIsle";
|
private static final String OWNER = "nagisa77";
|
||||||
private static final String REPO = "OpenIsle";
|
private static final String REPO = "OpenIsle";
|
||||||
|
|
||||||
private final ContributorConfigRepository repository;
|
private final ContributorConfigRepository repository;
|
||||||
@@ -34,12 +36,23 @@ public class ContributorService {
|
|||||||
private long fetchContributionLines(String githubId) {
|
private long fetchContributionLines(String githubId) {
|
||||||
try {
|
try {
|
||||||
String url = String.format("https://api.github.com/repos/%s/%s/stats/contributors", OWNER, REPO);
|
String url = String.format("https://api.github.com/repos/%s/%s/stats/contributors", OWNER, REPO);
|
||||||
ResponseEntity<List> response = restTemplate.getForEntity(url, List.class);
|
ResponseEntity<?> response = restTemplate.getForEntity(url, Object.class);
|
||||||
List<Map<String, Object>> body = response.getBody();
|
|
||||||
if (body == null) {
|
// 检查是否为202,GitHub有时会返回202表示正在生成统计数据
|
||||||
|
if (response.getStatusCodeValue() == 202) {
|
||||||
|
log.warn("GitHub API 返回202,统计数据正在生成中,githubId: {}", githubId);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
for (Map<String, Object> item : body) {
|
|
||||||
|
Object body = response.getBody();
|
||||||
|
if (!(body instanceof List)) {
|
||||||
|
// 不是List类型,直接返回0
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
List<?> listBody = (List<?>) body;
|
||||||
|
for (Object itemObj : listBody) {
|
||||||
|
if (!(itemObj instanceof Map)) continue;
|
||||||
|
Map<String, Object> item = (Map<String, Object>) itemObj;
|
||||||
Map<String, Object> author = (Map<String, Object>) item.get("author");
|
Map<String, Object> author = (Map<String, Object>) item.get("author");
|
||||||
if (author != null && githubId.equals(author.get("login"))) {
|
if (author != null && githubId.equals(author.get("login"))) {
|
||||||
List<Map<String, Object>> weeks = (List<Map<String, Object>>) item.get("weeks");
|
List<Map<String, Object>> weeks = (List<Map<String, Object>>) item.get("weeks");
|
||||||
@@ -59,7 +72,8 @@ public class ContributorService {
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (Exception e) {
|
||||||
|
log.warn(e.getMessage());
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public class MedalService {
|
|||||||
medals.add(postMedal);
|
medals.add(postMedal);
|
||||||
|
|
||||||
ContributorMedalDto contributorMedal = new ContributorMedalDto();
|
ContributorMedalDto contributorMedal = new ContributorMedalDto();
|
||||||
contributorMedal.setIcon("https://openisle-1307107697.cos.ap-guangzhou.myqcloud.com/assert/icons/achi_contributor.png");
|
contributorMedal.setIcon("https://openisle-1307107697.cos.ap-guangzhou.myqcloud.com/assert/icons/achi_coder.png");
|
||||||
contributorMedal.setTitle("贡献者");
|
contributorMedal.setTitle("贡献者");
|
||||||
contributorMedal.setDescription("对仓库贡献超过1行代码");
|
contributorMedal.setDescription("对仓库贡献超过1行代码");
|
||||||
contributorMedal.setType(MedalType.CONTRIBUTOR);
|
contributorMedal.setType(MedalType.CONTRIBUTOR);
|
||||||
|
|||||||
@@ -21,6 +21,9 @@
|
|||||||
<template v-else-if="medal.type === 'POST'">
|
<template v-else-if="medal.type === 'POST'">
|
||||||
{{ medal.currentPostCount }}/{{ medal.targetPostCount }}
|
{{ medal.currentPostCount }}/{{ medal.targetPostCount }}
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="medal.type === 'CONTRIBUTOR'">
|
||||||
|
{{ medal.currentContributionLines }}/{{ medal.targetContributionLines }}
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<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>
|
||||||
|
<i class="fas fa-medal medal-icon"></i>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="comment.medal"
|
v-if="comment.medal"
|
||||||
class="medal-name"
|
class="medal-name"
|
||||||
@@ -291,9 +292,19 @@ export default CommentItem
|
|||||||
|
|
||||||
.medal-name {
|
.medal-name {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-left: 4px;
|
margin-left: 1px;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.medal-icon {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes highlight {
|
@keyframes highlight {
|
||||||
|
|||||||
@@ -255,7 +255,7 @@
|
|||||||
import { ref, computed, onMounted, watch } from 'vue'
|
import { ref, computed, onMounted, watch } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { API_BASE_URL, toast } from '../main'
|
import { API_BASE_URL, toast } from '../main'
|
||||||
import { getToken, authState } from '../utils/auth'
|
import { getToken, authState } from '../../utils/auth'
|
||||||
import BaseTimeline from '../components/BaseTimeline.vue'
|
import BaseTimeline from '../components/BaseTimeline.vue'
|
||||||
import UserList from '../components/UserList.vue'
|
import UserList from '../components/UserList.vue'
|
||||||
import BasePlaceholder from '../components/BasePlaceholder.vue'
|
import BasePlaceholder from '../components/BasePlaceholder.vue'
|
||||||
@@ -306,7 +306,11 @@ export default {
|
|||||||
return { exp, currentLevel, nextExp, percent }
|
return { exp, currentLevel, nextExp, percent }
|
||||||
})
|
})
|
||||||
|
|
||||||
const isMine = computed(() => authState.username === username)
|
const isMine = computed(function() {
|
||||||
|
const mine = authState.username === username || String(authState.userId) === username
|
||||||
|
console.log(mine)
|
||||||
|
return mine
|
||||||
|
})
|
||||||
|
|
||||||
const formatDate = (d) => {
|
const formatDate = (d) => {
|
||||||
if (!d) return ''
|
if (!d) return ''
|
||||||
|
|||||||
Reference in New Issue
Block a user