feat: 项目初始化及当前全部内容提交

This commit is contained in:
2025-07-15 17:37:50 +08:00
parent ec817067f1
commit e78f192d34
622 changed files with 75174 additions and 383 deletions
+569
View File
@@ -0,0 +1,569 @@
<template>
<div class="home-container">
<!-- 导航栏 -->
<header class="header glass">
<div class="header-content">
<div class="logo">
<h1 class="gradient-text">情绪博物馆</h1>
<span class="subtitle">AI心理健康助手</span>
</div>
<nav class="nav-menu">
<a-button type="text" class="nav-item" @click="$router.push('/chat')">
<MessageOutlined />
AI对话
</a-button>
<a-button type="text" class="nav-item" @click="$router.push('/history')">
<HistoryOutlined />
历史记录
</a-button>
<a-button type="text" class="nav-item" @click="$router.push('/analysis')">
<BarChartOutlined />
情绪分析
</a-button>
<!-- 用户状态区域 -->
<div class="user-area">
<template v-if="userStore.isLoggedIn">
<a-dropdown>
<a-button type="text" class="nav-item user-btn">
<UserOutlined />
{{ userStore.userInfo.username || userStore.userInfo.account }}
</a-button>
<template #overlay>
<a-menu>
<a-menu-item key="profile">
<UserOutlined />
个人资料
</a-menu-item>
<a-menu-divider />
<a-menu-item key="logout" @click="handleLogout">
<LogoutOutlined />
退出登录
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
<template v-else>
<a-button type="text" class="nav-item" @click="$router.push('/login')">
<LoginOutlined />
登录
</a-button>
</template>
</div>
</nav>
</div>
</header>
<!-- 主要内容 -->
<main class="main-content">
<div class="hero-section">
<div class="hero-content fade-in-up">
<h2 class="hero-title">
欢迎来到情绪博物馆
</h2>
<p class="hero-description">
您的专属AI心理健康助手提供24/7情绪支持心理分析和个性化建议
</p>
<div class="hero-actions">
<a-button
type="primary"
size="large"
class="start-chat-btn"
@click="startChat"
style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border: none; margin-right: 16px;"
>
<MessageOutlined />
开始对话
</a-button>
<a-button
size="large"
class="learn-more-btn"
@click="scrollToFeatures"
style="background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.3); color: white;"
>
了解更多
</a-button>
</div>
</div>
<!-- 装饰性元素 -->
<div class="hero-decoration">
<div class="floating-card card bounce-in" style="animation-delay: 0.2s">
<HeartOutlined class="icon" />
<span>情绪识别</span>
</div>
<div class="floating-card card bounce-in" style="animation-delay: 0.4s">
<BulbOutlined class="icon" />
<span>智能建议</span>
</div>
<div class="floating-card card bounce-in" style="animation-delay: 0.6s">
<SafetyOutlined class="icon" />
<span>隐私保护</span>
</div>
</div>
</div>
<!-- 功能特性 -->
<section class="features-section" ref="featuresRef">
<div class="section-header">
<h3 class="section-title gradient-text">核心功能</h3>
<p class="section-description">专业的AI技术贴心的情绪关怀</p>
</div>
<div class="features-grid">
<div class="feature-card card" v-for="feature in features" :key="feature.id">
<div class="feature-icon">
<component :is="feature.icon" />
</div>
<h4 class="feature-title">{{ feature.title }}</h4>
<p class="feature-description">{{ feature.description }}</p>
</div>
</div>
</section>
<!-- 统计数据 -->
<section class="stats-section">
<div class="stats-container glass">
<div class="stat-item" v-for="stat in stats" :key="stat.label">
<div class="stat-number gradient-text">{{ stat.value }}</div>
<div class="stat-label">{{ stat.label }}</div>
</div>
</div>
</section>
<!-- API测试组件 (仅开发环境) -->
<section v-if="showApiTest" class="api-test-section">
<ApiTest />
</section>
</main>
<!-- 页脚 -->
<footer class="footer">
<div class="footer-content">
<p>&copy; 2025 情绪博物馆. 用心守护每一份情绪</p>
</div>
</footer>
</div>
</template>
<script setup>
import { ref, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { message } from 'ant-design-vue'
import {
MessageOutlined,
HistoryOutlined,
BarChartOutlined,
HeartOutlined,
BulbOutlined,
SafetyOutlined,
RobotOutlined,
LineChartOutlined,
ClockCircleOutlined,
LockOutlined,
UserOutlined,
LoginOutlined,
LogoutOutlined
} from '@ant-design/icons-vue'
import { ENV_CONFIG } from '@/config/env'
import { useUserStore } from '@/stores/user'
import ApiTest from '@/components/ApiTest.vue'
const router = useRouter()
const userStore = useUserStore()
const featuresRef = ref(null)
// 是否显示API测试组件 (仅开发环境)
const showApiTest = computed(() => ENV_CONFIG.isDevelopment)
// 功能特性数据
const features = ref([
{
id: 1,
icon: RobotOutlined,
title: 'AI智能对话',
description: '基于先进的自然语言处理技术,提供自然流畅的对话体验'
},
{
id: 2,
icon: LineChartOutlined,
title: '情绪分析',
description: '实时分析您的情绪状态,提供专业的心理健康评估'
},
{
id: 3,
icon: ClockCircleOutlined,
title: '24/7支持',
description: '全天候在线服务,随时随地为您提供情绪支持和心理疏导'
},
{
id: 4,
icon: LockOutlined,
title: '隐私保护',
description: '严格保护用户隐私,所有对话内容都经过加密处理'
}
])
// 统计数据
const stats = ref([
{ value: '10,000+', label: '用户信赖' },
{ value: '50,000+', label: '对话次数' },
{ value: '95%', label: '满意度' },
{ value: '24/7', label: '在线服务' }
])
// 开始对话
const startChat = () => {
console.log('开始对话按钮被点击')
router.push('/chat')
}
// 滚动到功能区域
const scrollToFeatures = () => {
featuresRef.value?.scrollIntoView({ behavior: 'smooth' })
}
// 处理登出
const handleLogout = async () => {
try {
await userStore.logout()
message.success('已退出登录')
} catch (error) {
console.error('登出失败:', error)
message.error('登出失败')
}
}
onMounted(() => {
// 页面加载动画
document.body.style.overflow = 'hidden'
setTimeout(() => {
document.body.style.overflow = 'auto'
}, 1000)
})
</script>
<style lang="scss" scoped>
.home-container {
min-height: 100vh;
background: var(--gradient-primary);
position: relative;
overflow-x: hidden;
}
.header {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
padding: var(--spacing-md) 0;
.header-content {
max-width: 1200px;
margin: 0 auto;
padding: 0 var(--spacing-lg);
display: flex;
align-items: center;
justify-content: space-between;
}
.logo {
h1 {
font-size: 24px;
margin: 0;
}
.subtitle {
font-size: 12px;
color: rgba(255, 255, 255, 0.8);
margin-left: var(--spacing-sm);
}
}
.nav-menu {
display: flex;
align-items: center;
gap: var(--spacing-lg);
.nav-item {
color: rgba(255, 255, 255, 0.9) !important;
border: none !important;
box-shadow: none !important;
background: transparent !important;
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--border-radius-small);
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: var(--spacing-xs);
&:hover {
background: rgba(255, 255, 255, 0.1) !important;
color: white !important;
}
}
.user-area {
margin-left: var(--spacing-md);
.user-btn {
background: rgba(255, 255, 255, 0.1) !important;
border: 1px solid rgba(255, 255, 255, 0.2) !important;
&:hover {
background: rgba(255, 255, 255, 0.2) !important;
}
}
}
}
}
.main-content {
padding-top: 80px;
}
.hero-section {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
position: relative;
padding: var(--spacing-xxl) var(--spacing-lg);
.hero-content {
text-align: center;
max-width: 600px;
color: white;
.hero-title {
font-size: 48px;
font-weight: 700;
margin-bottom: var(--spacing-lg);
line-height: 1.2;
}
.hero-description {
font-size: 18px;
margin-bottom: var(--spacing-xxl);
opacity: 0.9;
line-height: 1.6;
}
.hero-actions {
display: flex;
gap: var(--spacing-md);
justify-content: center;
flex-wrap: wrap;
.start-chat-btn {
height: 50px;
padding: 0 var(--spacing-xl);
font-size: 16px;
}
.learn-more-btn {
height: 50px;
padding: 0 var(--spacing-xl);
font-size: 16px;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.3);
color: white;
&:hover {
background: rgba(255, 255, 255, 0.2);
border-color: rgba(255, 255, 255, 0.5);
}
}
}
}
.hero-decoration {
position: absolute;
top: 50%;
right: 10%;
transform: translateY(-50%);
.floating-card {
position: absolute;
padding: var(--spacing-md);
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
color: white;
display: flex;
align-items: center;
gap: var(--spacing-sm);
white-space: nowrap;
.icon {
font-size: 20px;
}
&:nth-child(1) {
top: -60px;
right: 0;
}
&:nth-child(2) {
top: 20px;
right: -40px;
}
&:nth-child(3) {
top: 100px;
right: 20px;
}
}
}
}
.features-section {
padding: var(--spacing-xxl) var(--spacing-lg);
background: rgba(255, 255, 255, 0.05);
.section-header {
text-align: center;
margin-bottom: var(--spacing-xxl);
color: white;
.section-title {
font-size: 36px;
margin-bottom: var(--spacing-md);
}
.section-description {
font-size: 16px;
opacity: 0.8;
}
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: var(--spacing-xl);
max-width: 1000px;
margin: 0 auto;
.feature-card {
text-align: center;
background: rgba(255, 255, 255, 0.95);
.feature-icon {
font-size: 48px;
color: var(--primary-color);
margin-bottom: var(--spacing-md);
}
.feature-title {
font-size: 20px;
margin-bottom: var(--spacing-md);
color: var(--text-primary);
}
.feature-description {
color: var(--text-secondary);
line-height: 1.6;
}
}
}
}
.stats-section {
padding: var(--spacing-xxl) var(--spacing-lg);
.stats-container {
max-width: 800px;
margin: 0 auto;
padding: var(--spacing-xl);
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: var(--spacing-xl);
text-align: center;
.stat-item {
.stat-number {
font-size: 36px;
font-weight: 700;
margin-bottom: var(--spacing-sm);
}
.stat-label {
color: rgba(255, 255, 255, 0.8);
font-size: 14px;
}
}
}
}
.api-test-section {
padding: var(--spacing-xxl) var(--spacing-lg);
background: rgba(255, 255, 255, 0.05);
:deep(.ant-card) {
background: rgba(255, 255, 255, 0.95);
border: none;
border-radius: var(--border-radius-large);
box-shadow: var(--shadow-large);
}
}
.footer {
padding: var(--spacing-xl) var(--spacing-lg);
background: rgba(0, 0, 0, 0.2);
.footer-content {
text-align: center;
color: rgba(255, 255, 255, 0.7);
}
}
// 响应式设计
@media (max-width: 768px) {
.header {
.header-content {
padding: 0 var(--spacing-md);
}
.nav-menu {
gap: var(--spacing-md);
.nav-item {
padding: var(--spacing-xs) var(--spacing-sm);
font-size: 14px;
}
}
}
.hero-section {
.hero-content {
.hero-title {
font-size: 32px;
}
.hero-description {
font-size: 16px;
}
}
.hero-decoration {
display: none;
}
}
.features-section {
.features-grid {
grid-template-columns: 1fr;
gap: var(--spacing-lg);
}
}
.stats-section {
.stats-container {
grid-template-columns: repeat(2, 1fr);
gap: var(--spacing-lg);
}
}
}
</style>