Files
electron-opencode/src/renderer/views/home/HomeView.vue
2026-04-09 21:35:06 +08:00

426 lines
8.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="home-container">
<!-- 顶部欢迎区 -->
<div class="welcome-section">
<div class="welcome-content">
<h1 class="welcome-title">
<span class="greeting">你好开发者</span>
<span class="emoji">👋</span>
</h1>
<p class="welcome-subtitle">准备好开始今天的创作了吗</p>
</div>
</div>
<!-- 统计卡片区 -->
<el-row :gutter="16" class="stats-row">
<el-col :span="8" v-for="(stat, index) in stats" :key="index">
<el-card class="stat-card" shadow="hover">
<div class="stat-content">
<div class="stat-icon" :style="{ background: stat.color + '20' }">
<el-icon :size="24" :color="stat.color">
<component :is="stat.icon" />
</el-icon>
</div>
<div class="stat-info">
<p class="stat-value">{{ stat.value }}</p>
<p class="stat-label">{{ stat.label }}</p>
</div>
</div>
<div class="stat-trend" :class="stat.trend > 0 ? 'up' : 'down'">
<el-icon><component :is="stat.trend > 0 ? Top : Bottom" /></el-icon>
<span>{{ Math.abs(stat.trend) }}% 较上周</span>
</div>
</el-card>
</el-col>
</el-row>
<!-- 主要内容区 -->
<el-row :gutter="16" class="main-content">
<!-- 快捷操作区 -->
<el-col :span="12">
<el-card class="action-card" shadow="hover">
<template #header>
<div class="card-header">
<el-icon><Grid /></el-icon>
<span>快捷操作</span>
</div>
</template>
<div class="action-grid">
<div
v-for="action in actions"
:key="action.label"
class="action-item"
@click="action.onClick"
>
<div class="action-icon" :style="{ background: action.color + '20' }">
<el-icon :size="28" :color="action.color">
<component :is="action.icon" />
</el-icon>
</div>
<span class="action-label">{{ action.label }}</span>
</div>
</div>
</el-card>
</el-col>
<!-- 最近文件区 -->
<el-col :span="12">
<el-card class="recent-card" shadow="hover">
<template #header>
<div class="card-header">
<el-icon><Clock /></el-icon>
<span>最近访问</span>
</div>
</template>
<el-scrollbar height="280px">
<div class="recent-list">
<div
v-for="(item, index) in recents"
:key="index"
class="recent-item"
@click="handleFileClick(item)"
>
<div class="file-icon">
<el-icon :size="20"><Document /></el-icon>
</div>
<div class="file-info">
<p class="file-name">{{ item.name }}</p>
<p class="file-path">{{ item.path }}</p>
</div>
<span class="file-time">{{ item.time }}</span>
</div>
</div>
</el-scrollbar>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
import {
Document,
Plus,
FolderOpened,
Setting,
Upload,
Top,
Bottom,
Grid,
Clock,
Timer,
VideoCamera
} from '@element-plus/icons-vue'
const router = useRouter()
const stats = [
{
label: '文件总数',
value: '128',
trend: 12,
icon: Document,
color: '#409EFF'
},
{
label: '今日编辑',
value: '24',
trend: -3,
icon: Timer,
color: '#67C23A'
},
{
label: '运行次数',
value: '56',
trend: 8,
icon: VideoCamera,
color: '#E6A23C'
},
]
const actions = [
{
label: '新建文件',
icon: Plus,
color: '#409EFF',
onClick: () => router.push('/editor')
},
{
label: '打开文件',
icon: FolderOpened,
color: '#67C23A',
onClick: () => {}
},
{
label: '导入项目',
icon: Upload,
color: '#E6A23C',
onClick: () => {}
},
{
label: '系统设置',
icon: Setting,
color: '#F56C6C',
onClick: () => {}
},
]
const recents = [
{ name: 'main.js', path: '/src/main', time: '2 分钟前' },
{ name: 'App.vue', path: '/src/renderer', time: '1 小时前' },
{ name: 'index.css', path: '/src/renderer', time: '昨天' },
{ name: 'forge.config.js', path: '/', time: '3 天前' },
{ name: 'package.json', path: '/', time: '5 天前' },
]
const handleFileClick = (item) => {
console.log('点击文件:', item)
}
</script>
<style scoped>
.home-container {
padding: 24px;
height: 100%;
display: flex;
flex-direction: column;
gap: 20px;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}
/* 欢迎区样式 */
.welcome-section {
margin-bottom: 8px;
}
.welcome-content {
display: inline-block;
}
.welcome-title {
font-size: 28px;
font-weight: 600;
color: #303133;
margin: 0;
display: flex;
align-items: center;
gap: 12px;
}
.greeting {
background: linear-gradient(90deg, #409EFF 0%, #67C23A 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.emoji {
font-size: 32px;
}
.welcome-subtitle {
font-size: 14px;
color: #909399;
margin: 8px 0 0 0;
}
/* 统计卡片区 */
.stats-row {
margin-bottom: 8px;
}
.stat-card {
border-radius: 12px;
border: none;
transition: all 0.3s ease;
}
.stat-card:hover {
transform: translateY(-4px);
}
.stat-content {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 12px;
}
.stat-icon {
width: 56px;
height: 56px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.stat-info {
flex: 1;
}
.stat-value {
font-size: 32px;
font-weight: 700;
color: #303133;
margin: 0;
line-height: 1;
}
.stat-label {
font-size: 13px;
color: #909399;
margin: 6px 0 0 0;
}
.stat-trend {
display: flex;
align-items: center;
gap: 4px;
font-size: 12px;
padding-top: 8px;
border-top: 1px solid #f0f0f0;
}
.stat-trend.up {
color: #67C23A;
}
.stat-trend.down {
color: #F56C6C;
}
/* 主要内容区 */
.main-content {
flex: 1;
min-height: 0;
}
.action-card,
.recent-card {
border-radius: 12px;
border: none;
height: 100%;
}
.card-header {
display: flex;
align-items: center;
gap: 8px;
font-weight: 600;
font-size: 15px;
color: #303133;
}
/* 快捷操作区 */
.action-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
padding: 8px 0;
}
.action-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
padding: 20px 16px;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s ease;
background: #f5f7fa;
}
.action-item:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.action-icon {
width: 56px;
height: 56px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: all 0.3s ease;
}
.action-item:hover .action-icon {
transform: scale(1.1);
}
.action-label {
font-size: 13px;
color: #606266;
font-weight: 500;
text-align: center;
}
/* 最近文件区 */
.recent-list {
padding: 8px 0;
}
.recent-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
margin-bottom: 4px;
}
.recent-item:hover {
background: #f5f7fa;
}
.file-icon {
width: 40px;
height: 40px;
border-radius: 8px;
background: #ecf5ff;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: #409EFF;
}
.file-info {
flex: 1;
min-width: 0;
}
.file-name {
font-size: 14px;
color: #303133;
margin: 0;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.file-path {
font-size: 12px;
color: #909399;
margin: 4px 0 0 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.file-time {
font-size: 12px;
color: #C0C4CC;
flex-shrink: 0;
}
</style>