转为使用element-plus

This commit is contained in:
2026-01-25 14:09:47 +08:00
parent 5569e73ef1
commit 1134ecb732
73 changed files with 3 additions and 18855 deletions

View File

@@ -1,288 +0,0 @@
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
const props = defineProps({
title: {
type: String,
default: '暂无数据'
},
description: {
type: String,
default: '当前页面暂无相关数据,您可以稍后再来查看'
},
showAction: {
type: Boolean,
default: true
},
actionText: {
type: String,
default: '刷新页面'
}
})
const handleAction = () => {
router.go(0)
}
</script>
<template>
<div class="empty-state">
<div class="empty-content">
<div class="empty-illustration">
<div class="illustration-wrapper">
<svg class="empty-icon" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="boxGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color: #667eea; stop-opacity: 0.2" />
<stop offset="100%" style="stop-color: #764ba2; stop-opacity: 0.2" />
</linearGradient>
<linearGradient id="searchGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color: #00d4ff; stop-opacity: 1" />
<stop offset="100%" style="stop-color: #7c4dff; stop-opacity: 1" />
</linearGradient>
</defs>
<!-- 背景圆 -->
<circle cx="100" cy="100" r="80" fill="url(#boxGradient)" />
<!-- 搜索放大镜 -->
<g transform="translate(70, 70)">
<circle cx="30" cy="30" r="25" stroke="url(#searchGradient)" stroke-width="4" fill="none" />
<line x1="50" y1="50" x2="70" y2="70" stroke="url(#searchGradient)" stroke-width="4"
stroke-linecap="round" />
</g>
<!-- 小装饰元素 -->
<circle cx="50" cy="60" r="4" fill="#667eea" opacity="0.6">
<animate attributeName="cy" values="60;55;60" dur="2s" repeatCount="indefinite" />
</circle>
<circle cx="150" cy="80" r="3" fill="#764ba2" opacity="0.6">
<animate attributeName="cy" values="80;75;80" dur="1.5s" repeatCount="indefinite" />
</circle>
<circle cx="60" cy="140" r="5" fill="#00d4ff" opacity="0.5">
<animate attributeName="cy" values="140;145;140" dur="2.5s" repeatCount="indefinite" />
</circle>
</svg>
</div>
</div>
<div class="empty-text">
<h3 class="empty-title">{{ title }}</h3>
<p class="empty-description">{{ description }}</p>
</div>
<div v-if="showAction" class="empty-action">
<button class="action-btn" @click="handleAction">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M23 4v6h-6"></path>
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
</svg>
{{ actionText }}
</button>
</div>
</div>
</div>
</template>
<style scoped>
.empty-state {
min-height: 400px;
display: flex;
align-items: center;
justify-content: center;
padding: 60px 20px;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.03) 0%, rgba(118, 75, 162, 0.03) 100%);
border-radius: 16px;
position: relative;
overflow: hidden;
}
/* 装饰性背景 */
.empty-state::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image:
radial-gradient(2px 2px at 20px 30px, rgba(102, 126, 234, 0.3), transparent),
radial-gradient(2px 2px at 40px 70px, rgba(118, 75, 162, 0.3), transparent),
radial-gradient(1px 1px at 90px 40px, rgba(0, 212, 255, 0.3), transparent),
radial-gradient(2px 2px at 160px 120px, rgba(102, 126, 234, 0.3), transparent);
background-size: 200px 150px;
animation: floatBg 20s linear infinite;
opacity: 0.5;
}
@keyframes floatBg {
0% {
background-position: 0 0;
}
100% {
background-position: 200px 150px;
}
}
.empty-content {
text-align: center;
position: relative;
z-index: 1;
max-width: 480px;
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.empty-illustration {
margin-bottom: 32px;
position: relative;
}
.illustration-wrapper {
display: inline-block;
position: relative;
}
.empty-icon {
width: 180px;
height: 180px;
animation: floatIcon 3s ease-in-out infinite;
}
@keyframes floatIcon {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
}
.empty-text {
margin-bottom: 32px;
}
.empty-title {
font-size: 24px;
font-weight: 600;
color: #333;
margin: 0 0 12px;
letter-spacing: 0.5px;
}
.empty-description {
font-size: 15px;
color: #666;
margin: 0;
line-height: 1.6;
}
.empty-action {
display: flex;
justify-content: center;
}
.action-btn {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 32px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 10px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
letter-spacing: 0.5px;
}
.action-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 25px rgba(102, 126, 234, 0.4);
}
.action-btn:active {
transform: translateY(0);
}
.action-btn svg {
flex-shrink: 0;
}
/* 暗色主题适配 */
@media (prefers-color-scheme: dark) {
.empty-title {
color: #fff;
}
.empty-description {
color: rgba(255, 255, 255, 0.7);
}
}
/* 响应式适配 */
@media (max-width: 768px) {
.empty-state {
min-height: 300px;
padding: 40px 20px;
}
.empty-icon {
width: 140px;
height: 140px;
}
.empty-title {
font-size: 20px;
}
.empty-description {
font-size: 14px;
}
.action-btn {
padding: 10px 24px;
font-size: 14px;
}
}
@media (max-width: 480px) {
.empty-state {
padding: 30px 16px;
min-height: 250px;
}
.empty-icon {
width: 120px;
height: 120px;
}
.empty-title {
font-size: 18px;
}
.empty-description {
font-size: 13px;
}
}
</style>