feat: 工具导航页

master
LCJ-MinYa 5 months ago
parent bdc54856b0
commit d7dfd79a26

@ -1,25 +1,25 @@
const { VITE_HIDE_HOME } = import.meta.env;
const Layout = () => import("@/layout/index.vue");
const Layout = () => import('@/layout/index.vue');
export default {
path: "/",
name: "Home",
path: '/',
name: 'Home',
component: Layout,
redirect: "/welcome",
redirect: '/welcome',
meta: {
icon: "ep:home-filled",
title: "首页",
rank: 0
icon: 'ep:house',
title: '首页',
rank: 0,
},
children: [
{
path: "/welcome",
name: "Welcome",
component: () => import("@/views/welcome/index.vue"),
path: '/welcome',
name: 'Welcome',
component: () => import('@/views/welcome/index.vue'),
meta: {
title: "首页",
showLink: VITE_HIDE_HOME === "true" ? false : true
}
}
]
title: '首页',
showLink: VITE_HIDE_HOME === 'true' ? false : true,
},
},
],
} satisfies RouteConfigsTable;

@ -6,7 +6,7 @@ export default {
component: Layout,
redirect: '/template/base',
meta: {
icon: 'ep:house',
icon: 'ep:set-up',
title: '模版页面',
rank: 2,
},

@ -0,0 +1,23 @@
const Layout = () => import('@/layout/index.vue');
export default {
path: '/tool',
name: 'Tool',
component: Layout,
redirect: '/tool/nav',
meta: {
icon: 'ep:rank',
title: '工具页面',
rank: 1,
},
children: [
{
path: '/tool/nav',
name: 'ToolNav',
component: () => import('@/views/tool/nav/index.vue'),
meta: {
title: '工具导航',
},
},
],
} satisfies RouteConfigsTable;

@ -30,7 +30,7 @@
import { ref, computed, onMounted } from 'vue';
/** 原始数据列表 */
const dataList = Array.from({ length: 1000 }, (_, i) => ({ id: i, text: `Item ${i}` }));
const dataList = Array.from({ length: 10000 }, (_, i) => ({ id: i, text: `Item ${i}` }));
/** 虚拟列表单条item的高度 */
const itemHeight = 100;
/** 虚拟列表的总高度 */

@ -0,0 +1,217 @@
<template>
<div class="navigation-container">
<!-- 顶部标题栏 -->
<header class="header">
<h1 class="title">{{ pageTitle }}</h1>
<div
class="theme-toggle"
@click="toggleTheme"
>
<el-icon :size="24">
<component :is="themeIcon" />
</el-icon>
</div>
</header>
<!-- 搜索框 -->
<div class="search-container">
<el-input
v-model="searchQuery"
placeholder="搜索导航项..."
clearable
class="search-input"
>
<template #prefix>
<el-icon><Search /></el-icon>
</template>
</el-input>
</div>
<!-- 导航项网格 -->
<div class="nav-grid">
<div
v-for="(item, index) in filteredNavItems"
:key="index"
class="nav-item"
@click="navigateTo(item.url)"
>
<div class="nav-icon">
<el-icon :size="32">
<component :is="item.icon" />
</el-icon>
</div>
<div class="nav-name">{{ item.name }}</div>
</div>
</div>
<!-- 空状态提示 -->
<div
v-if="filteredNavItems.length === 0"
class="empty-state"
>
<el-icon :size="48"><Warning /></el-icon>
<p>没有找到匹配的导航项</p>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import { Search, Warning, Sunny, Moon, FullScreen, Printer, Picture } from '@element-plus/icons-vue';
//
const isDarkTheme = ref(false);
//
const pageTitle = ref('导航中心');
//
const searchQuery = ref('');
//
const navItems = ref([
{ icon: FullScreen, name: '二维码', url: '/demoHtml/qrcode/index.html' },
{ icon: Printer, name: 'OCR文字识别', url: '/demoHtml/ocr/ocr.html' },
{ icon: Picture, name: 'HTML转图片', url: '/#/htmlToImg' },
{ icon: Picture, name: '图片压缩', url: '/#/demo/compressImage' },
{ icon: Picture, name: '图片标注', url: '/#/demo/tuiImageEditor' },
]);
//
const filteredNavItems = computed(() => {
if (!searchQuery.value) return navItems.value;
return navItems.value.filter((item) => item.name.toLowerCase().includes(searchQuery.value.toLowerCase()));
});
//
const themeIcon = computed(() => (isDarkTheme.value ? Sunny : Moon));
//
const toggleTheme = () => {
isDarkTheme.value = !isDarkTheme.value;
document.documentElement.classList.toggle('dark', isDarkTheme.value);
};
// URL
const navigateTo = (url) => {
window.open(url, '_blank'); //
};
</script>
<style lang="scss" scoped>
.navigation-container {
min-height: 100vh;
padding: 1rem;
background-color: var(--el-bg-color);
transition: background-color 0.3s ease;
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
.title {
font-size: 1.5rem;
font-weight: bold;
color: var(--el-text-color-primary);
}
.theme-toggle {
cursor: pointer;
padding: 0.5rem;
border-radius: 50%;
transition: background-color 0.2s ease;
&:hover {
background-color: var(--el-fill-color-light);
}
}
}
.search-container {
max-width: 600px;
margin: 0 auto 2rem;
}
.nav-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
gap: 1.5rem;
max-width: 1200px;
margin: 0 auto;
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 1.5rem 0.5rem;
border-radius: var(--el-border-radius-base);
background-color: var(--el-fill-color-light);
cursor: pointer;
transition: all 0.2s ease;
text-align: center;
&:hover {
transform: translateY(-3px);
box-shadow: var(--el-box-shadow-light);
background-color: var(--el-fill-color);
}
.nav-icon {
margin-bottom: 0.75rem;
color: var(--el-color-primary);
}
.nav-name {
font-size: 0.9rem;
color: var(--el-text-color-regular);
}
}
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 3rem;
color: var(--el-text-color-secondary);
p {
margin-top: 1rem;
}
}
}
//
@media (max-width: 768px) {
.navigation-container {
.nav-grid {
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
gap: 1rem;
}
}
}
@media (max-width: 480px) {
.navigation-container {
.nav-grid {
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
gap: 0.75rem;
.nav-item {
padding: 1rem 0.25rem;
.nav-icon {
margin-bottom: 0.5rem;
}
.nav-name {
font-size: 0.8rem;
}
}
}
}
}
</style>
Loading…
Cancel
Save