mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 01:40:21 +08:00
feat: 支持系统设置中自定义全站名称和副标题
新增 site_name 和 site_subtitle 两个系统配置项,允许管理员在后台自定义 站点品牌名称(默认 Aether)和副标题(默认 AI Gateway)。 - 后端:DEFAULT_CONFIGS 新增配置项,公开 /api/public/site-info 端点 - 后端:邮件发送 app_name 回退链增加 site_name - 前端:新增 useSiteInfo composable 全局缓存站点信息 - 前端:首页、后台布局、登录页、指南页面全部改为动态读取 - 前端:系统设置页新增「站点信息」配置区块 - 前端:配置导出文件名跟随站点名称 - 优化:请求失败允许重试,保存后即时生效无需刷新页面 - 优化:document.title 随站点名称动态更新 Closes #176 Co-authored-by: LewisPen <LewisPen@nyadoo.com>
This commit is contained in:
@@ -34,9 +34,9 @@
|
||||
/>
|
||||
<div class="flex flex-col justify-center">
|
||||
<h1 class="text-base sm:text-lg font-bold text-[#191919] dark:text-white leading-none">
|
||||
Aether
|
||||
{{ siteName }}
|
||||
</h1>
|
||||
<span class="text-[9px] sm:text-[10px] text-[#91918d] dark:text-muted-foreground leading-none mt-1 sm:mt-1.5 font-medium tracking-wide">AI Gateway</span>
|
||||
<span class="text-[9px] sm:text-[10px] text-[#91918d] dark:text-muted-foreground leading-none mt-1 sm:mt-1.5 font-medium tracking-wide">{{ siteSubtitle }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
/>
|
||||
<div class="flex flex-col justify-center">
|
||||
<h1 class="text-lg font-bold text-[#191919] dark:text-white leading-none">
|
||||
Aether
|
||||
{{ siteName }}
|
||||
</h1>
|
||||
<span class="text-[10px] text-[#91918d] dark:text-muted-foreground leading-none mt-1.5 font-medium tracking-wide">AI Gateway</span>
|
||||
<span class="text-[10px] text-[#91918d] dark:text-muted-foreground leading-none mt-1.5 font-medium tracking-wide">{{ siteSubtitle }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -458,6 +458,7 @@ import GithubIcon from '@/components/icons/GithubIcon.vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useDarkMode } from '@/composables/useDarkMode'
|
||||
import { useClipboard } from '@/composables/useClipboard'
|
||||
import { useSiteInfo } from '@/composables/useSiteInfo'
|
||||
import LoginDialog from '@/features/auth/components/LoginDialog.vue'
|
||||
import RippleLogo from '@/components/RippleLogo.vue'
|
||||
import HeaderLogo from '@/components/HeaderLogo.vue'
|
||||
@@ -483,6 +484,7 @@ import {
|
||||
const authStore = useAuthStore()
|
||||
const { isDark, themeMode, toggleDarkMode } = useDarkMode()
|
||||
const { copyToClipboard } = useClipboard()
|
||||
const { siteName, siteSubtitle } = useSiteInfo()
|
||||
|
||||
const dashboardPath = computed(() =>
|
||||
authStore.user?.role === 'admin' ? '/admin/dashboard' : '/dashboard'
|
||||
@@ -566,10 +568,10 @@ const { claudeConfig, codexConfig, codexAuthConfig, geminiEnvConfig, geminiSetti
|
||||
// Dialog state
|
||||
const showLoginDialog = ref(false)
|
||||
|
||||
// Typewriter effect for "Aether"
|
||||
// Typewriter effect for site name
|
||||
const aetherText = ref('')
|
||||
const showCursor = ref(true)
|
||||
const typewriterFullText = 'Aether'
|
||||
const typewriterFullText = computed(() => siteName.value)
|
||||
let typewriterTimer: ReturnType<typeof setTimeout> | null = null
|
||||
const hasTypewriterStarted = ref(false)
|
||||
|
||||
@@ -578,19 +580,20 @@ const startTypewriter = () => {
|
||||
hasTypewriterStarted.value = true
|
||||
aetherText.value = ''
|
||||
showCursor.value = true
|
||||
|
||||
|
||||
const typeSpeed = 200
|
||||
const deleteSpeed = 120
|
||||
const pauseAfterType = 3500
|
||||
const pauseAfterDelete = 1000
|
||||
|
||||
|
||||
const typeLoop = () => {
|
||||
let index = 0
|
||||
|
||||
const fullText = typewriterFullText.value
|
||||
|
||||
// Type phase
|
||||
const typeNextChar = () => {
|
||||
if (index < typewriterFullText.length) {
|
||||
aetherText.value = typewriterFullText.slice(0, index + 1)
|
||||
if (index < fullText.length) {
|
||||
aetherText.value = fullText.slice(0, index + 1)
|
||||
index++
|
||||
typewriterTimer = setTimeout(typeNextChar, typeSpeed)
|
||||
} else {
|
||||
@@ -598,7 +601,7 @@ const startTypewriter = () => {
|
||||
typewriterTimer = setTimeout(deleteChars, pauseAfterType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Delete phase
|
||||
const deleteChars = () => {
|
||||
if (aetherText.value.length > 0) {
|
||||
@@ -609,7 +612,7 @@ const startTypewriter = () => {
|
||||
typewriterTimer = setTimeout(typeLoop, pauseAfterDelete)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typeNextChar()
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { ArrowRight, Shuffle, FileCode, Globe, Shield, Check, Info, AlertTriangle, Settings } from 'lucide-vue-next'
|
||||
import { panelClasses } from './guide-config'
|
||||
import { useSiteInfo } from '@/composables/useSiteInfo'
|
||||
|
||||
const { siteName } = useSiteInfo()
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
@@ -162,7 +165,7 @@ const systemSettings = [
|
||||
高级功能
|
||||
</h1>
|
||||
<p class="text-lg text-[#666663] dark:text-[#a3a094]">
|
||||
Aether 提供了一些高级功能,帮助你实现更灵活的 API 管理。
|
||||
{{ siteName }} 提供了一些高级功能,帮助你实现更灵活的 API 管理。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { Search, ChevronDown, ExternalLink, HelpCircle } from 'lucide-vue-next'
|
||||
import { faqItems, panelClasses } from './guide-config'
|
||||
import { useSiteInfo } from '@/composables/useSiteInfo'
|
||||
|
||||
const { siteName } = useSiteInfo()
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
@@ -70,7 +73,7 @@ function toggleAll() {
|
||||
常见问题
|
||||
</h1>
|
||||
<p class="text-lg text-[#666663] dark:text-[#a3a094]">
|
||||
关于 Aether 使用和配置的常见问题解答。
|
||||
关于 {{ siteName }} 使用和配置的常见问题解答。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
/>
|
||||
<div class="flex flex-col justify-center">
|
||||
<h1 class="text-base sm:text-lg font-bold text-[#191919] dark:text-white leading-none">
|
||||
Aether
|
||||
{{ siteName }}
|
||||
</h1>
|
||||
<span class="text-[9px] sm:text-[10px] text-[#91918d] dark:text-muted-foreground leading-none mt-1 sm:mt-1.5 font-medium tracking-wide">AI Gateway</span>
|
||||
<span class="text-[9px] sm:text-[10px] text-[#91918d] dark:text-muted-foreground leading-none mt-1 sm:mt-1.5 font-medium tracking-wide">{{ siteSubtitle }}</span>
|
||||
</div>
|
||||
</RouterLink>
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
<!-- Base URL Input -->
|
||||
<div class="p-4 border-t border-[#e5e4df] dark:border-[rgba(227,224,211,0.12)]">
|
||||
<label class="block text-xs font-medium text-[#666663] dark:text-muted-foreground mb-2">
|
||||
Aether Base URL
|
||||
{{ siteName }} Base URL
|
||||
</label>
|
||||
<input
|
||||
v-model="baseUrl"
|
||||
@@ -200,10 +200,12 @@ import {
|
||||
import GithubIcon from '@/components/icons/GithubIcon.vue'
|
||||
import HeaderLogo from '@/components/HeaderLogo.vue'
|
||||
import { useDarkMode } from '@/composables/useDarkMode'
|
||||
import { useSiteInfo } from '@/composables/useSiteInfo'
|
||||
import { guideNavItems } from './guide-config'
|
||||
|
||||
const route = useRoute()
|
||||
const { themeMode, toggleDarkMode } = useDarkMode()
|
||||
const { siteName, siteSubtitle } = useSiteInfo()
|
||||
|
||||
const showMobileNav = ref(false)
|
||||
const baseUrl = ref(typeof window !== 'undefined' ? window.location.origin : 'https://your-aether.com')
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { ArrowRight, Server, Layers, Key, Box, ChevronRight } from 'lucide-vue-next'
|
||||
import { coreConcepts, apiFormats, configSteps, panelClasses } from './guide-config'
|
||||
import { useSiteInfo } from '@/composables/useSiteInfo'
|
||||
|
||||
const { siteName } = useSiteInfo()
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
@@ -41,10 +44,10 @@ const conceptIconColors = {
|
||||
<!-- 标题区域 -->
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-3xl font-bold text-[#262624] dark:text-[#f1ead8]">
|
||||
欢迎使用 Aether
|
||||
欢迎使用 {{ siteName }}
|
||||
</h1>
|
||||
<p class="text-lg text-[#666663] dark:text-[#a3a094]">
|
||||
Aether 是一个 AI API 网关,帮助你统一管理多个 AI 服务供应商,实现负载均衡、访问控制和用量统计。
|
||||
{{ siteName }} 是一个 AI API 网关,帮助你统一管理多个 AI 服务供应商,实现负载均衡、访问控制和用量统计。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -54,7 +57,7 @@ const conceptIconColors = {
|
||||
核心概念
|
||||
</h2>
|
||||
<p class="text-[#666663] dark:text-[#a3a094]">
|
||||
理解这四个核心概念,是配置 Aether 的基础:
|
||||
理解这四个核心概念,是配置 {{ siteName }} 的基础:
|
||||
</p>
|
||||
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
@@ -161,7 +164,7 @@ const conceptIconColors = {
|
||||
支持的 API 格式
|
||||
</h2>
|
||||
<p class="text-[#666663] dark:text-[#a3a094]">
|
||||
Aether 支持多种 API 格式,可以作为不同客户端的统一入口:
|
||||
{{ siteName }} 支持多种 API 格式,可以作为不同客户端的统一入口:
|
||||
</p>
|
||||
|
||||
<div
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { ArrowRight, Server, Settings, Check, AlertTriangle, Info } from 'lucide-vue-next'
|
||||
import { apiFormats, panelClasses } from './guide-config'
|
||||
import { useSiteInfo } from '@/composables/useSiteInfo'
|
||||
|
||||
const { siteName } = useSiteInfo()
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
@@ -73,7 +76,7 @@ const providerExamples = [
|
||||
供应商管理
|
||||
</h1>
|
||||
<p class="text-lg text-[#666663] dark:text-[#a3a094]">
|
||||
供应商和端点是 Aether 的基础配置,决定了系统可以调用哪些 AI 服务。
|
||||
供应商和端点是 {{ siteName }} 的基础配置,决定了系统可以调用哪些 AI 服务。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { ArrowRight, Users, Key, Shield, Check, Info, AlertTriangle, Clock } from 'lucide-vue-next'
|
||||
import { panelClasses } from './guide-config'
|
||||
import { useSiteInfo } from '@/composables/useSiteInfo'
|
||||
|
||||
const { siteName } = useSiteInfo()
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
@@ -46,7 +49,7 @@ const roleComparison = [
|
||||
用户与密钥
|
||||
</h1>
|
||||
<p class="text-lg text-[#666663] dark:text-[#a3a094]">
|
||||
用户和 API Key 是 Aether 的访问控制核心。通过用户管理分配角色权限,通过 Key 管理控制 API 访问。
|
||||
用户和 API Key 是 {{ siteName }} 的访问控制核心。通过用户管理分配角色权限,通过 Key 管理控制 API 访问。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -192,7 +195,7 @@ const roleComparison = [
|
||||
<ul class="space-y-3 text-sm text-[#666663] dark:text-[#a3a094]">
|
||||
<li class="flex items-start gap-2">
|
||||
<Check class="h-4 w-4 text-green-500 mt-0.5 flex-shrink-0" />
|
||||
<span>API Key 是用户调用 Aether API 的凭证</span>
|
||||
<span>API Key 是用户调用 {{ siteName }} API 的凭证</span>
|
||||
</li>
|
||||
<li class="flex items-start gap-2">
|
||||
<Check class="h-4 w-4 text-green-500 mt-0.5 flex-shrink-0" />
|
||||
|
||||
Reference in New Issue
Block a user