mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 21:17:30 +00:00
feat: 全新的Vue3管理后台(admin-spa)和路由重构
🎨 新增功能: - 使用Vue3 + Vite构建的全新管理后台界面 - 支持Tab切换的API统计页面(统计查询/使用教程) - 优雅的胶囊式Tab切换设计 - 同步了PR #106的会话窗口管理功能 - 完整的响应式设计和骨架屏加载状态 🔧 路由调整: - 新版管理后台部署在 /admin-next/ 路径 - 将根路径 / 重定向到 /admin-next/api-stats - 将 /web 页面路由重定向到新版,保留 /web/auth/* 认证路由 - 将 /apiStats 页面路由重定向到新版,保留API端点 🗑️ 清理工作: - 删除旧版 web/admin/ 静态文件 - 删除旧版 web/apiStats/ 静态文件 - 清理相关的文件服务代码 🐛 修复问题: - 修复重定向循环问题 - 修复环境变量配置 - 修复路由404错误 - 优化构建配置 🚀 生成方式:使用 Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
101
web/admin-spa/src/composables/useChartConfig.js
Normal file
101
web/admin-spa/src/composables/useChartConfig.js
Normal file
@@ -0,0 +1,101 @@
|
||||
import { Chart } from 'chart.js/auto'
|
||||
|
||||
export function useChartConfig() {
|
||||
// 设置Chart.js默认配置
|
||||
Chart.defaults.font.family = "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif"
|
||||
Chart.defaults.color = '#6b7280'
|
||||
Chart.defaults.plugins.tooltip.backgroundColor = 'rgba(0, 0, 0, 0.8)'
|
||||
Chart.defaults.plugins.tooltip.padding = 12
|
||||
Chart.defaults.plugins.tooltip.cornerRadius = 8
|
||||
Chart.defaults.plugins.tooltip.titleFont.size = 14
|
||||
Chart.defaults.plugins.tooltip.bodyFont.size = 12
|
||||
|
||||
// 创建渐变色
|
||||
const getGradient = (ctx, color, opacity = 0.2) => {
|
||||
const gradient = ctx.createLinearGradient(0, 0, 0, 300)
|
||||
gradient.addColorStop(0, `${color}${Math.round(opacity * 255).toString(16).padStart(2, '0')}`)
|
||||
gradient.addColorStop(1, `${color}00`)
|
||||
return gradient
|
||||
}
|
||||
|
||||
// 通用图表选项
|
||||
const commonOptions = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'top',
|
||||
labels: {
|
||||
usePointStyle: true,
|
||||
padding: 20,
|
||||
font: {
|
||||
size: 12,
|
||||
weight: '500'
|
||||
}
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
mode: 'index',
|
||||
intersect: false,
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
let label = context.dataset.label || ''
|
||||
if (label) {
|
||||
label += ': '
|
||||
}
|
||||
if (context.parsed.y !== null) {
|
||||
label += new Intl.NumberFormat('zh-CN').format(context.parsed.y)
|
||||
}
|
||||
return label
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
grid: {
|
||||
display: false
|
||||
},
|
||||
ticks: {
|
||||
font: {
|
||||
size: 11
|
||||
}
|
||||
}
|
||||
},
|
||||
y: {
|
||||
grid: {
|
||||
color: 'rgba(0, 0, 0, 0.05)',
|
||||
drawBorder: false
|
||||
},
|
||||
ticks: {
|
||||
font: {
|
||||
size: 11
|
||||
},
|
||||
callback: function(value) {
|
||||
if (value >= 1000000) {
|
||||
return (value / 1000000).toFixed(1) + 'M'
|
||||
} else if (value >= 1000) {
|
||||
return (value / 1000).toFixed(1) + 'K'
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 颜色方案
|
||||
const colorSchemes = {
|
||||
primary: ['#667eea', '#764ba2', '#f093fb', '#4facfe', '#00f2fe'],
|
||||
success: ['#10b981', '#059669', '#34d399', '#6ee7b7', '#a7f3d0'],
|
||||
warning: ['#f59e0b', '#d97706', '#fbbf24', '#fcd34d', '#fde68a'],
|
||||
danger: ['#ef4444', '#dc2626', '#f87171', '#fca5a5', '#fecaca']
|
||||
}
|
||||
|
||||
return {
|
||||
getGradient,
|
||||
commonOptions,
|
||||
colorSchemes
|
||||
}
|
||||
}
|
||||
49
web/admin-spa/src/composables/useConfirm.js
Normal file
49
web/admin-spa/src/composables/useConfirm.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
const showConfirmModal = ref(false)
|
||||
const confirmOptions = ref({
|
||||
title: '',
|
||||
message: '',
|
||||
confirmText: '继续',
|
||||
cancelText: '取消'
|
||||
})
|
||||
const confirmResolve = ref(null)
|
||||
|
||||
export function useConfirm() {
|
||||
const showConfirm = (title, message, confirmText = '继续', cancelText = '取消') => {
|
||||
return new Promise((resolve) => {
|
||||
confirmOptions.value = {
|
||||
title,
|
||||
message,
|
||||
confirmText,
|
||||
cancelText
|
||||
}
|
||||
confirmResolve.value = resolve
|
||||
showConfirmModal.value = true
|
||||
})
|
||||
}
|
||||
|
||||
const handleConfirm = () => {
|
||||
showConfirmModal.value = false
|
||||
if (confirmResolve.value) {
|
||||
confirmResolve.value(true)
|
||||
confirmResolve.value = null
|
||||
}
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
showConfirmModal.value = false
|
||||
if (confirmResolve.value) {
|
||||
confirmResolve.value(false)
|
||||
confirmResolve.value = null
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
showConfirmModal,
|
||||
confirmOptions,
|
||||
showConfirm,
|
||||
handleConfirm,
|
||||
handleCancel
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user