完善首页显示

This commit is contained in:
2025-12-14 00:12:13 +08:00
parent 3559f2bf1e
commit 970e734dda
9 changed files with 284 additions and 26 deletions

View File

@@ -0,0 +1,109 @@
<template>
<header class="header">
<div class="header-left">
<button class="header-button create-datascreen"><i class="fa-solid fa-plus"></i> 创建大屏</button>
<button class="header-button import-datascreen"><i class="fa-solid fa-file-import"></i> 导入大屏</button>
</div>
<div class="header-right">
<input type="text" placeholder="请输入名称" class="header-search"></input>
<button class="header-button search-button"><i class="fa-solid fa-magnifying-glass"></i></button>
</div>
</header>
<main class="main">
<div class="no-data">
<i class="fa-solid fa-circle-xmark"></i>
<span>暂无数据</span>
</div>
</main>
</template>
<style>
.header-left {
position: absolute;
top: 15px;
left: 15px;
}
.header-right {
position: absolute;
top: 15px;
right: 15px;
}
.header-button {
width: 120px;
height: 32px;
font-size: 15px;
border: none;
border-radius: 10px;
margin: 0 4px;
}
.header-button:first-child {
margin-left: 0;
}
.header-button:last-child {
margin-right: 0;
}
.create-datascreen {
color: #fff;
background-color: #00b7ff;
}
.create-datascreen:hover {
background-color: #00a2e2;
}
.create-datascreen:active {
background-color: #0088c3;
}
.import-datascreen {
color: #fff;
background-color: #f472b6;
}
.import-datascreen:hover,
.search-button:hover {
background-color: #e267a7;
}
.import-datascreen:active,
.search-button:active {
background-color: #c35b99;
}
.header-search {
width: 150px;
height: 32px;
font-size: 15px;
border: none;
border-radius: 10px;
padding: 0 10px;
background-color: rgba(255,255,255,0.3);
}
.header-search:hover {
background-color: rgba(255,255,255,0.4);
}
.header-search:focus {
outline: none;
background-color: rgba(255,255,255,0.5);
}
.search-button {
width: 32px;
height: 32px;
background-color: #f472b6;
color: #fff;
}
.main {
height: calc(100vh - 62px);
padding-top: 62px;
box-sizing: border-box;
}
.no-data {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
font-size: 20px;
}
.no-data i {
font-size: 64px;
margin-bottom: 16px;
color: #0095cf;
}
.no-data span {
color: #00354a;
}
</style>

View File

