refactor(dashboard): 重构仪表盘模块架构
- 将监控相关组件重构为通用仪表盘组件 - 重命名 DashboardStatCard 和 LoginTrendChart 组件 - 重构主页面结构,简化组件层级 - 删除不再使用的图表组件和模拟数据 - 优化类型定义结构
This commit is contained in:
parent
3dbcf80402
commit
d6bee84581
@ -1,423 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="operation-pie-chart">
|
|
||||||
<!-- 图表容器 -->
|
|
||||||
<div class="chart-container">
|
|
||||||
<svg
|
|
||||||
class="pie-svg"
|
|
||||||
:width="chartSize"
|
|
||||||
:height="chartSize"
|
|
||||||
:viewBox="`0 0 ${chartSize} ${chartSize}`"
|
|
||||||
>
|
|
||||||
<!-- 饼图片段 -->
|
|
||||||
<g class="pie-segments" :transform="`translate(${center}, ${center})`">
|
|
||||||
<path
|
|
||||||
v-for="(segment, index) in pieSegments"
|
|
||||||
:key="index"
|
|
||||||
:d="segment.path"
|
|
||||||
:fill="segment.color"
|
|
||||||
class="pie-segment" :class="[{ active: hoveredIndex === index }]"
|
|
||||||
@mouseenter="hoverSegment(index, $event)"
|
|
||||||
@mouseleave="unhoverSegment"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
|
|
||||||
<!-- 中心文字 -->
|
|
||||||
<g class="center-text" :transform="`translate(${center}, ${center})`">
|
|
||||||
<text
|
|
||||||
x="0"
|
|
||||||
y="-10"
|
|
||||||
text-anchor="middle"
|
|
||||||
class="center-title"
|
|
||||||
>
|
|
||||||
总操作数
|
|
||||||
</text>
|
|
||||||
<text
|
|
||||||
x="0"
|
|
||||||
y="15"
|
|
||||||
text-anchor="middle"
|
|
||||||
class="center-value"
|
|
||||||
>
|
|
||||||
{{ totalOperations.toLocaleString() }}
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
<!-- 工具提示 -->
|
|
||||||
<div
|
|
||||||
v-if="tooltip.visible"
|
|
||||||
class="chart-tooltip"
|
|
||||||
:style="tooltipStyle"
|
|
||||||
>
|
|
||||||
<div class="tooltip-content">
|
|
||||||
<div class="tooltip-header">
|
|
||||||
<span class="tooltip-dot" :style="{ backgroundColor: tooltip.color }" />
|
|
||||||
<span class="tooltip-type">{{ tooltip.type }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="tooltip-stats">
|
|
||||||
<div>数量: {{ tooltip.count?.toLocaleString() }}</div>
|
|
||||||
<div>占比: {{ tooltip.percentage }}%</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 图例 -->
|
|
||||||
<div class="chart-legend">
|
|
||||||
<div
|
|
||||||
v-for="(item, index) in chartData"
|
|
||||||
:key="index"
|
|
||||||
class="legend-item"
|
|
||||||
:class="{ active: hoveredIndex === index }"
|
|
||||||
@mouseenter="hoverSegment(index)"
|
|
||||||
@mouseleave="unhoverSegment"
|
|
||||||
>
|
|
||||||
<div class="legend-color" :style="{ backgroundColor: item.color }" />
|
|
||||||
<div class="legend-content">
|
|
||||||
<div class="legend-type">
|
|
||||||
{{ item.type }}
|
|
||||||
</div>
|
|
||||||
<div class="legend-stats">
|
|
||||||
<span class="legend-count">{{ item.count.toLocaleString() }}</span>
|
|
||||||
<span class="legend-percentage">{{ item.percentage }}%</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { computed, reactive, ref } from 'vue'
|
|
||||||
|
|
||||||
// Props定义
|
|
||||||
interface OperationData {
|
|
||||||
type: string
|
|
||||||
count: number
|
|
||||||
percentage: number
|
|
||||||
color: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
data: OperationData[]
|
|
||||||
}>()
|
|
||||||
|
|
||||||
// 响应式数据
|
|
||||||
const hoveredIndex = ref<number | null>(null)
|
|
||||||
const chartSize = 240
|
|
||||||
const center = chartSize / 2
|
|
||||||
const radius = 80
|
|
||||||
const innerRadius = 30
|
|
||||||
|
|
||||||
// 工具提示状态
|
|
||||||
const tooltip = reactive({
|
|
||||||
visible: false,
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
type: '',
|
|
||||||
count: 0,
|
|
||||||
percentage: 0,
|
|
||||||
color: '',
|
|
||||||
})
|
|
||||||
|
|
||||||
// 计算属性
|
|
||||||
const chartData = computed(() => props.data || [])
|
|
||||||
|
|
||||||
const totalOperations = computed(() => {
|
|
||||||
return chartData.value.reduce((sum, item) => sum + item.count, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 饼图片段计算
|
|
||||||
const pieSegments = computed(() => {
|
|
||||||
let currentAngle = -Math.PI / 2 // 从顶部开始
|
|
||||||
|
|
||||||
return chartData.value.map((item, index) => {
|
|
||||||
const angleSize = (item.percentage / 100) * 2 * Math.PI
|
|
||||||
const startAngle = currentAngle
|
|
||||||
const endAngle = currentAngle + angleSize
|
|
||||||
|
|
||||||
// 计算路径
|
|
||||||
const path = createArcPath(0, 0, innerRadius, radius, startAngle, endAngle)
|
|
||||||
|
|
||||||
currentAngle = endAngle
|
|
||||||
|
|
||||||
return {
|
|
||||||
path,
|
|
||||||
color: item.color,
|
|
||||||
data: item,
|
|
||||||
index,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// 创建圆弧路径
|
|
||||||
function createArcPath(
|
|
||||||
centerX: number,
|
|
||||||
centerY: number,
|
|
||||||
innerRadius: number,
|
|
||||||
outerRadius: number,
|
|
||||||
startAngle: number,
|
|
||||||
endAngle: number,
|
|
||||||
): string {
|
|
||||||
const startOuterX = centerX + outerRadius * Math.cos(startAngle)
|
|
||||||
const startOuterY = centerY + outerRadius * Math.sin(startAngle)
|
|
||||||
const endOuterX = centerX + outerRadius * Math.cos(endAngle)
|
|
||||||
const endOuterY = centerY + outerRadius * Math.sin(endAngle)
|
|
||||||
|
|
||||||
const startInnerX = centerX + innerRadius * Math.cos(endAngle)
|
|
||||||
const startInnerY = centerY + innerRadius * Math.sin(endAngle)
|
|
||||||
const endInnerX = centerX + innerRadius * Math.cos(startAngle)
|
|
||||||
const endInnerY = centerY + innerRadius * Math.sin(startAngle)
|
|
||||||
|
|
||||||
const largeArcFlag = endAngle - startAngle > Math.PI ? 1 : 0
|
|
||||||
|
|
||||||
return [
|
|
||||||
'M',
|
|
||||||
startOuterX,
|
|
||||||
startOuterY,
|
|
||||||
'A',
|
|
||||||
outerRadius,
|
|
||||||
outerRadius,
|
|
||||||
0,
|
|
||||||
largeArcFlag,
|
|
||||||
1,
|
|
||||||
endOuterX,
|
|
||||||
endOuterY,
|
|
||||||
'L',
|
|
||||||
startInnerX,
|
|
||||||
startInnerY,
|
|
||||||
'A',
|
|
||||||
innerRadius,
|
|
||||||
innerRadius,
|
|
||||||
0,
|
|
||||||
largeArcFlag,
|
|
||||||
0,
|
|
||||||
endInnerX,
|
|
||||||
endInnerY,
|
|
||||||
'Z',
|
|
||||||
].join(' ')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 工具提示样式
|
|
||||||
const tooltipStyle = computed(() => ({
|
|
||||||
left: `${tooltip.x}px`,
|
|
||||||
top: `${tooltip.y}px`,
|
|
||||||
}))
|
|
||||||
|
|
||||||
// 悬停处理
|
|
||||||
function hoverSegment(index: number, event?: MouseEvent) {
|
|
||||||
hoveredIndex.value = index
|
|
||||||
const item = chartData.value[index]
|
|
||||||
|
|
||||||
if (event) {
|
|
||||||
const rect = (event.target as Element).closest('.chart-container')?.getBoundingClientRect()
|
|
||||||
if (rect) {
|
|
||||||
tooltip.visible = true
|
|
||||||
tooltip.x = event.clientX - rect.left + 10
|
|
||||||
tooltip.y = event.clientY - rect.top - 40
|
|
||||||
tooltip.type = item.type
|
|
||||||
tooltip.count = item.count
|
|
||||||
tooltip.percentage = item.percentage
|
|
||||||
tooltip.color = item.color
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function unhoverSegment() {
|
|
||||||
hoveredIndex.value = null
|
|
||||||
tooltip.visible = false
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.operation-pie-chart {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-container {
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pie-svg {
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pie-segment {
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
|
|
||||||
}
|
|
||||||
|
|
||||||
.pie-segment:hover,
|
|
||||||
.pie-segment.active {
|
|
||||||
transform: scale(1.05);
|
|
||||||
filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.2));
|
|
||||||
}
|
|
||||||
|
|
||||||
.center-text .center-title {
|
|
||||||
font-size: 12px;
|
|
||||||
fill: var(--text-color-2);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.center-text .center-value {
|
|
||||||
font-size: 16px;
|
|
||||||
fill: var(--text-color-1);
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-tooltip {
|
|
||||||
position: absolute;
|
|
||||||
background: var(--popover-color);
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
border-radius: 6px;
|
|
||||||
padding: 8px 12px;
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
||||||
z-index: 1000;
|
|
||||||
pointer-events: none;
|
|
||||||
font-size: 12px;
|
|
||||||
min-width: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip-content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--text-color-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip-dot {
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip-stats {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 2px;
|
|
||||||
color: var(--text-color-2);
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-legend {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 8px;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legend-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 6px 8px;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legend-item:hover,
|
|
||||||
.legend-item.active {
|
|
||||||
background: var(--hover-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.legend-color {
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
border-radius: 2px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legend-content {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legend-type {
|
|
||||||
font-size: 13px;
|
|
||||||
color: var(--text-color-1);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legend-stats {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-end;
|
|
||||||
gap: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legend-count {
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--text-color-1);
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legend-percentage {
|
|
||||||
font-size: 11px;
|
|
||||||
color: var(--text-color-3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 响应式设计 */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.operation-pie-chart {
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-container {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legend-item {
|
|
||||||
padding: 4px 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legend-type {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legend-count {
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 动画效果 */
|
|
||||||
.pie-segment {
|
|
||||||
transform-origin: center;
|
|
||||||
animation: fadeInScale 0.6s ease-out forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeInScale {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(0.8);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 为每个片段添加延迟动画 */
|
|
||||||
.pie-segment:nth-child(1) { animation-delay: 0.1s; }
|
|
||||||
.pie-segment:nth-child(2) { animation-delay: 0.2s; }
|
|
||||||
.pie-segment:nth-child(3) { animation-delay: 0.3s; }
|
|
||||||
.pie-segment:nth-child(4) { animation-delay: 0.4s; }
|
|
||||||
.pie-segment:nth-child(5) { animation-delay: 0.5s; }
|
|
||||||
</style>
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="chart-placeholder h-200px w-full flex-center">
|
|
||||||
<div class="text-center">
|
|
||||||
<div class="text-lg font-bold text-gray-400 mb-2">
|
|
||||||
监控图表
|
|
||||||
</div>
|
|
||||||
<div class="text-sm text-gray-500">
|
|
||||||
图表功能已简化
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
// 简化的图表占位组件
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.chart-placeholder {
|
|
||||||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid #e0e0e0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="chart-placeholder h-200px w-full flex-center">
|
|
||||||
<div class="text-center">
|
|
||||||
<div class="text-lg font-bold text-gray-400 mb-2">
|
|
||||||
柱状图
|
|
||||||
</div>
|
|
||||||
<div class="text-sm text-gray-500">
|
|
||||||
图表功能已简化
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
// 简化的图表占位组件
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.chart-placeholder {
|
|
||||||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid #e0e0e0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="chart-placeholder h-200px w-full flex-center">
|
|
||||||
<div class="text-center">
|
|
||||||
<div class="text-lg font-bold text-gray-400 mb-2">
|
|
||||||
饼图
|
|
||||||
</div>
|
|
||||||
<div class="text-sm text-gray-500">
|
|
||||||
图表功能已简化
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
// 简化的图表占位组件
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.chart-placeholder {
|
|
||||||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid #e0e0e0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,116 +0,0 @@
|
|||||||
import type { DashboardData } from './types'
|
|
||||||
|
|
||||||
// 生成模拟仪表盘数据
|
|
||||||
export function generateMockDashboardData(): DashboardData {
|
|
||||||
return {
|
|
||||||
// 用户统计数据
|
|
||||||
userStats: {
|
|
||||||
totalUsers: 1286,
|
|
||||||
todayNewUsers: 23,
|
|
||||||
activeUsers: 856,
|
|
||||||
onlineUsers: 142,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 登录统计数据
|
|
||||||
loginStats: {
|
|
||||||
todayLogins: 468,
|
|
||||||
totalLogins: 45672,
|
|
||||||
loginTrend: generateLoginTrendData(),
|
|
||||||
},
|
|
||||||
|
|
||||||
// 存储统计数据
|
|
||||||
storageStats: {
|
|
||||||
totalFiles: 8924,
|
|
||||||
totalImages: 3420,
|
|
||||||
totalSize: '2.3 GB',
|
|
||||||
todayUploads: 67,
|
|
||||||
storageUsage: 67.5,
|
|
||||||
availableSpace: '1.2 GB',
|
|
||||||
},
|
|
||||||
|
|
||||||
// 今日活跃数据
|
|
||||||
dailyActivityStats: {
|
|
||||||
todayVisits: 1247,
|
|
||||||
todayOperations: 856,
|
|
||||||
activeUsers: 142,
|
|
||||||
newContent: 23,
|
|
||||||
apiCalls: 3420,
|
|
||||||
avgResponseTime: 235,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 系统状态
|
|
||||||
systemStatus: {
|
|
||||||
diskUsage: 67.5,
|
|
||||||
memoryUsage: 43.2,
|
|
||||||
cpuUsage: 28.7,
|
|
||||||
systemHealth: 'good',
|
|
||||||
uptime: '15天 8小时 23分钟',
|
|
||||||
lastBackup: '2024-01-15 02:30:00',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成登录趋势数据(最近7天)
|
|
||||||
function generateLoginTrendData() {
|
|
||||||
const trendData = []
|
|
||||||
const today = new Date()
|
|
||||||
|
|
||||||
for (let i = 6; i >= 0; i--) {
|
|
||||||
const date = new Date(today)
|
|
||||||
date.setDate(date.getDate() - i)
|
|
||||||
|
|
||||||
const dateStr = date.toISOString().split('T')[0]
|
|
||||||
const label = date.toLocaleDateString('zh-CN', {
|
|
||||||
month: 'short',
|
|
||||||
day: 'numeric',
|
|
||||||
})
|
|
||||||
|
|
||||||
// 生成随机但合理的登录数量
|
|
||||||
const baseCount = 300
|
|
||||||
const randomVariation = Math.floor(Math.random() * 200) - 100
|
|
||||||
const weekendMultiplier
|
|
||||||
= date.getDay() === 0 || date.getDay() === 6 ? 0.6 : 1
|
|
||||||
const count = Math.max(
|
|
||||||
50,
|
|
||||||
Math.floor((baseCount + randomVariation) * weekendMultiplier),
|
|
||||||
)
|
|
||||||
|
|
||||||
trendData.push({
|
|
||||||
date: dateStr,
|
|
||||||
count,
|
|
||||||
label,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return trendData
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成随机颜色
|
|
||||||
export function generateRandomColor(): string {
|
|
||||||
const colors = [
|
|
||||||
'#18A058',
|
|
||||||
'#2080F0',
|
|
||||||
'#F0A020',
|
|
||||||
'#D03050',
|
|
||||||
'#722ED1',
|
|
||||||
'#13C2C2',
|
|
||||||
'#52C41A',
|
|
||||||
'#1890FF',
|
|
||||||
'#FAAD14',
|
|
||||||
'#F5222D',
|
|
||||||
]
|
|
||||||
return colors[Math.floor(Math.random() * colors.length)]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取状态颜色
|
|
||||||
export function getStatusColor(status: string): string {
|
|
||||||
const colorMap: Record<string, string> = {
|
|
||||||
success: 'var(--success-color)',
|
|
||||||
failed: 'var(--error-color)',
|
|
||||||
warning: 'var(--warning-color)',
|
|
||||||
info: 'var(--info-color)',
|
|
||||||
good: 'var(--success-color)',
|
|
||||||
critical: 'var(--error-color)',
|
|
||||||
}
|
|
||||||
return colorMap[status] || 'var(--text-color-3)'
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user