feat: 静态首页

master
LCJ-MinYa 5 months ago
parent 68beb08f90
commit 3f3366fde4

@ -0,0 +1,41 @@
<template>
<div
ref="chartRef"
class="w-full h-full"
></div>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue';
import * as echarts from 'echarts';
const props = defineProps({
option: Object,
});
const chartRef = ref(null);
let chartInstance = null;
onMounted(() => {
if (chartRef.value) {
chartInstance = echarts.init(chartRef.value);
chartInstance.setOption(props.option);
//
const resizeObserver = new ResizeObserver(() => {
chartInstance.resize();
});
resizeObserver.observe(chartRef.value);
}
});
watch(
() => props.option,
(newVal) => {
if (chartInstance) {
chartInstance.setOption(newVal);
}
},
{ deep: true }
);
</script>

@ -0,0 +1,27 @@
<template>
<div class="recent-note-card bg-white p-4 rounded-lg transition-all hover:bg-gray-50 cursor-pointer border border-gray-200 hover:border-blue-300">
<h4 class="font-medium text-lg mb-1 truncate text-gray-800">{{ title }}</h4>
<div class="flex items-center text-sm text-gray-500 mb-2">
<span class="bg-blue-100 text-blue-600 px-2 py-0.5 rounded text-xs mr-2">{{ category }}</span>
<span>{{ date }}</span>
</div>
<div class="flex flex-wrap gap-1">
<span
v-for="(tag, index) in tags"
:key="index"
class="bg-gray-100 text-gray-600 px-2 py-0.5 rounded text-xs"
>
{{ tag }}
</span>
</div>
</div>
</template>
<script setup>
defineProps({
title: String,
category: String,
date: String,
tags: Array,
});
</script>

@ -0,0 +1,34 @@
<template>
<div
class="stat-card p-6 rounded-xl shadow-md transition-all duration-300 hover:shadow-lg"
:class="bgColor"
>
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-600">{{ title }}</p>
<h3
class="text-3xl font-bold mt-2"
:class="color"
>
{{ value }}
</h3>
</div>
<el-icon
:size="40"
:class="`${color} opacity-80`"
>
<component :is="icon" />
</el-icon>
</div>
</div>
</template>
<script setup>
defineProps({
icon: String,
title: String,
value: [String, Number],
color: String,
bgColor: String,
});
</script>

@ -0,0 +1,27 @@
<template>
<div class="space-y-4">
<div
v-for="item in data"
:key="item.name"
class="tech-item"
>
<div class="flex justify-between text-sm mb-1 text-gray-700">
<span>{{ item.name }}</span>
<span>{{ item.progress }}%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div
class="h-2.5 rounded-full transition-all duration-1000 ease-out"
:class="item.color"
:style="{ width: `${item.progress}%` }"
></div>
</div>
</div>
</div>
</template>
<script setup>
defineProps({
data: Array,
});
</script>

