fix: 用量查看优化

This commit is contained in:
Gsh
2026-01-24 16:03:03 +08:00
parent 020ad797f2
commit 886cc3155f

View File

@@ -12,7 +12,7 @@ import {
} from 'echarts/components'; } from 'echarts/components';
import * as echarts from 'echarts/core'; import * as echarts from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers'; import { CanvasRenderer } from 'echarts/renderers';
import { getLast7DaysTokenUsage, getModelTokenUsage, getSelectableTokenInfo, getLast24HoursTokenUsage, getTodayModelUsage } from '@/api'; import { getLast7DaysTokenUsage, getLast24HoursTokenUsage, getModelTokenUsage, getSelectableTokenInfo, getTodayModelUsage } from '@/api';
// 注册必要的组件 // 注册必要的组件
echarts.use([ echarts.use([
@@ -93,11 +93,31 @@ const hourlyModels = computed(() => {
// 计算属性:模型颜色映射(保持一致性) // 计算属性:模型颜色映射(保持一致性)
const modelColors = computed(() => { const modelColors = computed(() => {
const baseColors = [ const baseColors = [
'#3a4de9', '#6a5acd', '#9370db', '#8a2be2', '#9932cc', '#3a4de9',
'#ba55d3', '#da70d6', '#ee82ee', '#dda0dd', '#ff00ff', '#6a5acd',
'#667eea', '#764ba2', '#f093fb', '#f5576c', '#4facfe', '#9370db',
'#00f2fe', '#43e97b', '#38f9d7', '#fa709a', '#fee140', '#8a2be2',
'#4361ee', '#3a0ca3', '#7209b7', '#f72585', '#4cc9f0', '#9932cc',
'#ba55d3',
'#da70d6',
'#ee82ee',
'#dda0dd',
'#ff00ff',
'#667eea',
'#764ba2',
'#f093fb',
'#f5576c',
'#4facfe',
'#00f2fe',
'#43e97b',
'#38f9d7',
'#fa709a',
'#fee140',
'#4361ee',
'#3a0ca3',
'#7209b7',
'#f72585',
'#4cc9f0',
]; ];
const colorMap: Record<string, string> = {}; const colorMap: Record<string, string> = {};
@@ -661,7 +681,7 @@ function updateHourlyBarChart() {
return; return;
} }
const hours = hourlyUsageData.value.map(item => { const hours = hourlyUsageData.value.map((item) => {
const date = new Date(item.hour); const date = new Date(item.hour);
return `${date.getHours().toString().padStart(2, '0')}:00`; return `${date.getHours().toString().padStart(2, '0')}:00`;
}); });
@@ -706,7 +726,7 @@ function updateHourlyBarChart() {
// 构建每个模型的数据系列(并排柱状图) // 构建每个模型的数据系列(并排柱状图)
const series = hourlyModels.value.map(({ modelId }, index) => { const series = hourlyModels.value.map(({ modelId }, index) => {
const data = hourlyUsageData.value.map(hour => { const data = hourlyUsageData.value.map((hour) => {
const modelData = hour.modelBreakdown?.find((m: any) => m.modelId === modelId); const modelData = hour.modelBreakdown?.find((m: any) => m.modelId === modelId);
return modelData?.tokens || 0; return modelData?.tokens || 0;
}); });
@@ -827,7 +847,7 @@ function updateHourlyBarChart() {
}, },
}, },
toolbox: { toolbox: {
show: !isMobile, show: true, // 强制显示工具箱
feature: { feature: {
dataZoom: { dataZoom: {
yAxisIndex: 'none', yAxisIndex: 'none',
@@ -855,10 +875,10 @@ function updateHourlyBarChart() {
}, },
right: 15, right: 15,
top: 5, top: 5,
itemSize: 14, itemSize: 18,
iconStyle: { iconStyle: {
borderColor: '#667eea', borderColor: '#667eea',
borderWidth: 1.5, borderWidth: 2,
}, },
emphasis: { emphasis: {
iconStyle: { iconStyle: {
@@ -876,26 +896,6 @@ function updateHourlyBarChart() {
}, },
}, },
}, },
// 区域选框缩放配置
brush: {
id: 'brush',
xAxisIndex: 0,
link: ['x'],
transform: {
type: 'bar',
},
throttleType: 'debounce',
throttleDelay: 300,
removeOnClick: true,
brushLink: 'all',
brushType: false,
inBrush: {
opacity: 1,
},
outOfBrush: {
opacity: 0.3,
},
},
legend: { legend: {
show: true, show: true,
type: hourlyModels.value.length > 8 || isMobile ? 'scroll' : 'plain', type: hourlyModels.value.length > 8 || isMobile ? 'scroll' : 'plain',
@@ -928,12 +928,12 @@ function updateHourlyBarChart() {
}, },
dataZoom: [ dataZoom: [
{ {
show: !isMobile, show: true, // 强制显示滑动条
start: hourlyUsageData.value.length > 12 ? 100 - Math.round((12 / hourlyUsageData.value.length) * 100) : 80, start: hourlyUsageData.value.length > 12 ? 100 - Math.round((12 / hourlyUsageData.value.length) * 100) : 80,
end: 100, end: 100,
xAxisIndex: [0], xAxisIndex: [0],
bottom: '3%', bottom: '3%',
height: 18, height: 20,
borderColor: 'transparent', borderColor: 'transparent',
fillerColor: 'rgba(102, 126, 234, 0.2)', fillerColor: 'rgba(102, 126, 234, 0.2)',
handleStyle: { handleStyle: {
@@ -954,7 +954,7 @@ function updateHourlyBarChart() {
moveOnMouseWheel: false, moveOnMouseWheel: false,
}, },
{ {
show: !isMobile && maxModelsPerHour > 3, show: true, // 强制显示Y轴缩放条
yAxisIndex: [0], yAxisIndex: [0],
filterMode: 'empty', filterMode: 'empty',
width: 28, width: 28,
@@ -977,7 +977,7 @@ function updateHourlyBarChart() {
throttleDelay: 300, throttleDelay: 300,
removeOnClick: true, removeOnClick: true,
brushLink: 'all', brushLink: 'all',
brushType: false, brushType: false, // 默认不启用刷子,通过工具箱激活
inBrush: { inBrush: {
opacity: 1, opacity: 1,
}, },
@@ -1174,9 +1174,15 @@ onBeforeUnmount(() => {
</template> </template>
<div class="today-model-cards"> <div class="today-model-cards">
<div v-if="todayModelUsageData.length === 0" class="empty-state"> <div v-if="todayModelUsageData.length === 0" class="empty-state">
<div class="empty-icon">📊</div> <div class="empty-icon">
<div class="empty-text">暂无数据</div> 📊
<div class="empty-hint">今日暂无模型使用记录</div> </div>
<div class="empty-text">
暂无数据
</div>
<div class="empty-hint">
今日暂无模型使用记录
</div>
</div> </div>
<div v-else class="model-cards-grid"> <div v-else class="model-cards-grid">
<div <div
@@ -1193,13 +1199,15 @@ onBeforeUnmount(() => {
:alt="item.modelId" :alt="item.modelId"
class="model-logo" class="model-logo"
@error="(e) => { (e.target as HTMLImageElement).style.display = 'none'; (e.target as HTMLImageElement).nextElementSibling?.classList.remove('fallback-icon'); }" @error="(e) => { (e.target as HTMLImageElement).style.display = 'none'; (e.target as HTMLImageElement).nextElementSibling?.classList.remove('fallback-icon'); }"
/> >
<div v-else class="model-logo-fallback" :style="{ background: modelColors[item.modelId] || '#667eea' }"> <div v-else class="model-logo-fallback" :style="{ background: modelColors[item.modelId] || '#667eea' }">
{{ item.modelId.charAt(0).toUpperCase() }} {{ item.modelId.charAt(0).toUpperCase() }}
</div> </div>
</div> </div>
<div class="model-info"> <div class="model-info">
<div class="model-name" :title="item.modelId">{{ item.modelId }}</div> <div class="model-name" :title="item.modelId">
{{ item.modelId }}
</div>
<div class="model-usage-count"> <div class="model-usage-count">
<el-icon><i-ep-data-analysis /></el-icon> <el-icon><i-ep-data-analysis /></el-icon>
使用 {{ item.usageCount }} 使用 {{ item.usageCount }}