147 lines
3.3 KiB
Vue
147 lines
3.3 KiB
Vue
<template>
|
|
<div class="page-container home">
|
|
<div class="hero-section">
|
|
<div class="logo-wrapper">
|
|
<div class="logo-text">Luxx</div>
|
|
</div>
|
|
<p class="subtitle">智能会话管理与工具平台</p>
|
|
</div>
|
|
|
|
<div class="stats-section">
|
|
<div class="stat-card">
|
|
<div class="stat-number">{{ stats.conversations }}</div>
|
|
<div class="stat-label">会话</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-number">{{ stats.tools }}</div>
|
|
<div class="stat-label">工具</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-number">{{ formatTokens(stats.totalTokens) }}</div>
|
|
<div class="stat-label">Tokens</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted } from 'vue'
|
|
import { conversationsAPI, toolsAPI } from '../utils/api.js'
|
|
import { formatTokens } from '../utils/useFormatters.js'
|
|
|
|
const stats = ref({ conversations: 0, tools: 0, totalTokens: 0 })
|
|
|
|
onMounted(async () => {
|
|
try {
|
|
const [convs, tools] = await Promise.allSettled([
|
|
conversationsAPI.list({ page: 1, page_size: 100 }),
|
|
toolsAPI.list()
|
|
])
|
|
if (convs.status === 'fulfilled' && convs.value.success) {
|
|
stats.value.conversations = convs.value.data?.total || 0
|
|
const items = convs.value.data?.items || []
|
|
stats.value.totalTokens = items.reduce((sum, c) => sum + (c.token_count || 0), 0)
|
|
}
|
|
if (tools.status === 'fulfilled' && tools.value.success) {
|
|
const data = tools.value.data?.categorized || {}
|
|
let total = 0
|
|
Object.values(data).forEach(arr => {
|
|
if (Array.isArray(arr)) total += arr.length
|
|
})
|
|
stats.value.tools = total
|
|
}
|
|
} catch (e) { console.error(e) }
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.home {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 4rem 2rem;
|
|
min-height: calc(100vh - 4rem);
|
|
}
|
|
.hero-section {
|
|
text-align: center;
|
|
margin-bottom: 3rem;
|
|
}
|
|
.logo-wrapper {
|
|
display: inline-block;
|
|
padding: 1.5rem 4rem;
|
|
}
|
|
.logo-text {
|
|
font-size: 6rem;
|
|
font-weight: 800;
|
|
letter-spacing: -0.02em;
|
|
line-height: 1.1;
|
|
color: var(--accent-primary);
|
|
text-shadow: 0 2px 10px rgba(37, 99, 235, 0.3);
|
|
}
|
|
.subtitle {
|
|
font-size: 1.25rem;
|
|
color: var(--text-secondary);
|
|
margin: 1.5rem 0 0;
|
|
font-weight: 400;
|
|
}
|
|
.stats-section {
|
|
display: flex;
|
|
gap: 2rem;
|
|
}
|
|
.stat-card {
|
|
text-align: center;
|
|
padding: 2rem 3rem;
|
|
background: var(--bg-primary);
|
|
border: 1px solid var(--border-light);
|
|
border-radius: 16px;
|
|
min-width: 140px;
|
|
transition: all 0.2s;
|
|
}
|
|
.stat-card:hover {
|
|
border-color: var(--accent-primary);
|
|
box-shadow: 0 4px 20px rgba(37, 99, 235, 0.1);
|
|
transform: translateY(-2px);
|
|
}
|
|
.stat-number {
|
|
font-size: 3rem;
|
|
font-weight: 700;
|
|
color: var(--text-primary);
|
|
line-height: 1.2;
|
|
}
|
|
.stat-label {
|
|
font-size: 0.9rem;
|
|
color: var(--text-secondary);
|
|
margin-top: 0.5rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.home {
|
|
padding: 2rem 1rem;
|
|
}
|
|
.logo-text {
|
|
font-size: 3.5rem;
|
|
}
|
|
.logo-wrapper {
|
|
padding: 1rem 2rem;
|
|
}
|
|
.subtitle {
|
|
font-size: 1rem;
|
|
}
|
|
.stats-section {
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
}
|
|
.stat-card {
|
|
padding: 1.5rem 2rem;
|
|
min-width: 100%;
|
|
}
|
|
.stat-number {
|
|
font-size: 2rem;
|
|
}
|
|
}
|
|
</style>
|