添加最近活动
This commit is contained in:
parent
186086c0bd
commit
c0a7097fd2
@ -2,12 +2,15 @@ import {request} from "@/utils/network.ts";
|
|||||||
|
|
||||||
const TOKEN = "fb8aec429ea7d0a36f7238dbffda9d2d66c7b045"
|
const TOKEN = "fb8aec429ea7d0a36f7238dbffda9d2d66c7b045"
|
||||||
|
|
||||||
export async function getActivity() {
|
export async function getActivity(): Promise<IActivity[]> {
|
||||||
return request({
|
return request({
|
||||||
url: '/git/api/v1/users/cantyonion/activities/feeds',
|
url: '/git/api/v1/users/cantyonion/activities/feeds',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: ` ${TOKEN}`
|
Authorization: ` ${TOKEN}`,
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
limit: 4
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ defineProps<{
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mb-4 flex justify-between text-2xl font-bold text-white">
|
<div class="mb-4 flex justify-between text-2xl font-bold text-white">
|
||||||
<div :class="mainColor" class="flex w-max items-center justify-center overflow-hidden rounded-2xl bg-rose-500">
|
<div :class="[mainColor]" class="flex w-max items-center justify-center overflow-hidden rounded-2xl">
|
||||||
<div :class="[subColor]" class="flex h-full w-14 items-center justify-center rounded-2xl px-4 py-2 text-center">
|
<div :class="[subColor]" class="flex h-full w-14 items-center justify-center rounded-2xl px-4 py-2 text-center">
|
||||||
<font-awesome-icon :icon="icon"/>
|
<font-awesome-icon :icon="icon"/>
|
||||||
</div>
|
</div>
|
||||||
|
76
src/components/card/GitCard.vue
Normal file
76
src/components/card/GitCard.vue
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import {FontAwesomeIcon} from "@fortawesome/vue-fontawesome";
|
||||||
|
import {computed} from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
commit: IActivity<IContent>
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const icon = computed(() => {
|
||||||
|
switch (props.commit.op_type) {
|
||||||
|
case "merge_pull_request":
|
||||||
|
return ['fas', 'code-merge']
|
||||||
|
case "create_repo":
|
||||||
|
return ['fab', 'git-alt']
|
||||||
|
case "commit_repo":
|
||||||
|
default:
|
||||||
|
return ['fas', 'code-commit']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const time = computed(() => timeDifference(props.commit.created))
|
||||||
|
|
||||||
|
const timeDifference = (dateString: string): string => {
|
||||||
|
const targetDate = new Date(dateString);
|
||||||
|
const currentDate = new Date();
|
||||||
|
|
||||||
|
const diffInMillis = currentDate.getTime() - targetDate.getTime();
|
||||||
|
|
||||||
|
const minutes = Math.floor(diffInMillis / (1000 * 60));
|
||||||
|
const hours = Math.floor(diffInMillis / (1000 * 60 * 60));
|
||||||
|
const days = Math.floor(diffInMillis / (1000 * 60 * 60 * 24));
|
||||||
|
const months = Math.floor(diffInMillis / (1000 * 60 * 60 * 24 * 30));
|
||||||
|
const years = Math.floor(diffInMillis / (1000 * 60 * 60 * 24 * 365));
|
||||||
|
|
||||||
|
if (minutes < 60) {
|
||||||
|
return `${minutes} 分钟前`;
|
||||||
|
} else if (hours < 24) {
|
||||||
|
return `${hours} 小时前`;
|
||||||
|
} else if (days < 30) {
|
||||||
|
return `${days} 天前`;
|
||||||
|
} else if (months < 12) {
|
||||||
|
return `${months} 个月前`;
|
||||||
|
} else {
|
||||||
|
return `${years} 年前`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="container relative flex h-36 w-full overflow-hidden rounded-2xl hover:shadow-md transition-all">
|
||||||
|
<!-- 提交图标 -->
|
||||||
|
<div class="flex h-36 w-36 items-center justify-center bg-pink-300 text-5xl text-white">
|
||||||
|
<font-awesome-icon :icon="icon"/>
|
||||||
|
</div>
|
||||||
|
<!-- 内容 -->
|
||||||
|
<div class="flex-1 bg-white p-4 overflow-hidden">
|
||||||
|
<div class="text-2xl font-bold mr-12 truncate">
|
||||||
|
仓库:{{ commit.repo.name }}
|
||||||
|
</div>
|
||||||
|
<span class="text-xl">{{ commit.content.HeadCommit.Message }}</span>
|
||||||
|
<span class="absolute top-0 right-0 m-4 bg-gray-300 px-2 rounded hidden sm:block">
|
||||||
|
{{ commit.content.HeadCommit.Sha1.slice(0, 10) }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="absolute bottom-0 right-0 m-4 bg-gray-300 px-2 rounded">
|
||||||
|
<font-awesome-icon :icon="['far', 'clock']" class="mr-1 text-sm"/>
|
||||||
|
{{ time }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -22,7 +22,7 @@ const handleReload = () => {
|
|||||||
</div>
|
</div>
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else class="w-full">
|
||||||
<!-- 错误处理 -->
|
<!-- 错误处理 -->
|
||||||
<div v-if="error" class="flex h-56 flex-col items-center justify-center" @click="handleReload">
|
<div v-if="error" class="flex h-56 flex-col items-center justify-center" @click="handleReload">
|
||||||
<span class="mb-4 text-8xl">❌</span>
|
<span class="mb-4 text-8xl">❌</span>
|
||||||
|
@ -15,11 +15,11 @@ import {
|
|||||||
faChevronRight,
|
faChevronRight,
|
||||||
faCodeCommit
|
faCodeCommit
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import {faWeibo, faQq, faGithubAlt, faSteamSymbol} from '@fortawesome/free-brands-svg-icons'
|
import {faWeibo, faQq, faGithubAlt, faSteamSymbol, faGitAlt} from '@fortawesome/free-brands-svg-icons'
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
faClock, faXmark, faBlog, faGauge, faCodeBranch, faCloud, faWeibo, faQq, faGithubAlt, faSteamSymbol, faChevronRight,
|
faClock, faXmark, faBlog, faGauge, faCodeBranch, faCloud, faWeibo, faQq, faGithubAlt, faSteamSymbol, faChevronRight,
|
||||||
faCodeCommit
|
faCodeCommit, faGitAlt
|
||||||
)
|
)
|
||||||
|
|
||||||
createApp(App).use(router).component('font-awesome-icon', FontAwesomeIcon).mount('#app')
|
createApp(App).use(router).component('font-awesome-icon', FontAwesomeIcon).mount('#app')
|
||||||
|
27
src/types/git.d.ts
vendored
Normal file
27
src/types/git.d.ts
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
declare interface IActivity<T = string> {
|
||||||
|
id: string;
|
||||||
|
content: T
|
||||||
|
op_type: string
|
||||||
|
repo: {
|
||||||
|
name: string
|
||||||
|
html_url: string
|
||||||
|
}
|
||||||
|
created: string
|
||||||
|
}
|
||||||
|
|
||||||
|
declare interface IContent {
|
||||||
|
Commits: ICommit[]
|
||||||
|
HeadCommit: ICommit
|
||||||
|
CompareURL: string
|
||||||
|
Len: number
|
||||||
|
}
|
||||||
|
|
||||||
|
declare interface ICommit {
|
||||||
|
Sha1: string,
|
||||||
|
Message: string,
|
||||||
|
AuthorEmail: string,
|
||||||
|
AuthorName: string,
|
||||||
|
CommitterEmail: string,
|
||||||
|
CommitterName: string,
|
||||||
|
Timestamp: string
|
||||||
|
}
|
@ -6,8 +6,11 @@ import NavBar from "@/components/nav/NavBar.vue";
|
|||||||
import IntroCard from "@/components/card/IntroCard.vue";
|
import IntroCard from "@/components/card/IntroCard.vue";
|
||||||
import CardTitle from "@/components/card/CardTitle.vue";
|
import CardTitle from "@/components/card/CardTitle.vue";
|
||||||
import SectionCard from "@/components/card/SectionCard.vue";
|
import SectionCard from "@/components/card/SectionCard.vue";
|
||||||
|
import {getActivity} from "@/api/git.ts";
|
||||||
|
import GitCard from "@/components/card/GitCard.vue";
|
||||||
|
|
||||||
const recentPosts = ref<IPost[] | null>(null);
|
const recentPosts = ref<IPost[] | null>(null);
|
||||||
|
const recentActivities = ref<IActivity[] | null>(null);
|
||||||
const isLoading = ref({
|
const isLoading = ref({
|
||||||
blog: true,
|
blog: true,
|
||||||
git: true
|
git: true
|
||||||
@ -18,12 +21,21 @@ const isError = ref({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const hasPosts = computed(() => (recentPosts.value ?? []).length > 0);
|
const hasPosts = computed(() => (recentPosts.value ?? []).length > 0);
|
||||||
|
const hasActivities = computed(() => (recentActivities.value ?? []).length > 0);
|
||||||
const postsData = computed(() => {
|
const postsData = computed(() => {
|
||||||
if (!recentPosts.value) return [];
|
if (!recentPosts.value) return [];
|
||||||
if (recentPosts.value.length > 4)
|
if (recentPosts.value.length > 4)
|
||||||
return recentPosts.value.slice(0, 4)
|
return recentPosts.value.slice(0, 4)
|
||||||
return recentPosts.value
|
return recentPosts.value
|
||||||
})
|
})
|
||||||
|
const activitiesData = computed((): IActivity<IContent>[] => {
|
||||||
|
if (!recentActivities.value) return [];
|
||||||
|
return recentActivities.value.map(obj => ({
|
||||||
|
...obj,
|
||||||
|
content: JSON.parse(obj.content)
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
const reloadPosts = async () => {
|
const reloadPosts = async () => {
|
||||||
try {
|
try {
|
||||||
@ -37,15 +49,21 @@ const reloadPosts = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
const reloadActivities = async () => {
|
||||||
try {
|
try {
|
||||||
const postData = await getBlogRecentPost();
|
isLoading.value.git = true
|
||||||
recentPosts.value = postData.data.dataSet
|
recentActivities.value = await getActivity()
|
||||||
isLoading.value.blog = false
|
console.log(recentActivities.value)
|
||||||
|
isLoading.value.git = false
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
isLoading.value.blog = false
|
isLoading.value.git = false
|
||||||
isError.value.blog = true
|
isError.value.git = true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await reloadPosts()
|
||||||
|
await reloadActivities()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -75,6 +93,14 @@ onMounted(async () => {
|
|||||||
<section class="my-4 w-full px-4 sm:px-0">
|
<section class="my-4 w-full px-4 sm:px-0">
|
||||||
<card-title :icon="['fas', 'code-commit']" main-color="bg-green-500" sub-color="bg-green-600" title="最近活动"
|
<card-title :icon="['fas', 'code-commit']" main-color="bg-green-500" sub-color="bg-green-600" title="最近活动"
|
||||||
url="/git/"/>
|
url="/git/"/>
|
||||||
|
|
||||||
|
<section-card :empty="!hasActivities" :error="isError.git" :loading="isLoading.git" @reload="reloadActivities">
|
||||||
|
<template v-slot:default>
|
||||||
|
<div class="grid w-full grid-cols-1 gap-4 lg:grid-cols-2">
|
||||||
|
<git-card v-for="item in activitiesData" :key="item.id" :commit="item"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</section-card>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
export default {
|
export default {
|
||||||
content: [
|
content: [
|
||||||
"./index.html",
|
"./index.html",
|
||||||
"./src/**/*.{vue,js,ts,jsx,tsx}",
|
"./src/**/*.{vue,js,ts,jsx,tsx}",
|
||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user