| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723 |
- <template>
- <div class="layout-wrapper" :class="{ 'full-screen': isFullScreen }" :style="isSpecialBg ? backgroundStyle : {}">
- <!-- 背景层 - 关键修改 -->
- <div v-if="isSpecialBg" class="background-layer"></div>
- <!-- Header 部分(透明背景) -->
- <el-header class="layout-header" v-if="!isFullScreen" :class="{ 'transparent-header': isSpecialBg }">
- <div class="logo-title-row">
- <img src="@/assets/logo.png" alt="Logo" class="logo" />
- <div class="title-and-user">
- <span class="project-name" :class="{ 'light-text': isSpecialBg }">
- 区域土壤重金属污染风险评估
- </span>
- <!-- 用户信息 - 在select-city页面隐藏 -->
- <div class="user-info-row" v-if="!isSelectCity">
- <span class="welcome-text" :class="{ 'light-text': isSpecialBg }">
- 欢迎{{
- tokenStore.token.loginType === "admin" ? "管理员" : "用户"
- }}登录成功
- </span>
- <el-dropdown>
- <span class="el-dropdown-link">
- <el-avatar :size="40" :class="{ 'light-avatar-border': isSpecialBg }"
- src="https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png" />
- </span>
- <template #dropdown>
- <el-dropdown-menu>
- <el-dropdown-item disabled>用户名:{{ userInfo.name }}</el-dropdown-item>
- <el-dropdown-item divided @click="handleLogout">退出登录</el-dropdown-item>
- </el-dropdown-menu>
- </template>
- </el-dropdown>
- </div>
- </div>
- </div>
- </el-header>
- <!-- Tab 区域(不加背景图) -->
- <div class="tabs-row" v-if="!isFullScreen">
- <el-tabs v-if="showTabs" v-model="activeName" class="demo-tabs" :style="tabStyle" @tab-click="handleClick">
- <el-tab-pane v-for="tab in tabs" :key="tab.name" :name="tab.name">
- <template #label>
- <i :class="['tab-icon', tab.icon]"></i>
- <span class="tab-label-text">{{ tab.label }}</span>
- </template>
- </el-tab-pane>
- </el-tabs>
- <div v-else class="single-tab" @click="handleClick(tabs[0], $event)">
- <i :class="['tab-icon', tabs[0].icon]"></i>
- <span class="tab-label-text">{{ tabs[0].label }}</span>
- </div>
- </div>
- <!-- 主体区域 -->
- <el-container class="layout-main-container">
- <!-- 侧边栏(不加背景图) -->
- <el-aside v-if="showAside && showTabs" class="layout-aside">
- <component :is="AsideComponent" :activeTab="activeName" :showTabs="showTabs" />
- </el-aside>
- <!-- 内容区域(透明背景) -->
- <el-main class="layout-content-wrapper" :style="mainStyle">
- <div class="scrollable-content" :class="{ 'transparent-scroll': isSpecialBg }">
- <div :class="{ 'select-city-container': isSelectCity }">
- <RouterView />
- </div>
- </div>
- </el-main>
- </el-container>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, reactive, computed, watch, defineAsyncComponent } from "vue";
- import { useRouter, useRoute } from "vue-router";
- import { useTokenStore } from "@/stores/mytoken";
- import { ElMessageBox, ElMessage } from "element-plus";
- import { logout } from "@/API/users";
- const router = useRouter();
- const route = useRoute();
- const tokenStore = useTokenStore();
- const currentBgImage = ref("");
- // 定义需要背景图的特殊路由和对应图片文件名
- const bgRouteMap: Record<string, string> = {
- // 添加灌溉水相关页面的背景图
- "/samplingMethodDevice1": "irrigation.jpg",
- "/irriSampleData": "irrigation.jpg",
- "/csSampleData": "irrigation.jpg",
- "/irriInputFlux": "irrigation.jpg",
- // 添加大农产品投入相关页面的背景图
- "/farmInputSamplingDesc": "agricultural_input.png",
- "/prodInputFlux": "agricultural_input.png",
- // 添加大气干湿沉降相关页面的背景图
- "/AtmosDepositionSamplingDesc": "atmospheric_deposition.png",
- "/heavyMetalEnterprise": "atmospheric_deposition.png",
- "/airSampleData": "atmospheric_deposition.png",
- "/airInputFlux": "atmospheric_deposition.png",
- //添加籽粒移除相关页面的背景图
- "/samplingDesc1": "rain_removal.png",
- "/grainRemovalInputFlux": "rain_removal.png",
- //添加秸秆移除相关页面的背景图
- "/samplingDesc2": "straw-removal.png",
- "/strawRemovalInputFlux": "straw-removal.png",
- //添加地下渗漏相关页面的背景图
- "/samplingDesc3": "subsurface-leakage.jpg",
- "/subsurfaceLeakageInputFlux": "subsurface-leakage.jpg",
- //添加地表径流相关页面的背景图
- "/samplingDesc4": "surface-runoff.jpg",
- "/surfaceRunoffInputFlux": "surface-runoff.jpg",
- "/totalInputFlux": "background.jpg",
- "/totalOutputFlux": "background.jpg",
- "/netFlux": "background.jpg",
- "/currentYearConcentration": "background.jpg",
- "/TotalCadmiumPrediction": "background.jpg",
- "/EffectiveCadmiumPrediction": "background.jpg",
- "/CropCadmiumPrediction": "background.jpg",
- "/cropRiskAssessment": "background.jpg",
- "/farmlandQualityAssessment": "background.jpg",
- "/Calculation": "background.jpg",
- "/SoilAcidReductionIterativeEvolution": "background.jpg",
- "/AcidNeutralizationModel": "background.jpg",
- "/SoilAcidificationIterativeEvolution": "background.jpg",
- "/TraditionalFarmingRisk": "background.jpg",
- "/HeavyMetalCadmiumControl": "background.jpg",
- "/SoilAcidificationControl": "background.jpg",
- "/DetectionStatistics": "background.jpg",
- "/FarmlandPollutionStatistics": "background.jpg",
- "/PlantingRiskStatistics": "background.jpg",
- };
- // 当前是否为特殊背景图页面
- const isSpecialBg = computed(() => Object.keys(bgRouteMap).includes(route.path));
- function getBgImageUrl(): string {
- const bgFile = bgRouteMap[route.path];
- console.log("根据路径查找背景文件名:", bgFile);
- if (bgFile) {
- try {
- const url = `url(${new URL(`../../assets/bg/background.jpg`, import.meta.url).href})`;
- return url;
- } catch (error) {
- console.error("加载背景图失败:", error);
- return "";
- }
- }
- return "";
- }
- // 监听路由变化更新背景图,并打印日志
- watch(
- () => route.path,
- (newPath) => {
- currentBgImage.value = getBgImageUrl();
- console.log(`[背景图更新] 当前路径: ${newPath}, 背景图: ${currentBgImage.value}`);
- },
- { immediate: true }
- );
- // 背景图样式 - 关键修改
- const backgroundStyle = computed(() => {
- return {
- backgroundImage: currentBgImage.value,
- backgroundSize: 'cover',
- backgroundPosition: 'center',
- backgroundRepeat: 'no-repeat',
- backgroundAttachment: 'fixed'
- };
- });
- // 是否为全屏页面
- const isFullScreen = computed(() => route.meta.fullScreen === true);
- // 判断是否是select-city页面
- const isSelectCity = computed(() => route.path === "/select-city");
- // Tab 配置
- const tabs = computed(() => {
- if (tokenStore.token.loginType === "admin") {
- return [
- {
- name: "dataManagement",
- label: "数据管理",
- icon: "el-icon-folder",
- routes: [
- "/soilAcidReductionData",
- "/soilAcidificationData",
- "/AdminRegionData",
- "/SoilAssessmentUnitData",
- "/SoilHeavyMetalData",
- "/CropHeavyMetalData",
- "/LandUseTypeData",
- "/ClimateInfoData",
- "/GeographicEnvInfoData",
- ],
- },
- {
- name: "infoManagement",
- label: "信息管理",
- icon: "el-icon-document",
- routes: ["/IntroductionUpdate"],
- },
- {
- name: "modelManagement",
- label: "模型管理及配置",
- icon: "el-icon-cpu",
- routes: [
- "/CadmiumPredictionModel",
- "/EffectiveCadmiumModel",
- "/Admin/RiceRiskModel",
- "/AdminModelSelection",
- "/Admin/thres",
- "/Admin/ModelTrain",
- "/Admin/WheatRiskModel",
- "/Admin/VegetableRiskModel",
- ],
- },
- {
- name: "userManagement",
- label: "用户管理",
- icon: "el-icon-user",
- routes: ["/UserManagement", "/UserRegistration"],
- },
- ];
- } else {
- return [
- {
- name: "shuJuKanBan",
- label: "数据看板",
- icon: "el-icon-data-analysis",
- routes: ["/shuJuKanBan"],
- },
- {
- name: "introduction",
- label: "软件简介",
- icon: "el-icon-info-filled",
- routes: ["/SoilPro", "/Overview", "/ResearchFindings", "/Unit"],
- },
- {
- name: "HmOutFlux",
- label: "重金属输入通量",
- icon: "el-icon-refresh",
- routes: [
- "/samplingMethodDevice1",
- "/irriSampleData",
- "/csSampleData",
- "/irriInputFlux",
- "/farmInputSamplingDesc",
- "/prodInputFlux",
- "/AtmosDepositionSamplingDesc",
- "/heavyMetalEnterprise",
- "/airSampleData",
- "/airInputFlux",
- ],
- },
- {
- name: "hmInFlux",
- label: "重金属输出通量",
- icon: "el-icon-refresh",
- routes: [
- "/samplingDesc1",
- "/grainRemovalInputFlux",
- "/samplingDesc2",
- "/strawRemovalInputFlux",
- "/samplingDesc3",
- "/subsurfaceLeakageInputFlux",
- "/samplingDesc4",
- "/surfaceRunoffInputFlux",
- ],
- },
- {
- name: "mapView",
- label: "地图展示",
- icon: "el-icon-map-location",
- routes: ["/mapView"],
- },
- {
- name: "cadmiumPrediction",
- label: "土壤污染物含量预测",
- icon: "el-icon-c-scale-to-original",
- routes: [
- "/totalInputFlux",
- "/TotalCadmiumPrediction",
- "/totalOutputFlux",
- "/netFlux",
- "/currentYearConcentration",
- "/EffectiveCadmiumPrediction",
- "CropCadmiumPrediction",
- ],
- },
- {
- name: "cropRiskAssessment",
- label: "作物风险评估",
- icon: "el-icon-warning",
- routes: ["/cropRiskAssessment"],
- },
- {
- name: "farmlandQualityAssessment",
- label: "耕地质量评估",
- icon: "el-icon-rank",
- routes: ["/farmlandQualityAssessment"],
- },
- {
- name: "soilAcidificationPrediction",
- label: "土壤酸化预测",
- icon: "el-icon-magic-stick",
- routes: ["/Calculation", "/AcidNeutralizationModel"],
- },
- {
- name: "scenarioSimulation",
- label: "情景模拟",
- icon: "el-icon-s-operation",
- routes: [
- "/TraditionalFarmingRisk",
- "/HeavyMetalCadmiumControl",
- "/SoilAcidificationControl",
- ],
- },
- {
- name: "dataStatistics",
- label: "数据统计",
- icon: "el-icon-pie-chart",
- routes: [
- "/DetectionStatistics",
- "/FarmlandPollutionStatistics",
- "/PlantingRiskStatistics",
- ],
- },
- ].filter(tab => !["shuJuKanBan", "mapView", "introduction"].includes(tab.name));
- }
- });
- // 当前激活 tab
- const activeName = ref(tabs.value[0]?.name || "");
- const showTabs = computed(() => tabs.value.length > 1);
- const tabStyle = computed(() =>
- tabs.value.length === 1 ? { width: "100%", justifyContent: "center" } : {}
- );
- let hasNavigated = false;
- watch(
- () => activeName.value,
- (newTab) => {
- const tab = tabs.value.find((t) => t.name === newTab);
- const targetPath = tab?.routes?.[0];
- if (!hasNavigated) {
- hasNavigated = true;
- return;
- }
- if (tab && targetPath && router.currentRoute.value.path !== targetPath) {
- router.push({ path: targetPath });
- }
- },
- { immediate: true }
- );
- // 点击切换 tab
- const handleClick = (tab: any, event: Event) => {
- activeAsideTab.value = tab.props.name;
- };
- // 动态加载侧边栏组件
- const AsideComponent = computed(() => {
- if (
- ["parameterConfig", "dataManagement", "infoManagement", "modelManagement", "userManagement"]
- .includes(activeName.value)
- ) {
- return defineAsyncComponent(() => import("./AppAsideForTab2.vue"));
- } else {
- return defineAsyncComponent(() => import("./AppAside.vue"));
- }
- });
- // 是否显示侧边栏
- const showAside = computed(() => {
- return (
- !isFullScreen.value &&
- activeName.value !== "mapView" &&
- activeName.value !== "cropRiskAssessment" &&
- activeName.value !== "farmlandQualityAssessment"
- );
- });
- const activeAsideTab = ref(activeName.value || "");
- const userInfo = reactive({ name: tokenStore.token.name || "未登录" });
- const handleLogout = async () => {
- try {
- await ElMessageBox.confirm("确定要退出登录吗?", "提示", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- type: "warning",
- });
- await logout();
- tokenStore.clearToken();
- ElMessage.success("退出成功");
- router.push("/login");
- } catch {
- ElMessage.info("已取消退出");
- }
- };
- // 内容区样式
- const mainStyle = computed(() => {
- return {
- padding: ["mapView", "infoManagement"].includes(activeName.value) ? "0" : "20px",
- overflow: "hidden",
- };
- });
- </script>
- <style>
- /* 隐藏所有滚动条 */
- *::-webkit-scrollbar {
- display: none;
- /* Chrome, Safari, Opera */
- }
- * {
- -ms-overflow-style: none;
- /* IE and Edge */
- scrollbar-width: none;
- /* Firefox */
- }
- /* 整体布局容器 */
- .layout-wrapper {
- display: flex;
- flex-direction: column;
- height: 100vh;
- overflow: hidden;
- position: relative;
- background-color: #f5f7fa;
- /* 默认背景色 */
- }
- /* 背景层 - 关键修改 */
- .background-layer {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 0;
- background-size: cover;
- background-position: center;
- background-repeat: no-repeat;
- filter: brightness(0.8);
- }
- /* 全屏页面特殊处理 */
- .layout-wrapper.full-screen {
- background: none;
- min-height: 100vh;
- }
- /* 特殊背景页面的Header样式 */
- .transparent-header {
- background: transparent !important;
- backdrop-filter: blur(2px);
- /* 添加轻微模糊效果增强可读性 */
- }
- /* 特殊背景页面的文字颜色 */
- .light-text {
- color: #ffffff !important;
- /* 白色文字 */
- text-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
- /* 文字阴影增强可读性 */
- }
- /* 特殊背景页面的头像边框 */
- .light-avatar-border {
- border: 2px solid #ffffff !important;
- /* 白色边框 */
- }
- /* 内容区域在特殊背景页面透明 */
- .transparent-scroll {
- background-color: transparent !important;
- }
- /* Header 样式 */
- .layout-header {
- height: 150px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- color: #333;
- /* 深色文字 */
- flex-shrink: 0;
- position: relative;
- z-index: 2;
- /* 确保在背景层上方 */
- background-color: white;
- /* 默认背景色 */
- }
- .logo-title-row {
- display: flex;
- align-items: center;
- gap: 24px;
- width: 100%;
- }
- .title-and-user {
- display: flex;
- flex-direction: column;
- flex: 1;
- }
- /* 用户信息区域 */
- .user-info-row {
- display: flex;
- align-items: center;
- justify-content: flex-end;
- gap: 24px;
- color: #333;
- /* 深色文字 */
- padding-top: 1px;
- position: static;
- z-index: 1;
- }
- .welcome-text {
- font-size: 28px;
- font-weight: 500;
- color: #333 !important;
- /* 深色文字 */
- }
- /* Tab 区域 - 不透明 */
- .tabs-row {
- height: 48px;
- display: flex;
- justify-content: center;
- align-items: center;
- padding: 0 24px;
- background: linear-gradient(to right, #1092d8, #02c3ad);
- border-bottom: none !important;
- flex-shrink: 0;
- position: relative;
- z-index: 2;
- /* 确保在背景层上方 */
- }
- /* el-tabs 外层容器 */
- .demo-tabs {
- height: 48px !important;
- display: flex;
- align-items: center;
- width: 100%;
- padding: 0 !important;
- margin: 0 !important;
- border-bottom: none !important;
- }
- /* 清除滑块条和底部线条 */
- .el-tabs__nav-wrap::after,
- .el-tabs__active-bar {
- display: none !important;
- height: 0 !important;
- border: none !important;
- }
- .el-tabs__nav-scroll {
- padding: 0 !important;
- margin: 0 !important;
- }
- /* Tabs 单项样式 */
- .el-tabs__item {
- height: 48px !important;
- line-height: 48px !important;
- display: flex !important;
- align-items: center;
- justify-content: center;
- padding: 0 20px !important;
- font-size: 20px;
- font-weight: 600;
- border-radius: 10px;
- transition: all 0.2s ease-in-out;
- background-color: transparent;
- position: relative;
- z-index: 1;
- }
- /* 激活 Tab */
- .el-tabs__item.is-active {
- background-color: #2a53ba;
- color: #ffffff;
- font-weight: 700;
- box-shadow: 0 4px 16px rgba(26, 188, 156, 0.4);
- z-index: 2;
- }
- /* 鼠标悬停 */
- .el-tabs__item:hover {
- background-color: #455a64;
- color: #ffffff;
- }
- /* 图标样式 */
- .tab-icon {
- font-size: 24px;
- margin-right: 4px;
- color: inherit;
- }
- /* 文字样式 */
- .tab-label-text {
- font-size: 20px;
- color: inherit;
- line-height: 1;
- display: inline-block;
- }
- .logo {
- height: 60px;
- }
- .project-name {
- font-size: 48px;
- font-weight: bold;
- margin-top: 30px;
- color: #333;
- /* 深色文字 */
- }
- .layout-main-container {
- flex: 1;
- display: flex;
- overflow: hidden;
- min-height: 0;
- position: relative;
- z-index: 1;
- /* 确保在背景层上方 */
- }
- /* 侧边栏 - 白色背景 */
- .layout-aside {
- width: 360px;
- background: linear-gradient(to bottom, #B7F1FC, #FFF8F0);
- border-right: 1px solid;
- overflow-y: auto;
- color: #000000;
- padding-top: 8px;
- height: 100%;
- position: relative;
- z-index: 2;
- /* 确保在背景层上方 */
- }
- /* 隐藏侧边栏滚动条 */
- .layout-aside::-webkit-scrollbar {
- display: none;
- }
- .layout-aside .el-menu-item,
- .layout-aside .el-sub-menu__title {
- font-size: 18px;
- font-weight: 500;
- color: #000000;
- background-color: transparent;
- transition: all 0.2s ease;
- border-radius: 6px;
- padding: 12px 16px !important;
- }
- .layout-aside .el-menu-item:hover,
- .layout-aside .el-sub-menu__title:hover {
- background-color: rgba(16, 146, 216, 0.1);
- color: #1092d8;
- }
- .layout-aside .el-menu-item.is-active,
- .layout-aside .el-sub-menu__title.is-active {
- background: linear-gradient(to right, #1092d8, #02c3ad);
- color: #000000 !important;
- border-radius: 8px;
- font-weight: 600;
- box-shadow: 0 2px 8px rgba(16, 146, 216, 0.25);
- }
- .layout-content-wrapper {
- flex: 1;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- position: relative;
- }
- /* 强制重置 el-tabs header 高度/边距/背景/阴影,避免背景层穿透错位 */
- .el-tabs__header.is-top {
- height: 48px !important;
- margin: 0 !important;
- padding: 0 !important;
- border: none !important;
- background: transparent !important;
- box-shadow: none !important;
- z-index: 0 !important;
- }
- /* 全屏页面特殊处理 */
- .layout-wrapper.full-screen .layout-main-container {
- height: 100vh;
- }
- .scrollable-content {
- flex: 1;
- overflow: auto;
- padding: 0 20px;
- box-sizing: border-box;
- background-color: white;
- /* 默认背景色 */
- }
- .scrollable-content.transparent-scroll {
- background-color: transparent;
- }
- </style>
|