@ -1,14 +1,234 @@
<script setup lang="ts">
import useTestStore from '@/store/modules/test';
<template>
<div class="dashboard-container min-h-screen bg-white text-gray-800 p-6">
<!-- 头部欢迎区域 -->
<div class="welcome-section mb-8">
<h1 class="text-4xl font-bold mb-2">欢迎回来, <span class="text-blue-600">开发者</span>!</h1>
<p class="text-gray-600">今天是 {{ currentDate }}今天也要保持学习哦</p>
</div>
<!-- 数据统计卡片 -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<StatCard
icon="el-icon-notebook-2"
title="总笔记数"
:value="stats.totalNotes"
color="text-purple-600"
bg-color="bg-purple-50"
/>
<StatCard
icon="el-icon-collection-tag"
title="分类数"
:value="stats.categories"
color="text-blue-600"
bg-color="bg-blue-50"
/>
<StatCard
icon="el-icon-star-off"
title="本周新增"
:value="stats.weeklyAdded"
color="text-green-600"
bg-color="bg-green-50"
/>
<StatCard
icon="el-icon-time"
title="最近更新"
:value="stats.lastUpdated"
color="text-yellow-600"
bg-color="bg-yellow-50"
/>
</div>
<!-- 主要内容区域 -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- 笔记分类图表 -->
<div class="lg:col-span-2">
<div class="bg-white rounded-xl p-6 shadow-md border border-gray-200">
<h2 class="text-xl font-semibold mb-4 flex items-center text-gray-800">
<el-icon class="mr-2 text-blue-600"><Notebook /></el-icon>
笔记分类统计
</h2>
<div class="h-80">
<Chart
:option="categoryChartOption"
class="w-full h-full"
/>
</div>
</div>
</div>
<!-- 最近笔记 -->
<div>
<div class="bg-white rounded-xl p-6 shadow-md border border-gray-200 h-full">
<h2 class="text-xl font-semibold mb-4 flex items-center text-gray-800">
<el-icon class="mr-2 text-blue-600"><Clock /></el-icon>
最近笔记
</h2>
<div class="space-y-4">
<RecentNoteCard
v-for="note in recentNotes"
:key="note.id"
:title="note.title"
:category="note.category"
:date="note.date"
:tags="note.tags"
/>
</div>
</div>
</div>
</div>
<!-- 技术栈展示 -->
<div class="mt-8">
<div class="bg-white rounded-xl p-6 shadow-md border border-gray-200">
<h2 class="text-xl font-semibold mb-6 flex items-center text-gray-800">
<el-icon class="mr-2 text-blue-600"><Cpu /></el-icon>
技术栈概览
</h2>
<TechStack :data="techStackData" />
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
import { Notebook, Clock, Cpu } from '@element-plus/icons-vue';
import * as echarts from 'echarts';
import StatCard from './components/StatCard.vue';
import RecentNoteCard from './components/RecentNoteCard.vue';
import TechStack from './components/TechStack.vue';
import Chart from './components/Chart.vue';
//
const currentDate = computed(() => {
return new Date().toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long',
});
});
//
const stats = ref({
totalNotes: 128,
categories: 12,
weeklyAdded: 7,
lastUpdated: '2小时前',
});
const testStore = useTestStore();
//
const recentNotes = ref([
{
id: 1,
title: 'Vue3组合式API最佳实践',
category: '前端',
date: '2023-05-15',
tags: ['Vue', 'JavaScript'],
},
{
id: 2,
title: 'TailwindCSS使用技巧',
category: '前端',
date: '2023-05-14',
tags: ['CSS', 'Tailwind'],
},
{
id: 3,
title: 'Node.js性能优化',
category: '后端',
date: '2023-05-12',
tags: ['Node', '性能'],
},
{
id: 4,
title: 'Docker容器化部署',
category: '运维',
date: '2023-05-10',
tags: ['Docker', 'DevOps'],
},
]);
testStore.updateCount();
defineOptions({
name: 'Welcome',
//
const techStackData = ref([
{ name: 'Vue3', progress: 90, color: 'bg-green-500' },
{ name: 'TypeScript', progress: 80, color: 'bg-blue-500' },
{ name: 'Node.js', progress: 75, color: 'bg-yellow-500' },
{ name: 'Docker', progress: 70, color: 'bg-purple-500' },
{ name: 'Python', progress: 65, color: 'bg-red-500' },
{ name: 'Go', progress: 50, color: 'bg-indigo-500' },
]);
// -
const categoryChartOption = ref({
tooltip: {
trigger: 'item',
},
legend: {
top: '5%',
left: 'center',
textStyle: {
color: '#333',
},
},
series: [
{
name: '笔记分类',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2,
},
label: {
show: false,
position: 'center',
},
emphasis: {
label: {
show: true,
fontSize: '18',
fontWeight: 'bold',
color: '#333',
},
},
labelLine: {
show: false,
},
data: [
{ value: 42, name: '前端' },
{ value: 30, name: '后端' },
{ value: 25, name: '运维' },
{ value: 18, name: '算法' },
{ value: 13, name: '数据库' },
],
color: ['#60a5fa', '#f472b6', '#f59e0b', '#10b981', '#8b5cf6'],
},
],
});
onMounted(() => {
//
});
</script>
<template>
<h1>首页</h1>
</template>
<style lang="scss" scoped>
.dashboard-container {
.welcome-section {
animation: fadeIn 0.8s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
}
</style>

Loading…
Cancel
Save