zhangwencui
5 小时以前 8fc95d9a67cdfdf8a8e56ffa278660e20d232fa6
基础数据分析修改
已修改2个文件
437 ■■■■ 文件已修改
src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue 282 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/dataDashboard/index.vue 155 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
@@ -1,8 +1,8 @@
<template>
  <div>
  <div class="center-top-container">
    <!-- 顶部统计卡片 -->
    <div class="stats-cards">
      <div class="stat-card">
      <!-- <div class="stat-card">
        <img src="@/assets/BI/icon@2x.png" alt="图标" class="card-icon" />
        <div class="card-content">
          <span class="card-label">员工总数</span>
@@ -13,13 +13,16 @@
            <span class="compare-icon">{{ staffYoY >= 0 ? '↑' : '↓' }}</span>
          </div>
        </div>
      </div>
      </div> -->
      <div class="stat-card">
        <img src="@/assets/BI/icon@2x.png" alt="图标" class="card-icon" />
        <img src="@/assets/BI/icon@2x.png"
             alt="图标"
             class="card-icon" />
        <div class="card-content">
          <span class="card-label">客户总数</span>
          <span class="card-value">{{ totalCustomers }}</span>
          <div class="card-compare" :class="compareClass(customersYoY)">
          <div class="card-compare"
               :class="compareClass(customersYoY)">
            <span>同比</span>
            <span class="compare-value">{{ formatPercent(customersYoY) }}</span>
            <span class="compare-icon">{{ customersYoY >= 0 ? '↑' : '↓' }}</span>
@@ -27,11 +30,14 @@
        </div>
      </div>
      <div class="stat-card">
        <img src="@/assets/BI/icon@2x.png" alt="图标" class="card-icon" />
        <img src="@/assets/BI/icon@2x.png"
             alt="图标"
             class="card-icon" />
        <div class="card-content">
          <span class="card-label">供应商总数</span>
          <span class="card-value">{{ totalSuppliers }}</span>
          <div class="card-compare" :class="compareClass(suppliersYoY)">
          <div class="card-compare"
               :class="compareClass(suppliersYoY)">
            <span>同比</span>
            <span class="compare-value">{{ formatPercent(suppliersYoY) }}</span>
            <span class="compare-icon">{{ suppliersYoY >= 0 ? '↑' : '↓' }}</span>
@@ -39,15 +45,12 @@
        </div>
      </div>
    </div>
    <!-- 设备统计 -->
    <div class="equipment-stats">
      <div class="equipment-header">
        <img
          src="@/assets/BI/shujutongjiicon@2x.png"
        <img src="@/assets/BI/shujutongjiicon@2x.png"
          alt="图标"
          class="equipment-icon"
        />
             class="equipment-icon" />
        <span class="equipment-title">设备统计</span>
      </div>
      <div class="equipment-items">
@@ -69,238 +72,242 @@
        </div>
      </div>
    </div>
    <!-- 事件名称 -->
    <div class="event-info">
      <div class="event-header">
        <img
          src="@/assets/BI/shijianmingxiicon@2x.png"
        <img src="@/assets/BI/shijianmingxiicon@2x.png"
          alt="图标"
          class="event-icon"
        />
             class="event-icon" />
        <span class="event-title">事件名称</span>
      </div>
      <div class="event-content">
        <ul class="todo-list" v-if="todoList.length > 0" ref="refTodoList">
          <li v-for="item in todoList" :key="item.id">
            <div
              style="
        <ul class="todo-list"
            v-if="todoList.length > 0"
            ref="refTodoList">
          <li v-for="item in todoList"
              :key="item.id">
            <div style="
                display: flex;
                flex-direction: column;
                justify-content: space-between;
                width: 100%;
                gap: 20px;
              "
            >
              ">
            <div class="todo-division">待办事由:{{ item.approveReason }}</div>
              <div style="display: flex;justify-content: space-between;align-items: center;"
              >
              <div style="display: flex;justify-content: space-between;align-items: center;">
                <div class="todo-title">申请类型:{{ item.approveTypeName }}</div>
                <div class="todo-division">申请部门:{{ item.approveDeptName }}</div>
                <div class="todo-time">{{ item.approveTime }}</div>
              </div>
            </div>
          </li>
        </ul>
        <div v-else style="text-align: center">暂无数据</div>
        <div v-else
             style="text-align: center;color:#fff">暂无数据</div>
      </div>
    </div>
  </div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { homeTodos, summaryStatistics } from '@/api/viewIndex.js'
