refactor: ♻️ 控制台统计数据动态完善
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="dashboard-container">
|
<div class="dashboard-container">
|
||||||
<!-- github角标 -->
|
|
||||||
<github-corner class="github-corner" />
|
<github-corner class="github-corner" />
|
||||||
|
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
@@ -55,7 +54,7 @@
|
|||||||
|
|
||||||
<div class="flex-x-between mt-2">
|
<div class="flex-x-between mt-2">
|
||||||
<span class="text-lg"> 1</span>
|
<span class="text-lg"> 1</span>
|
||||||
<svg-icon icon-class="item.iconClass" size="2em" />
|
<svg-icon icon-class="user" size="2em" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="flex-x-between mt-2 text-sm text-[var(--el-text-color-secondary)]"
|
class="flex-x-between mt-2 text-sm text-[var(--el-text-color-secondary)]"
|
||||||
@@ -103,7 +102,9 @@
|
|||||||
<span class="text-[var(--el-text-color-secondary)]">{{
|
<span class="text-[var(--el-text-color-secondary)]">{{
|
||||||
item.title
|
item.title
|
||||||
}}</span>
|
}}</span>
|
||||||
<el-tag type="primary" size="small"> 日 </el-tag>
|
<el-tag :type="item.tagType" size="small">
|
||||||
|
{{ item.granularity }}
|
||||||
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -111,26 +112,25 @@
|
|||||||
<div class="flex-y-center">
|
<div class="flex-y-center">
|
||||||
<span class="text-lg"> {{ item.todayCount }}</span>
|
<span class="text-lg"> {{ item.todayCount }}</span>
|
||||||
<span
|
<span
|
||||||
v-if="item.growthRate"
|
|
||||||
:class="[
|
:class="[
|
||||||
'text-xs',
|
'text-xs',
|
||||||
'ml-2',
|
'ml-2',
|
||||||
item.growthRate > 0 ? 'color-red' : 'color-green',
|
getGrowthRateClass(item.growthRate),
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<i-ep-top v-if="item.growthRate > 0" />
|
<i-ep-top v-if="item.growthRate > 0" />
|
||||||
<i-ep-bottom v-else-if="item.growthRate < 0" />
|
<i-ep-bottom v-else-if="item.growthRate < 0" />
|
||||||
{{ Math.abs(item.growthRate * 100).toFixed(2) }}%
|
{{ formatGrowthRate(item.growthRate) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<svg-icon :icon-class="item.type" size="2em" />
|
<svg-icon :icon-class="item.icon" size="2em" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="flex-x-between mt-2 text-sm text-[var(--el-text-color-secondary)]"
|
class="flex-x-between mt-2 text-sm text-[var(--el-text-color-secondary)]"
|
||||||
>
|
>
|
||||||
<span>总{{ item.title }} </span>
|
<span>总{{ item.title }} </span>
|
||||||
<span> {{ item.totalCountOutput }} </span>
|
<span> {{ item.totalCount }} </span>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
@@ -168,8 +168,6 @@ defineOptions({
|
|||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
import type { EpPropMergeType } from "element-plus/es/utils/vue/props/types";
|
|
||||||
|
|
||||||
import { useUserStore } from "@/store/modules/user";
|
import { useUserStore } from "@/store/modules/user";
|
||||||
import { useTransition, TransitionPresets } from "@vueuse/core";
|
import { useTransition, TransitionPresets } from "@vueuse/core";
|
||||||
|
|
||||||
@@ -202,7 +200,7 @@ const statisticData = ref([
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 50,
|
value: 50,
|
||||||
iconClass: "todolist",
|
iconClass: "todo",
|
||||||
title: "待办",
|
title: "待办",
|
||||||
suffix: "/100",
|
suffix: "/100",
|
||||||
key: "upcoming",
|
key: "upcoming",
|
||||||
@@ -244,24 +242,80 @@ const notices = ref([
|
|||||||
|
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
|
|
||||||
const visitStatsList = ref<VisitStatsVO[] | null>(Array(3).fill({}));
|
const visitStatsList = ref<VisitStats[] | null>(Array(3).fill({}));
|
||||||
|
|
||||||
|
interface VisitStats {
|
||||||
|
title: string;
|
||||||
|
icon: string;
|
||||||
|
tagType: "primary" | "success" | "warning";
|
||||||
|
growthRate: number;
|
||||||
|
/** 粒度 */
|
||||||
|
granularity: string;
|
||||||
|
/** 今日数量输出文档 */
|
||||||
|
todayCount: number;
|
||||||
|
totalCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
const loadVisitStatsData = async () => {
|
const loadVisitStatsData = async () => {
|
||||||
const list = await StatsAPI.getVisitStats();
|
const list: VisitStatsVO[] = await StatsAPI.getVisitStats();
|
||||||
|
|
||||||
if (list) {
|
if (list) {
|
||||||
visitStatsList.value = list;
|
const tagTypes: ("primary" | "success" | "warning")[] = [
|
||||||
// 初始化动画输出
|
"primary",
|
||||||
list.forEach((item) => {
|
"success",
|
||||||
item.totalCountOutput = useTransition(item.totalCount, {
|
"warning",
|
||||||
duration: 1000,
|
];
|
||||||
transition: TransitionPresets.easeOutExpo,
|
const transformedList: VisitStats[] = list.map((item, index) => ({
|
||||||
}).value;
|
title: item.title,
|
||||||
});
|
icon: getVisitStatsIcon(item.type),
|
||||||
|
tagType: tagTypes[index % tagTypes.length],
|
||||||
|
growthRate: item.growthRate,
|
||||||
|
granularity: "日",
|
||||||
|
todayCount: item.todayCount,
|
||||||
|
totalCount: item.totalCount,
|
||||||
|
}));
|
||||||
|
visitStatsList.value = transformedList;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 格式化增长率 */
|
||||||
|
const formatGrowthRate = (growthRate: number): string => {
|
||||||
|
if (growthRate === 0) {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
const formattedRate = Math.abs(growthRate * 100)
|
||||||
|
.toFixed(2)
|
||||||
|
.replace(/\.?0+$/, "");
|
||||||
|
return formattedRate + "%";
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 获取增长率文本颜色类 */
|
||||||
|
const getGrowthRateClass = (growthRate: number): string => {
|
||||||
|
if (growthRate > 0) {
|
||||||
|
return "color-[--el-color-danger]";
|
||||||
|
} else if (growthRate < 0) {
|
||||||
|
return "color-[--el-color-success]";
|
||||||
|
} else {
|
||||||
|
return "color-[--el-color-info]";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 获取访问统计图标 */
|
||||||
|
const getVisitStatsIcon = (type: string) => {
|
||||||
|
switch (type) {
|
||||||
|
case "pv":
|
||||||
|
return "pv";
|
||||||
|
case "uv":
|
||||||
|
return "uv";
|
||||||
|
case "ip":
|
||||||
|
return "ip";
|
||||||
|
default:
|
||||||
|
return "pv";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadVisitStatsData();
|
loadVisitStatsData();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user