feat: 静态首页
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>
|
||||||
Loading…
Reference in New Issue