Files
kami/license-system-frontend/src/pages/admin/DashboardView.vue
2026-01-04 23:00:21 +08:00

95 lines
2.9 KiB
Vue

<template>
<div class="page-shell">
<div class="toolbar">
<div>
<h2 class="section-title">{{ '\u4eea\u8868\u76d8' }}</h2>
<div class="tag">{{ '\u5b9e\u65f6\u6982\u89c8' }}</div>
</div>
<el-button type="primary" plain @click="loadData">{{ '\u5237\u65b0' }}</el-button>
</div>
<div class="stat-grid">
<div class="stat-card" v-for="item in overviewCards" :key="item.label">
<div class="stat-label">{{ item.label }}</div>
<div class="stat-value">{{ item.value }}</div>
</div>
</div>
<div class="grid-two">
<div class="glass-card panel">
<div class="chart-header">
<h3 class="section-title">{{ '\u6d3b\u8dc3\u8d8b\u52bf' }}</h3>
<span class="tag">{{ '\u6700\u8fd130\u5929' }}</span>
</div>
<TrendChart :trend="trend" />
</div>
<div class="glass-card panel">
<div class="chart-header">
<h3 class="section-title">{{ '\u9879\u76ee\u5206\u5e03' }}</h3>
<span class="tag">{{ '\u6d3b\u8dc3\u5361\u5bc6' }}</span>
</div>
<el-table :data="projectDistribution" height="320">
<el-table-column prop="project" :label="'\u9879\u76ee'" min-width="120" />
<el-table-column prop="count" :label="'\u5361\u5bc6'" width="120" />
</el-table>
</div>
</div>
</div>
</template>
<script setup>
import { computed, onMounted, ref } from 'vue';
import { ElMessage } from 'element-plus';
import TrendChart from '@/components/TrendChart.vue';
import { statsDashboard } from '@/api/admin';
const data = ref({ overview: {}, trend: {}, projectDistribution: [] });
const overviewCards = computed(() => {
const overview = data.value.overview || {};
return [
{ label: '\u9879\u76ee\u603b\u6570', value: overview.totalProjects ?? 0 },
{ label: '\u5361\u5bc6\u603b\u6570', value: overview.totalCards ?? 0 },
{ label: '\u6d3b\u8dc3\u5361\u5bc6', value: overview.activeCards ?? 0 },
{ label: '\u5728\u7ebf\u8bbe\u5907', value: overview.activeDevices ?? 0 },
{ label: '\u4eca\u65e5\u6536\u5165', value: overview.todayRevenue ?? 0 },
{ label: '\u672c\u6708\u6536\u5165', value: overview.monthRevenue ?? 0 }
];
});
const trend = computed(() => data.value.trend || {});
const projectDistribution = computed(() => data.value.projectDistribution || []);
const loadData = async () => {
try {
data.value = await statsDashboard();
} catch (err) {
ElMessage.error(err?.message || '\u52a0\u8f7d\u4eea\u8868\u76d8\u5931\u8d25');
}
};
onMounted(loadData);
</script>
<style scoped>
.grid-two {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 16px;
margin-top: 20px;
}
.chart-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
@media (max-width: 1024px) {
.grid-two {
grid-template-columns: 1fr;
}
}
</style>