mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 20:56:48 +00:00
refactor: standardize code formatting and linting configuration
- Replace .eslintrc.js with .eslintrc.cjs for better ES module compatibility - Add .prettierrc configuration for consistent code formatting - Update package.json with new lint and format scripts - Add nodemon.json for development hot reloading configuration - Standardize code formatting across all JavaScript and Vue files - Update web admin SPA with improved linting rules and formatting - Add prettier configuration to web admin SPA 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,66 +1,45 @@
|
||||
<template>
|
||||
<div class="glass-strong rounded-3xl p-6">
|
||||
<div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-6 gap-4">
|
||||
<h2 class="text-xl font-bold text-gray-800 flex items-center">
|
||||
<div class="mb-6 flex flex-col items-start justify-between gap-4 md:flex-row md:items-center">
|
||||
<h2 class="flex items-center text-xl font-bold text-gray-800">
|
||||
<i class="fas fa-robot mr-2 text-purple-500" />
|
||||
模型使用分布
|
||||
</h2>
|
||||
|
||||
<el-radio-group
|
||||
v-model="modelPeriod"
|
||||
size="small"
|
||||
@change="handlePeriodChange"
|
||||
>
|
||||
<el-radio-button label="daily">
|
||||
今日
|
||||
</el-radio-button>
|
||||
<el-radio-button label="total">
|
||||
累计
|
||||
</el-radio-button>
|
||||
|
||||
<el-radio-group v-model="modelPeriod" size="small" @change="handlePeriodChange">
|
||||
<el-radio-button label="daily"> 今日 </el-radio-button>
|
||||
<el-radio-button label="total"> 累计 </el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
|
||||
|
||||
<div
|
||||
v-if="dashboardStore.dashboardModelStats.length === 0"
|
||||
class="text-center py-12 text-gray-500"
|
||||
class="py-12 text-center text-gray-500"
|
||||
>
|
||||
<i class="fas fa-chart-pie text-4xl mb-3 opacity-30" />
|
||||
<i class="fas fa-chart-pie mb-3 text-4xl opacity-30" />
|
||||
<p>暂无模型使用数据</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="grid grid-cols-1 lg:grid-cols-2 gap-6"
|
||||
>
|
||||
|
||||
<div v-else class="grid grid-cols-1 gap-6 lg:grid-cols-2">
|
||||
<!-- 饼图 -->
|
||||
<div
|
||||
class="relative"
|
||||
style="height: 300px;"
|
||||
>
|
||||
<div class="relative" style="height: 300px">
|
||||
<canvas ref="chartCanvas" />
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 数据列表 -->
|
||||
<div class="space-y-3">
|
||||
<div
|
||||
v-for="(stat, index) in sortedStats"
|
||||
:key="stat.model"
|
||||
class="flex items-center justify-between p-3 bg-gray-50 rounded-lg"
|
||||
:key="stat.model"
|
||||
class="flex items-center justify-between rounded-lg bg-gray-50 p-3"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<div
|
||||
class="w-4 h-4 rounded"
|
||||
:style="`background-color: ${getColor(index)}`"
|
||||
/>
|
||||
<div class="h-4 w-4 rounded" :style="`background-color: ${getColor(index)}`" />
|
||||
<span class="font-medium text-gray-700">{{ stat.model }}</span>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<p class="font-semibold text-gray-800">
|
||||
{{ formatNumber(stat.requests) }} 请求
|
||||
</p>
|
||||
<p class="text-sm text-gray-500">
|
||||
{{ formatNumber(stat.totalTokens) }} tokens
|
||||
</p>
|
||||
<p class="font-semibold text-gray-800">{{ formatNumber(stat.requests) }} 请求</p>
|
||||
<p class="text-sm text-gray-500">{{ formatNumber(stat.totalTokens) }} tokens</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -93,23 +72,25 @@ const getColor = (index) => {
|
||||
|
||||
const createChart = () => {
|
||||
if (!chartCanvas.value || !dashboardStore.dashboardModelStats.length) return
|
||||
|
||||
|
||||
if (chart) {
|
||||
chart.destroy()
|
||||
}
|
||||
|
||||
|
||||
const { colorSchemes } = useChartConfig()
|
||||
const colors = colorSchemes.primary
|
||||
|
||||
|
||||
chart = new Chart(chartCanvas.value, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: sortedStats.value.map(stat => stat.model),
|
||||
datasets: [{
|
||||
data: sortedStats.value.map(stat => stat.requests),
|
||||
backgroundColor: sortedStats.value.map((_, index) => colors[index % colors.length]),
|
||||
borderWidth: 0
|
||||
}]
|
||||
labels: sortedStats.value.map((stat) => stat.model),
|
||||
datasets: [
|
||||
{
|
||||
data: sortedStats.value.map((stat) => stat.requests),
|
||||
backgroundColor: sortedStats.value.map((_, index) => colors[index % colors.length]),
|
||||
borderWidth: 0
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
@@ -120,9 +101,13 @@ const createChart = () => {
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
label: function (context) {
|
||||
const stat = sortedStats.value[context.dataIndex]
|
||||
const percentage = ((stat.requests / dashboardStore.dashboardModelStats.reduce((sum, s) => sum + s.requests, 0)) * 100).toFixed(1)
|
||||
const percentage = (
|
||||
(stat.requests /
|
||||
dashboardStore.dashboardModelStats.reduce((sum, s) => sum + s.requests, 0)) *
|
||||
100
|
||||
).toFixed(1)
|
||||
return [
|
||||
`${stat.model}: ${percentage}%`,
|
||||
`请求: ${formatNumber(stat.requests)}`,
|
||||
@@ -141,9 +126,13 @@ const handlePeriodChange = async () => {
|
||||
createChart()
|
||||
}
|
||||
|
||||
watch(() => dashboardStore.dashboardModelStats, () => {
|
||||
createChart()
|
||||
}, { deep: true })
|
||||
watch(
|
||||
() => dashboardStore.dashboardModelStats,
|
||||
() => {
|
||||
createChart()
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
createChart()
|
||||
@@ -158,4 +147,4 @@ onUnmounted(() => {
|
||||
|
||||
<style scoped>
|
||||
/* 组件特定样式 */
|
||||
</style>
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user