This commit is contained in:
leokun
2026-06-30 10:38:52 +08:00
commit c083be5ec2
312 changed files with 146628 additions and 0 deletions
@@ -0,0 +1,128 @@
<script setup>
import {
ArcElement,
Chart as ChartJS,
Tooltip,
} from "chart.js";
import { computed } from "vue";
import { Doughnut } from "vue-chartjs";
ChartJS.register(ArcElement, Tooltip);
const props = defineProps({
rate: {
type: Number,
default: 0,
},
});
const percentage = computed(() => {
const rate = Number(props.rate);
if (!Number.isFinite(rate)) {
return 0;
}
return Math.max(0, Math.min(100, rate * 100));
});
const label = computed(() => {
const rate = Number(props.rate);
if (!Number.isFinite(rate)) {
return "--";
}
return `${percentage.value.toFixed(2)}%`;
});
function getSegmentBorderRadius(dataIndex) {
const radius = 5;
if (percentage.value <= 0) {
return dataIndex === 1
? {
outerStart: radius,
outerEnd: radius,
innerStart: radius,
innerEnd: radius,
}
: 0;
}
if (percentage.value >= 100) {
return dataIndex === 0
? {
outerStart: radius,
outerEnd: radius,
innerStart: radius,
innerEnd: radius,
}
: 0;
}
return dataIndex === 0
? {
outerStart: radius,
outerEnd: 0,
innerStart: radius,
innerEnd: 0,
}
: {
outerStart: 0,
outerEnd: radius,
innerStart: 0,
innerEnd: radius,
};
}
const chartData = computed(() => ({
labels: ["命中", "未命中"],
datasets: [
{
data: [percentage.value, Math.max(0, 100 - percentage.value)],
backgroundColor: ["#4ade80", "#373737"],
borderWidth: 0,
hoverBorderWidth: 0,
selfJoin: false,
borderRadius: ({ dataIndex }) => getSegmentBorderRadius(dataIndex),
},
],
}));
const chartOptions = {
responsive: true,
maintainAspectRatio: false,
cutout: "82%",
rotation: -90,
circumference: 180,
animation: {
duration: 450,
},
events: [],
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: false,
},
},
};
</script>
<template>
<div class="flex flex-col items-center gap-3">
<div
class="relative h-[82px] w-[132px] shrink-0"
role="img"
:aria-label="`缓存命中率 ${label}`"
>
<Doughnut class="h-full w-full" :data="chartData" :options="chartOptions" />
<div class="pointer-events-none absolute inset-x-0 bottom-[10px] flex justify-center">
<div
class="text-[20px] leading-none text-white"
style="font-family: var(--font-num)"
>
{{ label }}
</div>
</div>
</div>
</div>
</template>