refactor(frontend): 优化布局和视图页面

- 更新 MainLayout 布局组件
- 优化 admin 视图: 用户、模型、Provider、API Keys 等管理页面
- 改进 shared 视图: Dashboard、Usage 页面
- 调整 user 视图: ModelCatalog、MyApiKeys、Settings、Announcements 页面
- 更新 public 视图: Home、CliSection、LogoColorDemo 页面
This commit is contained in:
fawney19
2025-12-12 16:15:54 +08:00
parent 06c0a47b21
commit 39ea9e8e86
20 changed files with 3062 additions and 1154 deletions

View File

@@ -12,7 +12,10 @@
:class="badgeClass"
:style="badgeStyle"
>
<component :is="badgeIcon" class="h-3 w-3" />
<component
:is="badgeIcon"
class="h-3 w-3"
/>
{{ badgeText }}
</div>
@@ -37,20 +40,27 @@
class="mb-4 transition-all duration-700 relative z-10"
:style="cardStyleFn(0)"
>
<div :class="[panelClasses.commandPanel, 'flex flex-wrap items-center gap-3 px-4 py-3']">
<div
class="flex flex-wrap items-center gap-3 px-4 py-3"
:class="[panelClasses.commandPanel]"
>
<PlatformSelect
:model-value="platformValue"
@update:model-value="$emit('update:platformValue', $event)"
:options="platformOptions"
class="shrink-0"
@update:model-value="$emit('update:platformValue', $event)"
/>
<div class="flex-1 min-w-[180px]">
<CodeHighlight :code="installCommand" language="bash" dense />
<CodeHighlight
:code="installCommand"
language="bash"
dense
/>
</div>
<button
@click="$emit('copy', installCommand)"
:class="panelClasses.iconButtonSmall"
title="复制配置"
@click="$emit('copy', installCommand)"
>
<Copy class="h-3.5 w-3.5" />
</button>
@@ -65,16 +75,19 @@
:class="idx < configFiles.length - 1 ? 'mb-3' : ''"
:style="cardStyleFn(idx + 1)"
>
<div :class="[panelClasses.configPanel, 'overflow-hidden']">
<div
class="overflow-hidden"
:class="[panelClasses.configPanel]"
>
<div :class="panelClasses.panelHeader">
<div class="flex items-center justify-between">
<span class="text-xs font-medium text-[#666663] dark:text-muted-foreground">
{{ config.path }}
</span>
<button
@click="$emit('copy', config.content)"
:class="panelClasses.iconButtonSmall"
title="复制配置"
@click="$emit('copy', config.content)"
>
<Copy class="h-3.5 w-3.5" />
</button>
@@ -82,7 +95,10 @@
</div>
<div :class="panelClasses.codeBody">
<div class="config-code-wrapper">
<CodeHighlight :code="config.content" :language="config.language" />
<CodeHighlight
:code="config.content"
:language="config.language"
/>
</div>
</div>
</div>
@@ -90,7 +106,10 @@
</div>
<!-- Logo placeholder column -->
<div :class="logoOrder" class="flex items-center justify-center h-full min-h-[300px] relative">
<div
:class="logoOrder"
class="flex items-center justify-center h-full min-h-[300px] relative"
>
<slot name="logo" />
</div>
</div>
@@ -104,6 +123,13 @@ import PlatformSelect from '@/components/PlatformSelect.vue'
import CodeHighlight from '@/components/CodeHighlight.vue'
import { panelClasses, type PlatformOption } from './home-config'
const props = withDefaults(defineProps<Props>(), {
contentPosition: 'left'
})
defineEmits<{
copy: [text: string]
'update:platformValue': [value: string]
}>()
// Expose section element for parent scroll tracking
const sectionRef = ref<HTMLElement | null>(null)
defineExpose({ sectionEl: sectionRef })
@@ -133,15 +159,6 @@ interface Props {
contentPosition?: 'left' | 'right'
}
const props = withDefaults(defineProps<Props>(), {
contentPosition: 'left'
})
defineEmits<{
copy: [text: string]
'update:platformValue': [value: string]
}>()
const contentOrder = computed(() =>
props.contentPosition === 'right' ? 'md:order-2' : ''
)

View File