import { getLedgerPage } from '@/api/equipmentManagement/ledger.js'
import { getRepairPage } from '@/api/equipmentManagement/repair.js'
import { getUpkeepPage } from '@/api/equipmentManagement/upkeep.js'
import { measuringInstrumentListPage } from '@/api/equipmentManagement/measurementEquipment.js'
  import { ref, onMounted, onBeforeUnmount, nextTick } from "vue";
  import { homeTodos, summaryStatistics } from "@/api/viewIndex.js";
  import { getLedgerPage } from "@/api/equipmentManagement/ledger.js";
  import { getRepairPage } from "@/api/equipmentManagement/repair.js";
  import { getUpkeepPage } from "@/api/equipmentManagement/upkeep.js";
  import { measuringInstrumentListPage } from "@/api/equipmentManagement/measurementEquipment.js";
// 统计数据
const totalStaff = ref(0)
const totalCustomers = ref(0)
const totalSuppliers = ref(0)
  const totalStaff = ref(0);
  const totalCustomers = ref(0);
  const totalSuppliers = ref(0);
// 同比
const staffYoY = ref(0)
const customersYoY = ref(0)
const suppliersYoY = ref(0)
const equipmentNum = ref(0)
const equipmentRepair = ref(0)
const equipmentMaintain = ref(0)
const totalMeasuring = ref(0)
  const staffYoY = ref(0);
  const customersYoY = ref(0);
  const suppliersYoY = ref(0);
  const equipmentNum = ref(0);
  const equipmentRepair = ref(0);
  const equipmentMaintain = ref(0);
  const totalMeasuring = ref(0);
// 待办事项
const todoList = ref([])
const refTodoList = ref(null)
  const todoList = ref([]);
  const refTodoList = ref(null);
const formatPercent = (val) => {
  const num = Number(val) || 0
  return `${Math.abs(num).toFixed(2)}%`
}
  const formatPercent = val => {
    const num = Number(val) || 0;
    return `${Math.abs(num).toFixed(2)}%`;
  };
const compareClass = (val) => (val >= 0 ? 'compare-up' : 'compare-down')
  const compareClass = val => (val >= 0 ? "compare-up" : "compare-down");
// 获取员工、客户、供应商数量
const getNum = () => {
  summaryStatistics().then((res) => {
    totalStaff.value = res.data.totalStaff
    staffYoY.value = res.data.staffGrowthRate
    totalCustomers.value = res.data.totalCustomer
    customersYoY.value = res.data.customerGrowthRate
    totalSuppliers.value = res.data.totalSupplier
    suppliersYoY.value = res.data.supplierGrowthRate
  }).catch(err => {
    console.error('获取基础统计数据失败:', err)
    summaryStatistics()
      .then(res => {
        totalStaff.value = res.data.totalStaff;
        staffYoY.value = res.data.staffGrowthRate;
        totalCustomers.value = res.data.totalCustomer;
        customersYoY.value = res.data.customerGrowthRate;
        totalSuppliers.value = res.data.totalSupplier;
        suppliersYoY.value = res.data.supplierGrowthRate;
  })
}
      .catch(err => {
        console.error("获取基础统计数据失败:", err);
      });
  };
// 获取设备相关数量
const getLedgerNum = () => {
  const params = {
    pageNum: -1,
    pageSize: -1,
  }
  getLedgerPage(params).then((res) => {
    equipmentNum.value = res.data.total
  })
  getRepairPage({ ...params, status: 0 }).then((res) => {
    equipmentRepair.value = res.data.total
  })
  getUpkeepPage({ ...params, status: 0 }).then((res) => {
    equipmentMaintain.value = res.data.total
  })
  measuringInstrumentListPage(params).then((res) => {
    totalMeasuring.value = res.data.total
  })
}
    };
    getLedgerPage(params).then(res => {
      equipmentNum.value = res.data.total;
    });
    getRepairPage({ ...params, status: 0 }).then(res => {
      equipmentRepair.value = res.data.total;
    });
    getUpkeepPage({ ...params, status: 0 }).then(res => {
      equipmentMaintain.value = res.data.total;
    });
    measuringInstrumentListPage(params).then(res => {
      totalMeasuring.value = res.data.total;
    });
  };
