mirror of
https://github.com/keven1024/015.git
synced 2026-05-26 07:08:02 +00:00
feat(front): enhance About page components to support shares and downloads statistics, improve layout, and add loading state
This commit is contained in:
@@ -24,6 +24,7 @@ const { data, isLoading } = useQuery({
|
||||
name?: string
|
||||
email?: string
|
||||
url?: string
|
||||
content?: Record<string, string>
|
||||
}
|
||||
}>('/api/about')
|
||||
return data?.data
|
||||
@@ -65,7 +66,7 @@ const genUserAvatar = (email: string) => {
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<div class="rounded-xl bg-white/50 flex-1 flex flex-col p-3 gap-2">
|
||||
<div class="opacity-75 text-xs">{{ t('about.admin') }}</div>
|
||||
<div
|
||||
@@ -106,4 +107,21 @@ const genUserAvatar = (email: string) => {
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="isLoading">
|
||||
<Skeleton class="w-full h-16 rounded-xl" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<div v-if="data?.content" class="rounded-xl bg-white/50 flex flex-col px-3 gap-2">
|
||||
<Accordion type="single" collapsible>
|
||||
<AccordionItem value="about">
|
||||
<AccordionTrigger>
|
||||
<span class="font-semibold">{{ t('about.about') }}</span>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<MarkdownRender :markdown="renderI18n(data?.content ?? {}, 'en', locale) ?? ''" />
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -8,9 +8,11 @@ import AboutChartTooltip from '@/components/AboutChartTooltip.vue'
|
||||
import dayjs from 'dayjs'
|
||||
import { times } from 'lodash-es'
|
||||
|
||||
interface FileChartData {
|
||||
interface StatChartData {
|
||||
file_size: number
|
||||
file_num: number
|
||||
share_num: number
|
||||
download_num: number
|
||||
date: string
|
||||
}
|
||||
|
||||
@@ -20,7 +22,7 @@ interface QueueChartData {
|
||||
date: string
|
||||
}
|
||||
|
||||
type ChartDataItem = FileChartData | QueueChartData
|
||||
type ChartDataItem = StatChartData | QueueChartData
|
||||
|
||||
type ChartConfig = {
|
||||
data: ChartDataItem[]
|
||||
@@ -35,7 +37,7 @@ const { data, isLoading } = useQuery({
|
||||
const response = await $fetch<{
|
||||
data: {
|
||||
chart: {
|
||||
storage: Record<string, FileChartData>
|
||||
storage: Record<string, StatChartData>
|
||||
queue: Record<string, QueueChartData>
|
||||
}
|
||||
}
|
||||
@@ -52,7 +54,21 @@ const chartTabs = computed(() => {
|
||||
label: t('about.file'),
|
||||
value: 'storage',
|
||||
total: data.value?.chart?.storage
|
||||
? Object.values(data.value.chart.storage).reduce((acc: number, curr: FileChartData) => acc + curr.file_num, 0)
|
||||
? Object.values(data.value.chart.storage).reduce((acc: number, curr: StatChartData) => acc + curr.file_num, 0)
|
||||
: 0,
|
||||
},
|
||||
{
|
||||
label: t('about.share'),
|
||||
value: 'share',
|
||||
total: data.value?.chart?.storage
|
||||
? Object.values(data.value.chart.storage).reduce((acc: number, curr: StatChartData) => acc + curr.share_num, 0)
|
||||
: 0,
|
||||
},
|
||||
{
|
||||
label: t('about.download'),
|
||||
value: 'download',
|
||||
total: data.value?.chart?.storage
|
||||
? Object.values(data.value.chart.storage).reduce((acc: number, curr: StatChartData) => acc + curr.download_num, 0)
|
||||
: 0,
|
||||
},
|
||||
{
|
||||
@@ -65,24 +81,10 @@ const chartTabs = computed(() => {
|
||||
]
|
||||
})
|
||||
|
||||
const currentChartTab = ref<'storage' | 'queue'>('storage')
|
||||
const currentChartTab = ref<'storage' | 'queue' | 'share' | 'download'>('storage')
|
||||
const currentChartData = computed((): ChartConfig => {
|
||||
const { storage, queue } = data.value?.chart || {}
|
||||
if (currentChartTab.value === 'storage') {
|
||||
const storageData = times(30, (i) => {
|
||||
return {
|
||||
date: dayjs().subtract(i, 'day').format('YYYY-MM-DD'),
|
||||
file_size: storage?.[dayjs().subtract(i, 'day').format('YYYY-MM-DD')]?.file_size || 0,
|
||||
file_num: storage?.[dayjs().subtract(i, 'day').format('YYYY-MM-DD')]?.file_num || 0,
|
||||
}
|
||||
})
|
||||
return {
|
||||
data: storageData,
|
||||
index: 'date' as const,
|
||||
categories: ['file_size', 'file_num'] as const,
|
||||
colors: ['#22d3ee', '#c084fc'],
|
||||
}
|
||||
}
|
||||
if (currentChartTab.value === 'queue') {
|
||||
const queueData = times(30, (i) => {
|
||||
return {
|
||||
date: dayjs().subtract(i, 'day').format('YYYY-MM-DD'),
|
||||
@@ -96,6 +98,48 @@ const currentChartData = computed((): ChartConfig => {
|
||||
categories: ['processed', 'failed'] as const,
|
||||
colors: ['#4ade80', '#f87171'],
|
||||
}
|
||||
}
|
||||
const storageData = times(30, (i) => {
|
||||
const base = { date: dayjs().subtract(i, 'day').format('YYYY-MM-DD') }
|
||||
if (currentChartTab.value === 'share') {
|
||||
return {
|
||||
...base,
|
||||
share_num: storage?.[dayjs().subtract(i, 'day').format('YYYY-MM-DD')]?.share_num || 0,
|
||||
}
|
||||
}
|
||||
if (currentChartTab.value === 'download') {
|
||||
return {
|
||||
...base,
|
||||
download_num: storage?.[dayjs().subtract(i, 'day').format('YYYY-MM-DD')]?.download_num || 0,
|
||||
}
|
||||
}
|
||||
return {
|
||||
...base,
|
||||
file_size: storage?.[dayjs().subtract(i, 'day').format('YYYY-MM-DD')]?.file_size || 0,
|
||||
file_num: storage?.[dayjs().subtract(i, 'day').format('YYYY-MM-DD')]?.file_num || 0,
|
||||
}
|
||||
})
|
||||
|
||||
let categories = ['file_size', 'file_num']
|
||||
if (currentChartTab.value === 'share') {
|
||||
categories = ['share_num']
|
||||
}
|
||||
if (currentChartTab.value === 'download') {
|
||||
categories = ['download_num']
|
||||
}
|
||||
let colors = ['#38bdf8', '#a78bfa']
|
||||
if (currentChartTab.value === 'share') {
|
||||
colors = ['#ea580c']
|
||||
}
|
||||
if (currentChartTab.value === 'download') {
|
||||
colors = ['#a3e635']
|
||||
}
|
||||
return {
|
||||
data: storageData as ChartDataItem[],
|
||||
index: 'date' as const,
|
||||
categories,
|
||||
colors,
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -108,7 +152,7 @@ const currentChartData = computed((): ChartConfig => {
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="flex flex-col gap-2 bg-white/50 w-full rounded-xl py-5">
|
||||
<div class="flex flex-row gap-2 px-5">
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-2 px-5">
|
||||
<div
|
||||
:class="cx('rounded-md min-w-30 flex flex-col px-3 py-1.5 cursor-pointer', currentChartTab === tab.value && 'bg-black/10')"
|
||||
v-for="tab in chartTabs"
|
||||
|
||||
@@ -107,10 +107,13 @@
|
||||
"about": {
|
||||
"powerBy": "Power by {0} as a open source temporary file sharing platform",
|
||||
"file": "File",
|
||||
"share": "Share",
|
||||
"download": "Download",
|
||||
"task": "Task",
|
||||
"admin": "Site Admin",
|
||||
"author": "Author",
|
||||
"title": "About",
|
||||
"about": "About",
|
||||
"systemInfo": "System Info",
|
||||
"systemVersion": "System Version",
|
||||
"storage": "Storage",
|
||||
|
||||
@@ -107,10 +107,13 @@
|
||||
"about": {
|
||||
"powerBy": "由 {0} 驱动的开源自托管临时文件分享平台",
|
||||
"file": "文件",
|
||||
"share": "分享",
|
||||
"download": "下载",
|
||||
"task": "任务",
|
||||
"admin": "本站管理员",
|
||||
"author": "作者",
|
||||
"title": "关于",
|
||||
"about": "关于",
|
||||
"systemInfo": "系统信息",
|
||||
"systemVersion": "系统版本",
|
||||
"storage": "已托管的文件",
|
||||
|
||||
Reference in New Issue
Block a user