mirror of
https://github.com/certd/certd.git
synced 2026-04-24 04:17:25 +08:00
perf: 优化首页统计数据,饼图替换成证书数量统计
This commit is contained in:
@@ -88,6 +88,14 @@ export default {
|
||||
helpDoc: "Help Docs",
|
||||
pipelineCount: "Number of Certificate Pipelines",
|
||||
noPipeline: "You have no certificate pipelines yet",
|
||||
enabledCount: "Enabled",
|
||||
disabledCount: "Disabled",
|
||||
certCount: "Number of Certificates",
|
||||
noCert: "You have no certificates yet",
|
||||
manageCert: "View Certificates",
|
||||
certExpiringCount: "Soon-to-Expire",
|
||||
certExpiredCount: "Expired",
|
||||
certNoExpireCount: "Not Expired",
|
||||
createNow: "Create Now",
|
||||
managePipeline: "Manage Pipelines",
|
||||
pipelineStatus: "Pipeline Status",
|
||||
|
||||
@@ -93,7 +93,16 @@ export default {
|
||||
alertMessage: "证书和授权为敏感信息,不要使用来历不明的在线Certd服务和镜像,以免泄露;请务必私有化部署使用,认准官方版本发布渠道:",
|
||||
helpDoc: "帮助文档",
|
||||
pipelineCount: "证书流水线数量",
|
||||
enabledCount: "已启用",
|
||||
disabledCount: "已禁用",
|
||||
noPipeline: "您还没有证书流水线",
|
||||
certCount: "证书数量",
|
||||
certExpiringCount: "即将过期",
|
||||
certExpiredCount: "已过期",
|
||||
certNoExpireCount: "未过期",
|
||||
noCert: "还没有证书",
|
||||
manageCert: "查看证书",
|
||||
|
||||
createNow: "立即创建",
|
||||
managePipeline: "管理流水线",
|
||||
pipelineStatus: "流水线状态",
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
<div class="statistic-data m-20">
|
||||
<a-row :gutter="20" class="flex-wrap">
|
||||
<a-col :md="6" :xs="24">
|
||||
<statistic-card :title="t('certd.dashboard.pipelineCount')" :count="count.pipelineCount">
|
||||
<statistic-card :title="t('certd.dashboard.pipelineCount')" :count="count.pipelineCount" :sub-counts="count.pipelineEnableCount">
|
||||
<template v-if="count.pipelineCount === 0" #default>
|
||||
<div class="flex-center flex-1 flex-col">
|
||||
<div style="font-size: 18px; font-weight: 700">{{ t("certd.dashboard.noPipeline") }}</div>
|
||||
@@ -79,10 +79,22 @@
|
||||
</template>
|
||||
</statistic-card>
|
||||
</a-col>
|
||||
<a-col :md="6" :xs="24">
|
||||
<!-- <a-col :md="6" :xs="24">
|
||||
<statistic-card :title="t('certd.dashboard.pipelineStatus')" :footer="false">
|
||||
<pie-count v-if="count.pipelineStatusCount" :data="count.pipelineStatusCount"></pie-count>
|
||||
</statistic-card>
|
||||
</a-col> -->
|
||||
<a-col :md="6" :xs="24">
|
||||
<statistic-card :title="t('certd.dashboard.certCount')" :count="count.certCount" :sub-counts="count.certStatusCount">
|
||||
<template v-if="count.certCount === 0" #default>
|
||||
<div class="flex-center flex-1 flex-col">
|
||||
<div style="font-size: 18px; font-weight: 700">{{ t("certd.dashboard.noCert") }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<router-link to="/certd/monitor/cert" class="flex"> <fs-icon icon="ion:settings-outline" class="mr-5 fs-16" /> {{ t("certd.dashboard.manageCert") }} </router-link>
|
||||
</template>
|
||||
</statistic-card>
|
||||
</a-col>
|
||||
<a-col :md="6" :xs="24">
|
||||
<statistic-card :title="t('certd.dashboard.recentRun')" :footer="false">
|
||||
@@ -242,6 +254,19 @@ function transformStatusCount() {
|
||||
}
|
||||
}
|
||||
count.value.pipelineStatusCount = result;
|
||||
|
||||
const pipelineEnableCount = count.value.pipelineEnableCount;
|
||||
count.value.pipelineEnableCount = [
|
||||
{ name: t("certd.dashboard.enabledCount"), value: pipelineEnableCount.enabled, color: "green" },
|
||||
{ name: t("certd.dashboard.disabledCount"), value: pipelineEnableCount.disabled, color: "gray" },
|
||||
];
|
||||
const certCount = count.value.certCount;
|
||||
count.value.certStatusCount = [
|
||||
{ name: t("certd.dashboard.certExpiredCount"), value: certCount.expired, color: "red", checkIcon: "mingcute:warning-fill:#f44336" },
|
||||
{ name: t("certd.dashboard.certExpiringCount"), value: certCount.expiring, color: "yellow", checkIcon: "mingcute:alert-fill:#ff9800" },
|
||||
{ name: t("certd.dashboard.certNoExpireCount"), value: certCount.notExpired, color: "green" },
|
||||
];
|
||||
count.value.certCount = certCount.total;
|
||||
}
|
||||
async function loadCount() {
|
||||
count.value = await GetStatisticCount();
|
||||
|
||||
@@ -8,7 +8,27 @@
|
||||
</div>
|
||||
<div class="content">
|
||||
<div v-if="!slots.default" class="statistic">
|
||||
<div v-if="count !== 0" class="value">{{ count }}</div>
|
||||
<div v-if="count !== 0" class="value flex items-center w-full">
|
||||
<div class="total flex-center flex-1 flex-col">
|
||||
<span>{{ count }}</span>
|
||||
<span class="title">{{ title }}</span>
|
||||
</div>
|
||||
<a-divider type="vertical h-10"></a-divider>
|
||||
<div class="sub flex-1 flex-col h-[80%] flex-between pl-4">
|
||||
<div v-for="item in subCounts" :key="item.name" class="sub-item flex justify-center w-full">
|
||||
<div class="flex items-center w-[60%] ellipsis overflow-hidden">
|
||||
<div class="status-indicator" :class="`bg-${item.color}`"></div>
|
||||
{{ item.name }}:
|
||||
</div>
|
||||
<div class="w-[40%] flex items-center justify-center relative">
|
||||
<span class="icon-text">{{ item.value }}</span>
|
||||
<div v-if="item.value !== 0 && item.checkIcon" class="ml-2 flex items-center absolute right-0">
|
||||
<fs-icon :icon="item.checkIcon" class="fs-icon"></fs-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-empty v-else></a-empty>
|
||||
</div>
|
||||
<slot></slot>
|
||||
@@ -25,51 +45,103 @@ import { FsIcon } from "@fast-crud/fast-crud";
|
||||
const props = defineProps<{
|
||||
title: string;
|
||||
count?: number;
|
||||
subCounts?: {
|
||||
name: string;
|
||||
value: number;
|
||||
color: string;
|
||||
checkIcon?: string;
|
||||
}[];
|
||||
}>();
|
||||
const slots = defineSlots();
|
||||
</script>
|
||||
<style lang="less">
|
||||
.statistic-card {
|
||||
margin-bottom: 10px;
|
||||
|
||||
.icon-text {
|
||||
display: inline-flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
|
||||
.fs-icon {
|
||||
margin-right: 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.data-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 188px;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
//padding-bottom: 10px;
|
||||
color: #8077a4;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
|
||||
.statistic {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.value {
|
||||
font-size: 50px;
|
||||
font-weight: 700;
|
||||
color: #2c254e;
|
||||
color: #323232;
|
||||
|
||||
.total {
|
||||
.title {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #8077a4;
|
||||
}
|
||||
}
|
||||
|
||||
.sub-item {
|
||||
font-size: 14px;
|
||||
|
||||
.status-indicator {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
margin-right: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.bg-green {
|
||||
background: linear-gradient(90deg, #4caf50, #8bc34a);
|
||||
}
|
||||
|
||||
.bg-red {
|
||||
background: linear-gradient(90deg, #f44336, #e57373);
|
||||
}
|
||||
|
||||
.bg-yellow {
|
||||
background: linear-gradient(90deg, #ff9800, #ffc107);
|
||||
}
|
||||
.bg-blue {
|
||||
background: linear-gradient(90deg, #2196f3, #64b5f6);
|
||||
}
|
||||
.bg-gray {
|
||||
background: linear-gradient(90deg, #9e9e9e, #bdbdbd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x-vue-echarts {
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
color: #8077a4;
|
||||
font-size: 12px;
|
||||
@@ -81,9 +153,11 @@ const slots = defineSlots();
|
||||
border-style: dashed;
|
||||
border-width: 1px 0 0;
|
||||
padding-top: 15px;
|
||||
|
||||
> * {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user