// 初始化待办事项列表滚动功能
const initTodoListScroll = () => {
  const todoListEl = refTodoList.value
    const todoListEl = refTodoList.value;
  // 强制启用滚动,不检查任何条件
  if (todoListEl) {
    // 创建一个克隆项,用于实现无缝滚动
    const scrollItems = Array.from(todoListEl.querySelectorAll('li'))
      const scrollItems = Array.from(todoListEl.querySelectorAll("li"));
    if (scrollItems.length > 0) {
      // 确保有足够的项目用于滚动
      // 如果项目太少,多复制几次以确保滚动效果
      if (scrollItems.length < 4) {
        const originalItems = [...scrollItems]
          const originalItems = [...scrollItems];
        for (let i = 0; i < 4; i++) {
          originalItems.forEach((item) => {
            const clone = item.cloneNode(true)
            todoListEl.appendChild(clone)
          })
            originalItems.forEach(item => {
              const clone = item.cloneNode(true);
              todoListEl.appendChild(clone);
            });
        }
        // 重新获取所有项目
        scrollItems.push(
          ...Array.from(todoListEl.querySelectorAll('li')).slice(
            ...Array.from(todoListEl.querySelectorAll("li")).slice(
            scrollItems.length
          )
        )
          );
      }
      const itemHeight = scrollItems[0]?.offsetHeight || 0
      const containerHeight = todoListEl.clientHeight
      const cloneCount = Math.ceil(containerHeight / itemHeight) + 2
        const itemHeight = scrollItems[0]?.offsetHeight || 0;
        const containerHeight = todoListEl.clientHeight;
        const cloneCount = Math.ceil(containerHeight / itemHeight) + 2;
      // 克隆前几个项目并添加到列表末尾,实现无缝滚动
      for (let i = 0; i < cloneCount; i++) {
        const clone = scrollItems[i % scrollItems.length].cloneNode(true)
        todoListEl.appendChild(clone)
          const clone = scrollItems[i % scrollItems.length].cloneNode(true);
          todoListEl.appendChild(clone);
      }
      let scrollPosition = 0
      const scrollSpeed = 1.5 // 增加滚动速度,使滚动更加明显
      const pauseTime = 3000 // 滚动暂停时间
      let isPaused = false
      let lastTimestamp = 0
        let scrollPosition = 0;
        const scrollSpeed = 1.5; // 增加滚动速度,使滚动更加明显
        const pauseTime = 3000; // 滚动暂停时间
        let isPaused = false;
        let lastTimestamp = 0;
      // 连续滚动动画函数
      function scrollAnimation(timestamp) {
        if (!lastTimestamp) lastTimestamp = timestamp
        const deltaTime = timestamp - lastTimestamp
        lastTimestamp = timestamp
          if (!lastTimestamp) lastTimestamp = timestamp;
          const deltaTime = timestamp - lastTimestamp;
          lastTimestamp = timestamp;
        if (!isPaused) {
          scrollPosition += scrollSpeed * (deltaTime / 16) // 标准化为60fps的速度
            scrollPosition += scrollSpeed * (deltaTime / 16); // 标准化为60fps的速度
          // 当滚动超过原始内容长度时,重置位置实现无缝滚动
          const maxScroll = Math.max(
            todoListEl.scrollHeight -
              containerHeight -
              cloneCount * itemHeight,
              todoListEl.scrollHeight - containerHeight - cloneCount * itemHeight,
            itemHeight * scrollItems.length
          )
            );
          if (scrollPosition >= maxScroll) {
            scrollPosition = 0
            todoListEl.scrollTop = 0
              scrollPosition = 0;
              todoListEl.scrollTop = 0;
          } else {
            todoListEl.scrollTop = scrollPosition
              todoListEl.scrollTop = scrollPosition;
          }
        }
        todoListEl._animationFrame = requestAnimationFrame(scrollAnimation)
          todoListEl._animationFrame = requestAnimationFrame(scrollAnimation);
      }
      // 启动滚动动画
      todoListEl._animationFrame = requestAnimationFrame(scrollAnimation)
        todoListEl._animationFrame = requestAnimationFrame(scrollAnimation);
      // 设置滚动-暂停-滚动的循环效果
      const pauseTimer = setInterval(() => {
        isPaused = !isPaused
      }, pauseTime)
          isPaused = !isPaused;
        }, pauseTime);
      // 清理定时器
      todoListEl._pauseTimer = pauseTimer
        todoListEl._pauseTimer = pauseTimer;
    }
  }
}
  };