@@ -8,8 +8,8 @@
<button
v-for="(section, index) in sections"
:key="index"
@click="scrollToSection(index)"
class="scroll-indicator-btn group"
@click="scrollToSection(index)"
>
<span class="scroll-indicator-label">{{ section.name }}</span>
<div
@@ -28,9 +28,14 @@
class="flex items-center gap-3 group/logo cursor-pointer"
@click="scrollToSection(0)"
>
<HeaderLogo size="h-9 w-9" className="text-[#191919] dark:text-white" />
<HeaderLogo
size="h-9 w-9"
class-name="text-[#191919] dark:text-white"
/>
<div class="flex flex-col justify-center">
<h1 class="text-lg font-bold text-[#191919] dark:text-white leading-none">Aether</h1>
<h1 class="text-lg font-bold text-[#191919] dark:text-white leading-none">
Aether
</h1>
<span class="text-[10px] text-[#91918d] dark:text-muted-foreground leading-none mt-1.5 font-medium tracking-wide">API Gateway</span>
</div>
</div>
@@ -40,11 +45,11 @@
<button
v-for="(section, index) in sections"
:key="index"
@click="scrollToSection(index)"
class="group relative px-3 py-2 text-sm font-medium transition"
:class="currentSection === index
? 'text-[#cc785c] dark:text-[#d4a27f]'
: 'text-[#666663] dark:text-muted-foreground hover:text-[#191919] dark:hover:text-white'"
@click="scrollToSection(index)"
>
{{ section.name }}
<div
@@ -57,13 +62,22 @@
<!-- Right Actions -->
<div class="flex items-center gap-3">
<button
@click="toggleDarkMode"
class="flex h-9 w-9 items-center justify-center rounded-lg text-muted-foreground hover:text-foreground hover:bg-muted/50 transition"
:title="themeMode === 'system' ? '跟随系统' : themeMode === 'dark' ? '深色模式' : '浅色模式'"
@click="toggleDarkMode"
>
<SunMoon v-if="themeMode === 'system'" class="h-4 w-4" />
<Sun v-else-if="themeMode === 'light'" class="h-4 w-4" />
<Moon v-else class="h-4 w-4" />
<SunMoon
v-if="themeMode === 'system'"
class="h-4 w-4"
/>
<Sun
v-else-if="themeMode === 'light'"
class="h-4 w-4"
/>
<Moon
v-else
class="h-4 w-4"
/>
</button>
<RouterLink
@@ -75,8 +89,8 @@
</RouterLink>
<button
v-else
@click="showLoginDialog = true"
class="rounded-xl bg-[#cc785c] px-4 py-2 text-sm font-medium text-white shadow-lg shadow-[#cc785c]/30 transition hover:bg-[#d4a27f]"
@click="showLoginDialog = true"
>
登录
</button>
@@ -123,7 +137,8 @@
:disable-ripple="currentSection === SECTIONS.GEMINI || currentSection === SECTIONS.FEATURES"
:anim-delay="logoTransitionDelay"
:static="currentSection === SECTIONS.FEATURES"
:class="[currentLogoClass, 'logo-active']"
class="logo-active"
:class="[currentLogoClass]"
/>
</div>
</Transition>
@@ -131,7 +146,10 @@
</div>
<!-- Section 0: Introduction -->
<section ref="section0" class="min-h-screen snap-start flex items-center justify-center px-16 lg:px-20 py-20">
<section
ref="section0"
class="min-h-screen snap-start flex items-center justify-center px-16 lg:px-20 py-20"
>
<div class="max-w-4xl mx-auto text-center">
<div class="h-80 w-full mb-16" />
<h1
@@ -144,13 +162,13 @@
class="mb-8 text-xl text-[#666663] dark:text-gray-300 max-w-2xl mx-auto transition-all duration-700"
:style="getDescStyle(SECTIONS.HOME)"
>
AI 开发工具统一接入平台<br />
AI 开发工具统一接入平台<br>
整合 Claude CodeCodex CLIGemini CLI 等多个 AI 编程助手
</p>
<button
@click="scrollToSection(SECTIONS.CLAUDE)"
class="mt-16 transition-all duration-700 cursor-pointer hover:scale-110"
:style="getScrollIndicatorStyle(SECTIONS.HOME)"
@click="scrollToSection(SECTIONS.CLAUDE)"
>
<ChevronDown class="h-8 w-8 mx-auto text-[#91918d] dark:text-muted-foreground/80 animate-bounce" />
</button>
@@ -160,12 +178,12 @@
<!-- Section 1: Claude Code -->
<CliSection
ref="section1"
v-model:platform-value="claudePlatform"
title="Claude Code"
description="直接在您的终端中释放Claude的原始力量。瞬间搜索百万行代码库。将数小时的流程转化为单一命令。您的工具。您的流程。您的代码库,以思维速度进化。"
:badge-icon="Code2"
badge-text="IDE 集成"
badge-class="bg-[#cc785c]/10 dark:bg-amber-900/30 border border-[#cc785c]/20 dark:border-amber-800 text-[#cc785c] dark:text-amber-400"
v-model:platform-value="claudePlatform"
:platform-options="platformPresets.claude.options"
:install-command="claudeInstallCommand"
:config-files="[{ path: '~/.claude/settings.json', content: claudeConfig, language: 'json' }]"
@@ -180,12 +198,12 @@
<!-- Section 2: Codex CLI -->
<CliSection
ref="section2"
v-model:platform-value="codexPlatform"
title="Codex CLI"
description="Codex CLI 是一款可在本地终端运行的编程助手工具它能够读取修改并执行用户指定目录中的代码"
:badge-icon="Terminal"
badge-text="命令行工具"
badge-class="bg-[#cc785c]/10 dark:bg-emerald-900/30 border border-[#cc785c]/20 dark:border-emerald-800 text-[#cc785c] dark:text-emerald-400"
v-model:platform-value="codexPlatform"
:platform-options="platformPresets.codex.options"
:install-command="codexInstallCommand"
:config-files="[
@@ -203,12 +221,12 @@
<!-- Section 3: Gemini CLI -->
<CliSection
ref="section3"
v-model:platform-value="geminiPlatform"
title="Gemini CLI"
description="Gemini CLI 是一款开源人工智能代理可将 Gemini 的强大功能直接带入你的终端它提供了对 Gemini 的轻量级访问为你提供了从提示符到我们模型的最直接路径"
:badge-icon="Sparkles"
badge-text="多模态 AI"
badge-class="bg-[#cc785c]/10 dark:bg-primary/20 border border-[#cc785c]/20 dark:border-primary/30 text-[#cc785c] dark:text-primary"
v-model:platform-value="geminiPlatform"
:platform-options="platformPresets.gemini.options"
:install-command="geminiInstallCommand"
:config-files="[
@@ -228,7 +246,10 @@
</CliSection>
<!-- Section 4: Features -->
<section ref="section4" class="min-h-screen snap-start flex items-center justify-center px-16 lg:px-20 py-20 relative overflow-hidden">
<section
ref="section4"
class="min-h-screen snap-start flex items-center justify-center px-16 lg:px-20 py-20 relative overflow-hidden"
>
<div class="max-w-4xl mx-auto text-center relative z-10">
<div
class="inline-flex items-center gap-2 rounded-full bg-[#cc785c]/10 dark:bg-purple-500/20 border border-[#cc785c]/20 dark:border-purple-500/40 px-4 py-2 text-sm font-medium text-[#cc785c] dark:text-purple-300 mb-6 backdrop-blur-sm transition-all duration-500"
@@ -273,8 +294,12 @@
: 'text-[#cc785c] dark:text-[#d4a27f] animate-spin'"
/>
</div>
<h3 class="text-lg font-bold text-[#191919] dark:text-white mb-2">{{ feature.title }}</h3>
<p class="text-sm text-[#666663] dark:text-[#c9c3b4]">{{ feature.desc }}</p>
<h3 class="text-lg font-bold text-[#191919] dark:text-white mb-2">
{{ feature.title }}
</h3>
<p class="text-sm text-[#666663] dark:text-[#c9c3b4]">
{{ feature.desc }}
</p>
<div
class="mt-3 inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium"
:class="feature.status === 'completed'
@@ -286,7 +311,10 @@
</div>
</div>
<div class="mt-12 transition-all duration-700" :style="getButtonsStyle(SECTIONS.FEATURES)">
<div
class="mt-12 transition-all duration-700"
:style="getButtonsStyle(SECTIONS.FEATURES)"
>
<RouterLink
v-if="authStore.isAuthenticated"
:to="dashboardPath"
@@ -297,8 +325,8 @@
</RouterLink>
<button
v-else
@click="showLoginDialog = true"
class="inline-flex items-center gap-2 rounded-xl bg-primary hover:bg-primary/90 px-6 py-3 text-base font-semibold text-white shadow-lg shadow-primary/30 transition hover:shadow-primary/50 hover:scale-105"
@click="showLoginDialog = true"
>
<Rocket class="h-5 w-5" />
立即开始使用
@@ -312,11 +340,22 @@
<footer class="relative z-10 border-t border-[#cc785c]/10 dark:border-[rgba(227,224,211,0.12)] bg-[#fafaf7]/90 dark:bg-[#191714]/95 backdrop-blur-md py-8">
<div class="mx-auto max-w-7xl px-6">
<div class="flex flex-col items-center justify-between gap-4 sm:flex-row">
<p class="text-sm text-[#91918d] dark:text-muted-foreground">© 2025 Aether. 团队内部使用</p>
<p class="text-sm text-[#91918d] dark:text-muted-foreground">
© 2025 Aether. 团队内部使用
</p>
<div class="flex items-center gap-6 text-sm text-[#91918d] dark:text-muted-foreground">
<a href="#" class="transition hover:text-[#191919] dark:hover:text-white">使用条款</a>
<a href="#" class="transition hover:text-[#191919] dark:hover:text-white">隐私政策</a>
<a href="#" class="transition hover:text-[#191919] dark:hover:text-white">技术支持</a>
<a
href="#"
class="transition hover:text-[#191919] dark:hover:text-white"
>使用条款</a>
<a
href="#"
class="transition hover:text-[#191919] dark:hover:text-white"
>隐私政策</a>
<a
href="#"
class="transition hover:text-[#191919] dark:hover:text-white"
>技术支持</a>
</div>
</div>
</div>

