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:
shaw
2025-07-29 12:40:51 +08:00
parent c98de2aca5
commit 414856f152
70 changed files with 18748 additions and 10314 deletions

View 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
}
}

View 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
}
}