// 待办事项
const todoInfoS = () => {
  homeTodos().then((res) => {
    todoList.value = res.data
    homeTodos().then(res => {
      todoList.value = res.data;
    // 在获取到待办事项数据后,初始化滚动功能
    nextTick(() => {
      initTodoListScroll()
    })
  })
}
        initTodoListScroll();
      });
    });
  };
onMounted(() => {
  getNum()
  getLedgerNum()
  todoInfoS()
})
    getNum();
    getLedgerNum();
    todoInfoS();
  });
onBeforeUnmount(() => {
  // 清理待办事项列表的动画和定时器
  const todoListEl = refTodoList.value
    const todoListEl = refTodoList.value;
  if (todoListEl) {
    if (todoListEl._animationFrame) {
      cancelAnimationFrame(todoListEl._animationFrame)
      todoListEl._animationFrame = null
        cancelAnimationFrame(todoListEl._animationFrame);
        todoListEl._animationFrame = null;
    }
    if (todoListEl._pauseTimer) {
      clearInterval(todoListEl._pauseTimer)
      todoListEl._pauseTimer = null
        clearInterval(todoListEl._pauseTimer);
        todoListEl._pauseTimer = null;
    }
  }
})
  });
</script>
<style scoped>
  .center-top-container {
    display: flex;
    flex-direction: column;
    height: 100%;
  }