View File

@@ -1,8 +1,12 @@
<template>
<div class="min-h-screen bg-[#fafaf7] dark:bg-[#191714] p-8">
<div class="max-w-7xl mx-auto">
<h1 class="text-3xl font-bold text-center mb-2 text-[#191919] dark:text-white">Logo 颜色方案对比</h1>
<p class="text-center text-[#666663] dark:text-gray-400 mb-8">点击任意方案可以放大预览</p>
<h1 class="text-3xl font-bold text-center mb-2 text-[#191919] dark:text-white">
Logo 颜色方案对比
</h1>
<p class="text-center text-[#666663] dark:text-gray-400 mb-8">
点击任意方案可以放大预览
</p>
<!-- Color schemes grid -->
<div class="grid grid-cols-2 md:grid-cols-3 gap-6">
@@ -14,8 +18,10 @@
@click="selectScheme(index)"
>
<!-- Scheme name badge -->
<div class="absolute top-3 left-3 px-2 py-1 rounded-full text-xs font-medium"
:style="{ backgroundColor: scheme.primary + '20', color: scheme.primary }">
<div
class="absolute top-3 left-3 px-2 py-1 rounded-full text-xs font-medium"
:style="{ backgroundColor: scheme.primary + '20', color: scheme.primary }"
>
{{ scheme.name }}
</div>
@@ -27,10 +33,25 @@
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<linearGradient :id="`gradient-${index}`" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" :stop-color="scheme.primary" />
<stop offset="50%" :stop-color="scheme.secondary" />
<stop offset="100%" :stop-color="scheme.primary" />
<linearGradient
:id="`gradient-${index}`"
x1="0%"
y1="0%"
x2="100%"
y2="100%"
>
<stop
offset="0%"
:stop-color="scheme.primary"
/>
<stop
offset="50%"
:stop-color="scheme.secondary"
/>
<stop
offset="100%"
:stop-color="scheme.primary"
/>
</linearGradient>
</defs>
@@ -62,20 +83,22 @@
<div
class="w-8 h-8 rounded-full border-2 border-white shadow"
:style="{ backgroundColor: scheme.primary }"
></div>
/>
<span class="text-xs text-[#666663] dark:text-gray-400 mt-1">{{ scheme.primary }}</span>
</div>
<div class="flex flex-col items-center">
<div
class="w-8 h-8 rounded-full border-2 border-white shadow"
:style="{ backgroundColor: scheme.secondary }"
></div>
/>
<span class="text-xs text-[#666663] dark:text-gray-400 mt-1">{{ scheme.secondary }}</span>
</div>
</div>
<!-- Description -->
<p class="text-center text-sm text-[#666663] dark:text-gray-400 mt-3">{{ scheme.description }}</p>
<p class="text-center text-sm text-[#666663] dark:text-gray-400 mt-3">
{{ scheme.description }}
</p>
</div>
</div>
@@ -95,11 +118,21 @@
{{ colorSchemes[selectedScheme].name }}
</h2>
<button
@click="showPreview = false"
class="p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition"
@click="showPreview = false"
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
<svg
class="w-5 h-5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
@@ -126,7 +159,7 @@
<div
class="w-6 h-6 rounded-full border-2 border-white shadow"
:style="{ backgroundColor: colorSchemes[selectedScheme].primary }"
></div>
/>
<span class="text-sm font-mono text-[#666663] dark:text-gray-400">
{{ colorSchemes[selectedScheme].primary }}
</span>
@@ -135,7 +168,7 @@
<div
class="w-6 h-6 rounded-full border-2 border-white shadow"
:style="{ backgroundColor: colorSchemes[selectedScheme].secondary }"
></div>
/>
<span class="text-sm font-mono text-[#666663] dark:text-gray-400">
{{ colorSchemes[selectedScheme].secondary }}
</span>
@@ -145,8 +178,8 @@
<!-- Apply button -->
<div class="mt-6 text-center">
<button
@click="applyScheme"
class="px-6 py-2 bg-primary text-white rounded-xl font-medium hover:bg-primary/90 transition"
@click="applyScheme"
>
应用此方案
</button>
@@ -161,8 +194,18 @@
to="/"
class="inline-flex items-center gap-2 px-4 py-2 text-[#666663] dark:text-gray-400 hover:text-[#191919] dark:hover:text-white transition"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
<svg
class="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15 19l-7-7 7-7"
/>
</svg>
返回首页
</RouterLink>