165 lines
3.4 KiB
Vue
165 lines
3.4 KiB
Vue
<template>
|
||
<div class="dashboard-layout">
|
||
<!-- 顶部导航栏(通用布局) -->
|
||
<header class="layout-header">
|
||
<button
|
||
class="header-btn back-btn"
|
||
@click="handleBack"
|
||
aria-label="返回"
|
||
>
|
||
<el-icon><ArrowLeft /></el-icon>
|
||
<span>返回</span>
|
||
</button>
|
||
|
||
<h1 class="layout-title">{{ title }}</h1>
|
||
|
||
<div style="display: flex;align-items: center;gap: 10px;">
|
||
<button class="header-btn" aria-label="设置" @click="settingVisible = true">
|
||
<el-icon><Setting /></el-icon>
|
||
<span>设置</span>
|
||
</button>
|
||
<button
|
||
class="header-btn refresh-btn"
|
||
@click="handleRefresh"
|
||
aria-label="刷新"
|
||
:disabled="loading"
|
||
:class="{ refreshing: isRefreshing }"
|
||
>
|
||
<el-icon><Refresh /></el-icon>
|
||
<span>刷新</span>
|
||
</button>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- 内容插槽:用于插入图表网格 -->
|
||
<main class="layout-content" v-loading="loading">
|
||
<slot></slot>
|
||
</main>
|
||
|
||
<el-dialog v-model="settingVisible" title="图表设置" width="80%">
|
||
<ChartSetting />
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ArrowLeft, Refresh, Setting } from '@element-plus/icons-vue';
|
||
import ChartSetting from '../grid/setting.vue';
|
||
|
||
// 接收外部传入的状态与方法(props 类型约束)
|
||
const props = defineProps({
|
||
title: {
|
||
type: String,
|
||
required: true,
|
||
default: '数据可视化大屏'
|
||
},
|
||
loading: {
|
||
type: Boolean,
|
||
required: true,
|
||
default: false
|
||
},
|
||
isRefreshing: {
|
||
type: Boolean,
|
||
required: true,
|
||
default: false
|
||
},
|
||
handleBack: {
|
||
type: Function,
|
||
required: true
|
||
},
|
||
handleRefresh: {
|
||
type: Function,
|
||
required: true
|
||
}
|
||
});
|
||
|
||
const settingVisible = ref(false);
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 布局根容器样式 */
|
||
.dashboard-layout {
|
||
width: 100vw;
|
||
height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
background-color: #0f172a; /* 深色背景统一在布局层定义 */
|
||
}
|
||
|
||
/* 顶部导航样式 */
|
||
.layout-header {
|
||
height: 60px;
|
||
padding: 0 20px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
background: linear-gradient(120deg, #1e293b, #0f172a);
|
||
border-bottom: 1px solid #334155;
|
||
z-index: 10;
|
||
}
|
||
|
||
.layout-title {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
color: #f8fafc;
|
||
margin: 0;
|
||
}
|
||
|
||
.header-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 6px 12px;
|
||
background-color: #334155;
|
||
color: #f8fafc;
|
||
border: none;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.header-btn:hover {
|
||
background-color: #475569;
|
||
box-shadow: 0 0 8px rgba(255, 255, 255, 0.1);
|
||
}
|
||
|
||
.header-btn:disabled {
|
||
background-color: #2d3748;
|
||
cursor: not-allowed;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.header-btn i {
|
||
font-size: 16px;
|
||
}
|
||
|
||
/* 刷新按钮动画 */
|
||
.refreshing el-icon {
|
||
animation: spin 0.8s linear;
|
||
}
|
||
|
||
@keyframes spin {
|
||
from { transform: rotate(0deg); }
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
|
||
/* 内容区域容器(插槽父容器) */
|
||
.layout-content {
|
||
flex: 1;
|
||
overflow: hidden; /* 避免与子组件滚动冲突 */
|
||
}
|
||
|
||
/* 小屏幕适配(导航栏) */
|
||
@media (max-width: 768px) {
|
||
.layout-title {
|
||
font-size: 16px;
|
||
}
|
||
.header-btn span {
|
||
display: none; /* 隐藏按钮文字节省空间 */
|
||
}
|
||
.header-btn {
|
||
padding: 6px 8px;
|
||
}
|
||
}
|
||
</style> |