.stats-cards {
  display: flex;
  gap: 30px;
    flex-shrink: 0;
}
.stat-card {
  flex: 1;
  display: flex;
  align-items: center;
  background-image: url('@/assets/BI/border@2x.png');
    background-image: url("@/assets/BI/border@2x.png");
  background-size: 100% 100%;
  background-position: center;
  background-repeat: no-repeat;
@@ -370,8 +377,8 @@
.equipment-stats {
  border: 1px solid #1a58b0;
  padding: 18px;
  height: 240px;
  padding-top: 0px;
    flex-shrink: 0;
}
.equipment-header {
@@ -423,7 +430,7 @@
  width: 120px;
  height: 110px;
  line-height: 110px;
  background-image: url('@/assets/BI/shujutongji@2x.png');
    background-image: url("@/assets/BI/shujutongji@2x.png");
  background-size: 100% 100%;
  background-position: center;
  background-repeat: no-repeat;
@@ -437,18 +444,22 @@
}
.event-info {
  background-image: url('@/assets/BI/shijianmingchengbeijing@2x.png');
    background-image: url("@/assets/BI/shijianmingchengbeijing@2x.png");
  background-size: 100% 100%;
  background-position: center;
  background-repeat: no-repeat;
  padding: 20px;
  padding-top: 10px;
  height: 186px;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
.event-header {
  display: flex;
  align-items: center;
    height: 80px;
}
.event-icon {
@@ -462,12 +473,15 @@
  color: #fffffe;
  line-height: 30px;
}
  .event-content {
    flex: 1;
  }
.todo-list {
  list-style: none;
  padding: 0;
  margin: 0;
  height: 120px; /* 按用户要求调整高度 */
    height: 100%; /* 按用户要求调整高度 */
  overflow: hidden;
  font-size: 15px;
}
@@ -489,8 +503,6 @@
  position: relative;
}
.todo-division {
  font-weight: 400;
  font-size: 16px;
@@ -499,7 +511,7 @@
}
.todo-division::before {
  content: '';
    content: "";
  position: absolute;
  left: -20px;
  top: 50%;
src/views/reportAnalysis/dataDashboard/index.vue
@@ -1,41 +1,49 @@
<template>
  <div class="scale-container">
    <div class="data-dashboard" :style="{ transform: `scale(${scaleRatio})` }">
    <div class="data-dashboard"
         :style="{ transform: `scale(${scaleRatio})` }">
    <!-- 全屏按钮 - 移动到左上角 -->
    <button class="fullscreen-btn" @click="toggleFullscreen" :title="isFullscreen ? '退出全屏' : '全屏显示'">
      <svg v-if="!isFullscreen" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
      <button class="fullscreen-btn"
              @click="toggleFullscreen"
              :title="isFullscreen ? '退出全屏' : '全屏显示'">
        <svg v-if="!isFullscreen"
             width="20"
             height="20"
             viewBox="0 0 24 24"
             fill="none"
             stroke="currentColor"
             stroke-width="2">
        <path d="M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3"/>
      </svg>
      <svg v-else width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
        <svg v-else
             width="20"
             height="20"
             viewBox="0 0 24 24"
             fill="none"
             stroke="currentColor"
             stroke-width="2">
        <path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/>
      </svg>
    </button>
    <!-- 顶部标题栏 -->
    <div class="dashboard-header">
      <div class="factory-name">基础数据</div>
    </div>
    <!-- 主要内容区域 -->
    <div class="dashboard-content">
    <!-- 左侧区域 -->
    <div class="left-panel">
      <LeftTop />
      <LeftBottom />
    </div>
    <!-- 中间区域 -->
    <div class="center-panel">
      <CenterTop />
      <CenterBottom />
          <!-- <CenterBottom /> -->
    </div>
    <!-- 右侧区域 -->
    <div class="right-panel">
      <RightTop />
       <RightBottom />
    </div>
    </div>
@@ -44,117 +52,122 @@
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
import autofit from 'autofit.js'
import LeftTop from './components/basic/left-top.vue'
import LeftBottom from './components/basic/left-bottom.vue'
import CenterTop from './components/basic/center-top.vue'
import CenterBottom from './components/basic/center-bottom.vue'
import RightTop from './components/basic/right-top.vue'
import RightBottom from './components/basic/right-bottom.vue'
import useUserStore from '@/store/modules/user'
  import { ref, onMounted, onBeforeUnmount, nextTick } from "vue";
  import autofit from "autofit.js";
  import LeftTop from "./components/basic/left-top.vue";
  import LeftBottom from "./components/basic/left-bottom.vue";
  import CenterTop from "./components/basic/center-top.vue";
  import CenterBottom from "./components/basic/center-bottom.vue";
  import RightTop from "./components/basic/right-top.vue";
  import RightBottom from "./components/basic/right-bottom.vue";
  import useUserStore from "@/store/modules/user";
// 全屏相关状态
const isFullscreen = ref(false);
// 缩放比例
const scaleRatio = ref(1)
  const scaleRatio = ref(1);
// 设计尺寸(基准尺寸)- 根据实际设计稿调整
const designWidth = 1920
const designHeight = 1080
  const designWidth = 1920;
  const designHeight = 1080;
// 用户store
const userStore = useUserStore()
  const userStore = useUserStore();
// 计算缩放比例
const calculateScale = () => {
  const container = document.querySelector('.scale-container')
  if (!container) return
    const container = document.querySelector(".scale-container");
    if (!container) return;
  // 获取容器的实际尺寸
  const rect = container.getBoundingClientRect?.()
  const containerWidth = container.clientWidth || rect?.width || window.innerWidth
  const containerHeight = container.clientHeight || rect?.height || window.innerHeight
    const rect = container.getBoundingClientRect?.();
    const containerWidth =
      container.clientWidth || rect?.width || window.innerWidth;
    const containerHeight =
      container.clientHeight || rect?.height || window.innerHeight;
  // 计算宽高缩放比例,取较小值以保证内容完整显示(等比缩放)
  const scaleX = containerWidth / designWidth
  const scaleY = containerHeight / designHeight
  scaleRatio.value = Math.min(scaleX, scaleY)
}
    const scaleX = containerWidth / designWidth;
    const scaleY = containerHeight / designHeight;
    scaleRatio.value = Math.min(scaleX, scaleY);
  };
// 窗口大小变化处理
const handleResize = () => {
  // 延迟执行,确保DOM更新完成
  setTimeout(() => {
    calculateScale()
  }, 100)
}
      calculateScale();
    }, 100);
  };