@@ -1,16 +1,40 @@
<script setup>
import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { Eleme } from '@element-plus/icons-vue'
const route = useRoute()
const router = useRouter()
const handleMenuClick = (path) => {
router.push(path)
}
const activeMenu = computed(() => {
const path = route.path
if (path === '/' || path === '/datascreen') return '/datascreen'
if (path.startsWith('/category')) return '/category'
if (path.startsWith('/datasource')) return '/datasource'
if (path.startsWith('/record')) return '/record'
if (path.startsWith('/components')) return '/components'
if (path.startsWith('/variables')) return '/variables'
if (path.startsWith('/files')) return '/files'
if (path.startsWith('/maps')) return '/maps'
if (path.startsWith('/tools')) return '/tools'
return ''
})
</script>
<template>
<div class="leftbar">
<button class="leftbar-item"><i class="fa-solid fa-table-cells-large"></i> 大屏管理</button>
<button class="leftbar-item"><i class="fa-solid fa-folder"></i> 大屏分类</button>
<button class="leftbar-item"><i class="fa-solid fa-database"></i> 数据源管理</button>
<button class="leftbar-item"><i class="fa-solid fa-suitcase"></i> 数据集管理</button>
<button class="leftbar-item"><el-icon style="font-size:20px;transform: translateY(4px);"><Eleme /></el-icon> 组件库</button>
<button class="leftbar-item"><i class="fa-solid fa-lightbulb"></i> 全局变量</button>
<button class="leftbar-item"><i class="fa-solid fa-layer-group"></i> 静态资源</button>
<button class="leftbar-item"><i class="fa-solid fa-location-dot"></i> 地图管理</button>
<button class="leftbar-item"><i class="fa-solid fa-boxes-stacked"></i> 工具箱</button>
<button class="leftbar-item" :class="{ 'activated': activeMenu === '/datascreen' }" @click="handleMenuClick('/datascreen')"><i class="fa-solid fa-table-cells-large"></i> 大屏管理</button>
<button class="leftbar-item" :class="{ 'activated': activeMenu === '/category' }" @click="handleMenuClick('/category')"><i class="fa-solid fa-folder"></i> 大屏分类</button>
<button class="leftbar-item" :class="{ 'activated': activeMenu === '/datasource' }" @click="handleMenuClick('/datasource')"><i class="fa-solid fa-database"></i> 数据源管理</button>
<button class="leftbar-item" :class="{ 'activated': activeMenu === '/record' }" @click="handleMenuClick('/record')"><i class="fa-solid fa-suitcase"></i> 数据集管理</button>
<button class="leftbar-item" :class="{ 'activated': activeMenu === '/components' }" @click="handleMenuClick('/components')"><el-icon style="font-size:20px;transform: translateY(4px);"><Eleme /></el-icon> 组件库</button>
<button class="leftbar-item" :class="{ 'activated': activeMenu === '/variables' }" @click="handleMenuClick('/variables')"><i class="fa-solid fa-lightbulb"></i> 全局变量</button>
<button class="leftbar-item" :class="{ 'activated': activeMenu === '/files' }" @click="handleMenuClick('/files')"><i class="fa-solid fa-layer-group"></i> 静态资源</button>
<button class="leftbar-item" :class="{ 'activated': activeMenu === '/maps' }" @click="handleMenuClick('/maps')"><i class="fa-solid fa-location-dot"></i> 地图管理</button>
<button class="leftbar-item" :class="{ 'activated': activeMenu === '/tools' }" @click="handleMenuClick('/tools')"><i class="fa-solid fa-boxes-stacked"></i> 工具箱</button>
</div>
</template>
<style>
@@ -21,13 +45,19 @@
border-radius: 16px;
width: 200px;
height: calc(100% - 48px);
background-color: rgba(255,255,255,0.2);
backdrop-filter: blur(3px);
background-color: rgba(255,255,255,0.15);
backdrop-filter: blur(10px) saturate(180%);
-webkit-backdrop-filter: blur(10px) saturate(180%);
border: 1px solid rgba(255,255,255,0.4);
box-shadow:
0 8px 32px rgba(0,0,0,0.2),
inset 0 4px 20px rgba(255,255,255,0.3);
display: flex;
flex-direction: column;
align-items: center;
padding-top: 8px;
box-sizing: border-box;
z-index: 2;
}
.leftbar-item {
width: 90%;
@@ -43,7 +73,8 @@
.leftbar-item:hover {
background-color: rgba(255,255,255,0.2);
}
.leftbar-item:active {
.leftbar-item:active,
.activated {
background-color: rgba(255,255,255,0.4);
}
</style>

View File

@@ -21,6 +21,7 @@ onMounted(() => {
height: 100vh;
width: 100vw;
background-color: #fff;
z-index: 9999;
}
.title {
position: fixed;

View File

@@ -0,0 +1,36 @@
<script setup>
import { defineAsyncComponent, computed } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const DynamicContent = computed(() => {
switch (route.path) {
case '/':
case '/datascreen':
return defineAsyncComponent(() => import('@/components/index/Datascreen.vue'))
}
})
</script>
<template>
<div class="container">
<component :is="DynamicContent" />
</div>
</template>
<style>
.container {
position: fixed;
top: 38px;
left: 216px;
border-radius: 16px;
width: calc(100vw - 224px);
height: calc(100vh - 48px);
background-color: rgba(255,255,255,0.15);
backdrop-filter: blur(10px) saturate(180%);
-webkit-backdrop-filter: blur(10px) saturate(180%);
border: 1px solid rgba(255,255,255,0.4);
box-shadow:
0 8px 32px rgba(0,0,0,0.2),
inset 0 4px 20px rgba(255,255,255,0.3);
z-index: 1;
}
</style>

View File

@@ -43,8 +43,10 @@ onUnmounted(() => {
left: 0;
width: 100%;
height: 32px;
background-color: rgba(255,255,255,0.2);
background-color: rgba(255,255,255,0.15);
backdrop-filter: blur(3px);
-webkit-backdrop-filter: blur(3px);
z-index: 2;
}
.logo {
position: fixed;

View File

@@ -32,15 +32,60 @@ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/' || '/index.html',
name: 'index',
component: () => import('./views/Index.vue'),
meta: { requiresIndexLoading: true },
path: '/',
name: 'Index',
component: () => import('./views/Loading.vue'),
meta: { requiresIndexLoading: true }
},
{
path: '/datascreen',
name: 'Datascreen',
component: () => import('./views/Index.vue')
},
{
path: '/category',
name: 'Category',
component: () => import('./views/Index.vue')
},
{
path: '/datasource',
name: 'Datasource',
component: () => import('./views/Index.vue')
},
{
path: '/record',
name: 'Record',
component: () => import('./views/Index.vue')
},
{
path: '/components',
name: 'Components',
component: () => import('./views/Index.vue')
},
{
path: '/variables',
name: 'Variables',
component: () => import('./views/Index.vue')
},
{
path: '/files',
name: 'Files',
component: () => import('./views/Index.vue')
},
{
path: '/maps',
name: 'Maps',
component: () => import('./views/Index.vue')
},
{
path: '/tools',
name: 'Tools',
component: () => import('./views/Index.vue')
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: () => import('./views/NotFound.vue'),
component: () => import('./views/NotFound.vue')
},
],
})
@@ -48,22 +93,19 @@ const router = createRouter({
router.beforeEach(async (to, from, next) => {
if (!to.meta.requiresIndexLoading) {
NProgress.start()
}
if (to.meta.requiresIndexLoading) {
} else {
NProgress.done()
NProgress.remove()
loadingNode = document.createElement('div');
loadingNode.id = 'custom-loading';
document.body.appendChild(loadingNode);
try {
const LoadingComponent = (await import('@/components/index/Loading.vue')).default;
loadingApp = createApp({
render: () => h(LoadingComponent)
});
loadingApp.mount(loadingNode);
} catch (error) {
console.error('Failed to load custom loading component:', error);
@@ -88,7 +130,7 @@ router.afterEach((to) => {
document.body.removeChild(loadingNode);
loadingNode = null;
}
}, 300);
}, 3000);
}
if (!to.meta.requiresIndexLoading && NProgress.isStarted()) {

View File

@@ -9,14 +9,27 @@ const config = getConfig()
const Topbar = defineAsyncComponent(() => import('@/components/index/Topbar.vue'))
const Leftbar = defineAsyncComponent(() => import('@/components/index/Leftbar.vue'))
const Main = defineAsyncComponent(() => import('@/components/index/Main.vue'))
onMounted(() => {
document.title = config.title
document.body.style.background = "url('"+config.backgroundImg+"') no-repeat center center fixed"
document.body.style.backgroundSize = "cover"
const linkElement = document.createElement('link');
linkElement.rel = 'stylesheet';
if (config.cdnUrl && config.cdnUrl !== "") {
linkElement.href = `${config.cdnUrl}/assets/font-awesome/css/all.min.css`;
} else {
linkElement.href = '@/assets/font-awesome/css/all.min.css';
}
document.head.appendChild(linkElement);
})
</script>
<template>
<Topbar />
<Leftbar />
<Main />
</template>

19
src/views/Loading.vue Normal file
View File

@@ -0,0 +1,19 @@
<script setup>
import { onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
let timer = null
onMounted(() => {
timer = setTimeout(() => {
router.push('/datascreen')
}, 3000)
})
onUnmounted(() => {
if (timer) {
clearTimeout(timer)
}
})
</script>

View File

@@ -54,8 +54,13 @@ onMounted(() => {
height: 80%;
border-radius: 20px;
backdrop-filter: blur(3px);
background-color: rgba(255, 255, 255, 0.2);
box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.2);
background-color: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(10px) saturate(180%);
-webkit-backdrop-filter: blur(10px) saturate(180%);
border: 1px solid rgba(255,255,255,0.4);
box-shadow:
0 8px 32px rgba(0,0,0,0.2),
inset 0 4px 20px rgba(255,255,255,0.3);
display: flex;
flex-direction: column;
justify-content: center;