- Replace fixed-width table columns with min-width + table-layout="auto" so tables stretch to fill available space instead of squeezing left - Condense 6 action buttons into "划拨" + "更多" dropdown menu - Add responsive grid columns for dashboard stats (xl:6 → xs:24) - Unify page headers with .page-header CSS class - Add global .el-table width:100% fix - Consistent number formatting with toLocaleString() - Clean up redundant style attributes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
87 lines
3.2 KiB
Vue
87 lines
3.2 KiB
Vue
<template>
|
|
<div>
|
|
<div class="page-header">
|
|
<h2>仪表盘</h2>
|
|
</div>
|
|
<el-row :gutter="16" style="margin-bottom: 24px;">
|
|
<el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24" style="margin-bottom:12px;">
|
|
<el-card shadow="hover">
|
|
<el-statistic title="子账号总数" :value="data.total_users" />
|
|
</el-card>
|
|
</el-col>
|
|
<el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24" style="margin-bottom:12px;">
|
|
<el-card shadow="hover">
|
|
<el-statistic title="正常运行" :value="data.active_users">
|
|
<template #suffix><span style="color:#67c23a;font-size:14px;"> 个</span></template>
|
|
</el-statistic>
|
|
</el-card>
|
|
</el-col>
|
|
<el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24" style="margin-bottom:12px;">
|
|
<el-card shadow="hover">
|
|
<el-statistic title="已停用" :value="data.disabled_users">
|
|
<template #suffix><span style="color:#f56c6c;font-size:14px;"> 个</span></template>
|
|
</el-statistic>
|
|
</el-card>
|
|
</el-col>
|
|
<el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24" style="margin-bottom:12px;">
|
|
<el-card shadow="hover">
|
|
<el-statistic title="累计总消费" :value="Number(data.total_spending)" :precision="2"
|
|
prefix="¥" />
|
|
</el-card>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<el-card>
|
|
<template #header>
|
|
<span>最近告警</span>
|
|
</template>
|
|
<el-table :data="data.recent_alerts" stripe table-layout="auto" empty-text="暂无告警">
|
|
<el-table-column prop="created_at" label="时间" min-width="160">
|
|
<template #default="{ row }">{{ formatTime(row.created_at) }}</template>
|
|
</el-table-column>
|
|
<el-table-column prop="alert_type" label="类型" min-width="80" align="center">
|
|
<template #default="{ row }">
|
|
<el-tag :type="typeTagMap[row.alert_type] || 'info'" size="small">
|
|
{{ typeLabelMap[row.alert_type] || row.alert_type }}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="iam_username" label="子账号" min-width="120" />
|
|
<el-table-column prop="title" label="标题" min-width="200" />
|
|
<el-table-column prop="spending_amount" label="消费" min-width="100" align="right">
|
|
<template #default="{ row }">
|
|
{{ row.spending_amount ? `¥${Number(row.spending_amount).toLocaleString()}` : '-' }}
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</el-card>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted } from 'vue'
|
|
import api from '../../api'
|
|
|
|
const data = ref({
|
|
total_users: 0, active_users: 0, disabled_users: 0,
|
|
monitored_users: 0, total_spending: '0', recent_alerts: [],
|
|
})
|
|
|
|
const typeLabelMap = { warning: '告警', disable: '停用', manual: '操作', error: '错误' }
|
|
const typeTagMap = { warning: 'warning', disable: 'danger', manual: '', error: 'danger' }
|
|
|
|
onMounted(async () => {
|
|
try {
|
|
const res = await api.get('/api/v1/dashboard/')
|
|
data.value = res.data
|
|
} catch (e) {
|
|
console.error('Failed to load dashboard:', e)
|
|
}
|
|
})
|
|
|
|
function formatTime(t) {
|
|
if (!t) return ''
|
|
return new Date(t).toLocaleString('zh-CN')
|
|
}
|
|
</script>
|