// 全屏功能实现 - 针对scale-container元素
const toggleFullscreen = () => {
  const element = document.querySelector('.scale-container')
    const element = document.querySelector(".scale-container");
  if (!element) return
    if (!element) return;
  if (!isFullscreen.value) {
    if (element.requestFullscreen) {
      element.requestFullscreen()
        element.requestFullscreen();
    } else if (element.webkitRequestFullscreen) {
      element.webkitRequestFullscreen()
        element.webkitRequestFullscreen();
    } else if (element.msRequestFullscreen) {
      element.msRequestFullscreen()
        element.msRequestFullscreen();
    }
  } else {
    if (document.exitFullscreen) {
      document.exitFullscreen()
        document.exitFullscreen();
    } else if (document.webkitExitFullscreen) {
      document.webkitExitFullscreen()
        document.webkitExitFullscreen();
    } else if (document.msExitFullscreen) {
      document.msExitFullscreen()
        document.msExitFullscreen();
    }
  }
}
  };
// 监听全屏变化事件
const handleFullscreenChange = () => {
  const fullscreenElement = document.fullscreenElement ||
    const fullscreenElement =
      document.fullscreenElement ||
                           document.webkitFullscreenElement || 
                           document.msFullscreenElement
  isFullscreen.value = fullscreenElement && fullscreenElement.classList.contains('scale-container')
      document.msFullscreenElement;
    isFullscreen.value =
      fullscreenElement &&
      fullscreenElement.classList.contains("scale-container");
  // 全屏状态变化时,延迟重新计算缩放比例(确保DOM更新完成)
  setTimeout(() => {
    calculateScale()
  }, 200)
}
      calculateScale();
    }, 200);
  };
// 生命周期钩子
onMounted(() => {
  // 使用nextTick确保DOM完全渲染后再初始化
  nextTick(() => {
    // 计算初始缩放比例
    calculateScale()
  })
      calculateScale();
    });
  window.addEventListener('resize', handleResize)
  window.addEventListener('fullscreenchange', handleFullscreenChange)
  window.addEventListener('webkitfullscreenchange', handleFullscreenChange)
  window.addEventListener('MSFullscreenChange', handleFullscreenChange)
})
    window.addEventListener("resize", handleResize);
    window.addEventListener("fullscreenchange", handleFullscreenChange);
    window.addEventListener("webkitfullscreenchange", handleFullscreenChange);
    window.addEventListener("MSFullscreenChange", handleFullscreenChange);
  });
onBeforeUnmount(() => {
  window.removeEventListener('resize', handleResize)
  window.removeEventListener('fullscreenchange', handleFullscreenChange)
  window.removeEventListener('webkitfullscreenchange', handleFullscreenChange)
  window.removeEventListener('MSFullscreenChange', handleFullscreenChange)
    window.removeEventListener("resize", handleResize);
    window.removeEventListener("fullscreenchange", handleFullscreenChange);
    window.removeEventListener("webkitfullscreenchange", handleFullscreenChange);
    window.removeEventListener("MSFullscreenChange", handleFullscreenChange);
  // 移除我们添加的autofit动态调整监听器
  if (window._autofitUpdateHandler) {
    window.removeEventListener('resize', window._autofitUpdateHandler)
    delete window._autofitUpdateHandler
      window.removeEventListener("resize", window._autofitUpdateHandler);
      delete window._autofitUpdateHandler;
  }
  // 关闭autofit
  autofit.off()
})
    autofit.off();
  });
</script>
<style scoped>
@@ -213,7 +226,6 @@
z-index: 9999;
}
.dashboard-header {
position: relative;
z-index: 1;
@@ -229,7 +241,7 @@
.factory-name {
font-weight: 600;
font-size: 52px;
color: #FFFFFF;
    color: #ffffff;
top: 16px;
position: absolute;
}
@@ -268,7 +280,9 @@
}
/* 确保各面板能够正确显示 */
.left-panel, .center-panel, .right-panel {
  .left-panel,
  .center-panel,
  .right-panel {
overflow: hidden;
}
@@ -287,5 +301,4 @@
flex-direction: column;
gap: 20px;
}
</style>