Files
claude-relay-service/web/admin-spa/src/components/common/LogoTitle.vue
shaw 414856f152 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>
2025-07-29 12:40:51 +08:00

81 lines
1.9 KiB
Vue

<template>
<div class="flex items-center gap-4">
<!-- Logo区域 -->
<div class="w-12 h-12 bg-gradient-to-br from-blue-500/20 to-purple-500/20 border border-gray-300/30 rounded-xl flex items-center justify-center backdrop-blur-sm flex-shrink-0 overflow-hidden">
<template v-if="!loading">
<img v-if="logoSrc"
:src="logoSrc"
alt="Logo"
class="w-8 h-8 object-contain"
@error="handleLogoError">
<i v-else class="fas fa-cloud text-xl text-gray-700"></i>
</template>
<div v-else class="w-8 h-8 bg-gray-300/50 rounded animate-pulse"></div>
</div>
<!-- 标题区域 -->
<div class="flex flex-col justify-center min-h-[48px]">
<div class="flex items-center gap-3">
<template v-if="!loading && title">
<h1 :class="['text-2xl font-bold header-title leading-tight', titleClass]">{{ title }}</h1>
</template>
<div v-else-if="loading" class="h-8 w-64 bg-gray-300/50 rounded animate-pulse"></div>
</div>
<p v-if="subtitle" class="text-gray-600 text-sm leading-tight mt-0.5">{{ subtitle }}</p>
</div>
</div>
</template>
<script setup>
defineProps({
loading: {
type: Boolean,
default: false
},
title: {
type: String,
default: ''
},
subtitle: {
type: String,
default: ''
},
logoSrc: {
type: String,
default: ''
},
titleClass: {
type: String,
default: 'text-gray-900'
}
})
// 处理图片加载错误
const handleLogoError = (e) => {
e.target.style.display = 'none'
}
</script>
<style scoped>
/* 骨架屏动画 */
@keyframes pulse {
0% {
opacity: 0.7;
}
50% {
opacity: 0.4;
}
100% {
opacity: 0.7;
}
}
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
/* 标题样式 */
.header-title {
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
</style>