92 lines
2.1 KiB
Vue
92 lines
2.1 KiB
Vue
<script setup lang="ts">
|
|
import { onMounted, ref } from 'vue'
|
|
|
|
import AdminPageHeader from '@/components/admin/AdminPageHeader.vue'
|
|
import { fetchAdminDashboardSummary } from '@/services/admin'
|
|
import type { AdminDashboardSummary } from '@/types/admin'
|
|
|
|
const loading = ref(true)
|
|
const summary = ref<AdminDashboardSummary | null>(null)
|
|
const errorMessage = ref('')
|
|
|
|
onMounted(async () => {
|
|
try {
|
|
const response = await fetchAdminDashboardSummary()
|
|
summary.value = response.data
|
|
} catch (error) {
|
|
errorMessage.value = error instanceof Error ? error.message : '读取概览失败'
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
})
|
|
|
|
const cards = [
|
|
{ key: 'todayOrders', label: '今日订单' },
|
|
{ key: 'paidPendingClaim', label: '待领取' },
|
|
{ key: 'claimingTasks', label: '领取中' },
|
|
{ key: 'redeemedToday', label: '今日成功' },
|
|
{ key: 'abnormalTasks', label: '异常任务' },
|
|
] as const
|
|
</script>
|
|
|
|
<template>
|
|
<div class="dashboard-page">
|
|
<AdminPageHeader title="系统概览" description="快速查看订单和交付链路的运行状态。" />
|
|
|
|
<el-alert
|
|
v-if="errorMessage"
|
|
:title="errorMessage"
|
|
type="error"
|
|
show-icon
|
|
:closable="false"
|
|
class="mt-4"
|
|
/>
|
|
|
|
<el-skeleton v-if="loading" :rows="12" animated class="mt-4" />
|
|
|
|
<div v-else class="summary-grid">
|
|
<el-card v-for="card in cards" :key="card.key" shadow="never" class="stat-card">
|
|
<span class="stat-label">{{ card.label }}</span>
|
|
<strong class="stat-value">{{ summary?.[card.key] ?? 0 }}</strong>
|
|
</el-card>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.dashboard-page {
|
|
display: grid;
|
|
gap: 0;
|
|
}
|
|
|
|
.summary-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
gap: var(--space-4);
|
|
margin-top: var(--space-4);
|
|
}
|
|
|
|
.stat-card {
|
|
text-align: left;
|
|
}
|
|
|
|
.stat-label {
|
|
display: block;
|
|
color: var(--text-secondary);
|
|
font-size: var(--text-sm);
|
|
}
|
|
|
|
.stat-value {
|
|
display: block;
|
|
margin-top: 10px;
|
|
font-size: var(--text-3xl);
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
@media (max-width: 900px) {
|
|
.summary-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
</style>
|