test: web

This commit is contained in:
tbphp
2025-07-01 22:47:25 +08:00
parent c447e3ad0b
commit dcb862b11a
50 changed files with 5059 additions and 689 deletions

View File

@@ -1,53 +1,163 @@
<template>
<div class="dashboard-page">
<h1>仪表盘</h1>
<div v-if="loading">加载中...</div>
<div v-if="stats" class="stats-grid">
<el-card>
<el-statistic title="总请求数" :value="stats.total_requests" />
</el-card>
<el-card>
<el-statistic title="成功请求数" :value="stats.success_requests" />
</el-card>
<el-card>
<el-statistic title="成功率" :value="stats.success_rate" :formatter="rateFormatter" />
</el-card>
<div class="dashboard-container">
<div class="dashboard-header">
<h1>仪表盘</h1>
<p>查看您账户的总体使用情况和统计数据</p>
</div>
<LoadingSpinner v-if="loading && !stats.total_keys" />
<div v-else class="dashboard-content">
<!-- 统计卡片 -->
<StatsCards />
<!-- 快捷操作和筛选 -->
<div class="dashboard-grid">
<div class="quick-actions-section">
<QuickActions />
</div>
<div class="filters-section">
<el-card shadow="never">
<template #header>
<h3>筛选图表</h3>
</template>
<div class="filter-controls">
<!-- 时间范围筛选 -->
<el-select
v-model="filters.timeRange"
@change="onFilterChange"
placeholder="选择时间范围"
style="width: 200px"
>
<el-option label="过去 24 小时" value="24h" />
<el-option label="过去 7 天" value="7d" />
<el-option label="过去 30 天" value="30d" />
</el-select>
<!-- 分组筛选 -->
<el-select
v-model="filters.groupId"
@change="onFilterChange"
placeholder="选择分组"
style="width: 200px"
clearable
>
<el-option
v-for="group in groupStore.groups"
:key="group.id"
:label="group.name"
:value="group.id"
/>
</el-select>
</div>
</el-card>
</div>
</div>
<!-- 请求统计图表 -->
<RequestChart />
</div>
<el-card v-if="stats && stats.group_stats.length > 0" class="chart-card">
<StatsChart :data="stats.group_stats" />
</el-card>
</div>
</template>
<script setup lang="ts">
import { onMounted } from 'vue';
import { storeToRefs } from 'pinia';
import { useDashboardStore } from '@/stores/dashboardStore';
import StatsChart from '@/components/StatsChart.vue';
import { onMounted, onUnmounted } from "vue";
import { storeToRefs } from "pinia";
import { useDashboardStore } from "@/stores/dashboardStore";
import { useGroupStore } from "@/stores/groupStore";
import StatsCards from "@/components/business/dashboard/StatsCards.vue";
import RequestChart from "@/components/business/dashboard/RequestChart.vue";
import QuickActions from "@/components/business/dashboard/QuickActions.vue";
import LoadingSpinner from "@/components/common/LoadingSpinner.vue";
const dashboardStore = useDashboardStore();
const { stats, loading } = storeToRefs(dashboardStore);
const groupStore = useGroupStore();
const { stats, loading, filters } = storeToRefs(dashboardStore);
const onFilterChange = () => {
dashboardStore.fetchDashboardData();
};
onMounted(() => {
dashboardStore.fetchStats();
dashboardStore.startPolling();
groupStore.fetchGroups(); // 获取分组列表用于筛选
});
const rateFormatter = (rate: number) => {
return `${(rate * 100).toFixed(2)}%`;
};
onUnmounted(() => {
dashboardStore.stopPolling();
});
</script>
<style scoped>
.dashboard-page {
padding: 20px;
.dashboard-container {
padding: 24px;
max-width: 1200px;
margin: 0 auto;
}
.stats-grid {
.dashboard-header {
margin-bottom: 24px;
}
.dashboard-header h1 {
font-size: 28px;
font-weight: 600;
color: #1f2937;
margin-bottom: 8px;
}
.dashboard-header p {
color: #6b7280;
font-size: 14px;
}
.dashboard-content {
display: flex;
flex-direction: column;
gap: 24px;
}
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 20px;
grid-template-columns: 1fr 2fr;
gap: 24px;
align-items: start;
}
.chart-card {
margin-top: 20px;
.quick-actions-section {
min-height: 200px;
}
</style>
.filters-section h3 {
font-size: 18px;
font-weight: 500;
color: #1f2937;
margin: 0;
}
.filter-controls {
display: flex;
gap: 16px;
flex-wrap: wrap;
}
@media (max-width: 1024px) {
.dashboard-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 768px) {
.dashboard-container {
padding: 16px;
}
.filter-controls {
flex-direction: column;
}
.filter-controls .el-select {
width: 100% !important;
}
}
</style>