gaoluyang
2025-12-11 b207e5c3dd012a17ba71632da0ebbc09a38e39c2
src/views/reportAnalysis/dataDashboard/index.vue
@@ -1,36 +1,36 @@
<template>
    <div class="data-dashboard">
      <!-- 全屏按钮 - 移动到左上角 -->
      <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">
          <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">{{ userStore.currentFactoryName }}</div>
      </div>
      <!-- 主要内容区域 -->
      <div class="dashboard-content">
      <!-- 左侧区域 -->
      <div class="left-panel">
        <!-- 客户信息统计分析 -->
   <div class="data-dashboard">
      <!-- 全屏按钮 - 移动到左上角 -->
      <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">
            <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">{{ userStore.currentFactoryName }}</div>
      </div>
      <!-- 主要内容区域 -->
      <div class="dashboard-content">
         <!-- 左侧区域 -->
         <div class="left-panel">
            <!-- 客户信息统计分析 -->
            <div class="panel-header">
               <span class="panel-title">客户信息统计分析</span>
            </div>
        <div class="panel-item-customers">
            <div class="panel-item-customers">
               <div class="panel-title-second">
                  <div class="panel-title-icon"></div>
                  <div class="total-customers">
                     <span class="label">总合同金额(元)</span>
                     <span class="value">{{sum}}</span>
                  </div>
<!--                  <div class="jiantou"></div>-->
                  <!--                  <div class="jiantou"></div>-->
               </div>
               <!-- 饼图区域 -->
               <div style="display: flex;align-items: center;gap: 20px;justify-content: space-evenly;height: 82%;margin-top: 20px">
@@ -50,11 +50,52 @@
                     </li>
                  </ul>
               </div>
        </div>
        <!-- 质量统计 -->
            <div class="panel-header">
               <span class="panel-title">质量统计</span>
            </div>
            <!-- 质量统计 -->
<!--            <div class="panel-header">-->
<!--               <span class="panel-title">近4个月质量统计</span>-->
<!--            </div>-->
<!--            <div class="main-panel">-->
<!--               <div class="panel-item-customers">-->
<!--                  <div class="quality-cards">-->
<!--                     <div class="quality-cardSec">-->
<!--                        <div class="quality-card one"></div>-->
<!--                        <div class="quality-cardTitle">-->
<!--                           <div>原材料已检测数</div>-->
<!--                           <div>{{qualityStatisticsObject.supplierNum}}件</div>-->
<!--                        </div>-->
<!--                     </div>-->
<!--                     <div class="quality-cardSec">-->
<!--                        <div class="quality-card two"></div>-->
<!--                        <div class="quality-cardTitle">-->
<!--                           <div>过程检验数量</div>-->
<!--                           <div>{{qualityStatisticsObject.processNum}}件</div>-->
<!--                        </div>-->
<!--                     </div>-->
<!--                     <div class="quality-cardSec">-->
<!--                        <div class="quality-card three"></div>-->
<!--                        <div class="quality-cardTitle">-->
<!--                           <div>出厂已检数量</div>-->
<!--                           <div>{{qualityStatisticsObject.factoryNum}}件</div>-->
<!--                        </div>-->
<!--                     </div>-->
<!--                  </div>-->
<!--                  <Echarts ref="chart"-->
<!--                               :chartStyle="chartStyle"-->
<!--                               :grid="grid"-->
<!--                               :legend="barLegend"-->
<!--                               :series="barSeries1"-->
<!--                               :tooltip="tooltip"-->
<!--                               :xAxis="xAxis1"-->
<!--                               :yAxis="yAxis1"-->
<!--                               :options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}"-->
<!--                               style="height: 260px"></Echarts>-->
<!--               </div>-->
<!--            </div>-->
<!--         </div>-->
         <div class="panel-header">
               <span class="panel-title">近4个月仓库统计</span>
            </div>
            <div class="main-panel">
               <div class="panel-item-customers">
@@ -62,24 +103,24 @@
                     <div class="quality-cardSec">
                        <div class="quality-card one"></div>
                        <div class="quality-cardTitle">
                           <div>原材料已检测数</div>
                           <div>{{qualityStatisticsObject.supplierNum}}件</div>
                           <div>入库数量</div>
                           <div>{{supplierNum}}件</div>
                        </div>
                     </div>
                     <div class="quality-cardSec">
                        <div class="quality-card two"></div>
                        <div class="quality-cardTitle">
                           <div>过程检验数量</div>
                           <div>{{qualityStatisticsObject.processNum}}件</div>
                           <div>出库数量</div>
                           <div>{{factoryNum}}件</div>
                        </div>
                     </div>
                     <div class="quality-cardSec">
                        <div class="quality-card three"></div>
                        <div class="quality-cardTitle">
                           <div>出厂已检数量</div>
                           <div>{{qualityStatisticsObject.factoryNum}}件</div>
                        </div>
                     </div>
<!--                     <div class="quality-cardSec">-->
<!--                        <div class="quality-card three"></div>-->
<!--                        <div class="quality-cardTitle">-->
<!--                           <div>出厂已检数量</div>-->
<!--                           <div>{{qualityStatisticsObject.factoryNum}}件</div>-->
<!--                        </div>-->
<!--                     </div>-->
                  </div>
                  <Echarts ref="chart"
                               :chartStyle="chartStyle"
@@ -93,85 +134,110 @@
                               style="height: 260px"></Echarts>
               </div>
            </div>
      </div>
      <!-- 中间区域 -->
      <div class="center-panel">
        <!-- 顶部统计卡片 -->
        <div class="stats-cards">
          <div class="stat-card">
            <img src="@/assets/BI/icon@2x.png" alt="图标" class="card-icon" />
            <div class="card-content">
              <span class="card-label">员工总数</span>
              <span class="card-value">{{totalStaff}}</span>
            </div>
          </div>
          <div class="stat-card">
            <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>
          </div>
          <div class="stat-card">
            <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>
          </div>
        </div>
        <!-- 设备统计 -->
        <div class="equipment-stats">
          <div class="equipment-header">
                  <img src="@/assets/BI/shujutongjiicon@2x.png" alt="图标" class="equipment-icon" />
            <span class="equipment-title">设备统计</span>
          </div>
          <div class="equipment-items">
            <div class="equipment-item">
              <span class="equipment-value">{{equipmentNum}}</span>
              <span class="equipment-label">设备总数</span>
            </div>
            <div class="equipment-item">
              <span class="equipment-value">{{equipmentRepair}}</span>
              <span class="equipment-label">待维修设备</span>
            </div>
            <div class="equipment-item">
              <span class="equipment-value">{{equipmentMaintain}}</span>
              <span class="equipment-label">待保养设备</span>
            </div>
            <div class="equipment-item">
              <span class="equipment-value">{{totalMeasuring}}</span>
              <span class="equipment-label">计量器具总数</span>
            </div>
          </div>
        </div>
        <!-- 事件名称 -->
        <div class="event-info">
          <div class="event-header">
                  <img src="@/assets/BI/shijianmingxiicon@2x.png" alt="图标" 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="display: flex;flex-direction: column;justify-content: space-between;width: 100%;gap: 20px">
     <div style="display: flex;justify-content: space-between;align-items: center;">
      <div class="todo-title">待办编号:{{item.approveId}}</div>
      <div class="todo-division">部门:{{item.approveDeptName}}</div>
      <div class="todo-time">{{item.approveTime}}</div>
     </div>
     <div class="todo-division">待办事由:{{item.approveReason}}</div>
    </div>
   </li>
 </ul>
                  <div v-else style="text-align: center">
                     暂无数据
         </div>
         <!-- 中间区域 -->
         <div class="center-panel">
            <!-- 顶部统计卡片 -->
            <div class="stats-cards">
               <div class="stat-card">
                  <img src="@/assets/BI/icon@2x.png" alt="图标" class="card-icon" />
                  <div class="card-content">
                     <span class="card-label">员工总数</span>
                     <span class="card-value">{{totalStaff}}</span>
                  </div>
          </div>
        </div>
               </div>
               <div class="stat-card">
                  <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>
               </div>
               <div class="stat-card">
                  <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>
               </div>
            </div>
            <!-- 设备统计 -->
            <div class="equipment-stats">
               <div class="equipment-header">
                  <img src="@/assets/BI/shujutongjiicon@2x.png" alt="图标" class="equipment-icon" />
                  <span class="equipment-title">生产统计</span>
               </div>
               <div class="equipment-items">
                  <div class="equipment-item">
                     <span class="equipment-value">{{noWorkListLength}}</span>
                     <span class="equipment-label">待排产</span>
                  </div>
                  <div class="equipment-item">
                     <span class="equipment-value">{{workListLength}}</span>
                     <span class="equipment-label">已排产</span>
                  </div>
                  <div class="equipment-item">
                     <span class="equipment-value">{{noListPageProcessLength}}</span>
                     <span class="equipment-label">待报工</span>
                  </div>
                  <div class="equipment-item">
                     <span class="equipment-value">{{listPageProcessLength}}</span>
                     <span class="equipment-label">已报工</span>
                  </div>
               </div>
            </div>
            <!-- 合格率 -->
            <div class="equipment-stats">
               <div class="equipment-header">
                  <img src="@/assets/BI/shujutongjiicon@2x.png" alt="图标" class="equipment-icon" />
                  <span class="equipment-title">质检统计</span>
               </div>
               <div class="equipment-items">
                  <div class="equipment-item">
                     <span class="equipment-value">{{rawMaterialQualifiedRate}}%</span>
                     <span class="equipment-label">原材料合格率</span>
                  </div>
                  <div class="equipment-item">
                     <span class="equipment-value">{{processQualifiedRate}}%</span>
                     <span class="equipment-label">过程合格率</span>
                  </div>
                  <div class="equipment-item">
                     <span class="equipment-value">{{factoryQualifiedRate}}%</span>
                     <span class="equipment-label">出厂合格率</span>
                  </div>
                  <div class="equipment-item">
                     <span class="equipment-value">{{inventoryTurnoverRate}}%</span>
                     <span class="equipment-label">库存周转率</span>
                  </div>
               </div>
            </div>
            <!-- 事件名称 -->
            <!--        <div class="event-info">-->
            <!--          <div class="event-header">-->
            <!--                  <img src="@/assets/BI/shijianmingxiicon@2x.png" alt="图标" 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="display: flex;flex-direction: column;justify-content: space-between;width: 100%;gap: 20px"> -->
            <!--     <div style="display: flex;justify-content: space-between;align-items: center;"> -->
            <!--      <div class="todo-title">待办编号:{{item.approveId}}</div> -->
            <!--      <div class="todo-division">部门:{{item.approveDeptName}}</div> -->
            <!--      <div class="todo-time">{{item.approveTime}}</div> -->
            <!--     </div> -->
            <!--     <div class="todo-division">待办事由:{{item.approveReason}}</div> -->
            <!--    </div> -->
            <!--   </li> -->
            <!-- </ul>-->
            <!--                  <div v-else style="text-align: center">-->
            <!--                     暂无数据-->
            <!--                  </div>-->
            <!--          </div>-->
            <!--        </div>-->
            
            <div class="financial-header">
               <span class="financial-title">财务分析</span>
@@ -191,31 +257,31 @@
                               :xAxis="xAxis3"
                               :yAxis="yAxis3"
                               :options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}"
                               style="height: 300px"></Echarts>
                               style="height: 280px"></Echarts>
               </div>
            </div>
      </div>
      <!-- 右侧区域 -->
      <div class="right-panel">
        <!-- 应收应付统计 -->
         </div>
         <!-- 右侧区域 -->
         <div class="right-panel">
            <!-- 应收应付统计 -->
            <div class="panel-header">
               <span class="panel-title">应收应付统计</span>
            </div>
            <div class="panel-item-customers">
               <div style="display: flex;justify-content: space-between;margin-bottom: 20px;">
                  <div class="section-title">应收应付统计</div>
                  <el-radio-group v-model="radio1" size="large" @change="statisticsReceivable" class="custom-radio-group">
                     <el-radio-button label="按周" :value="1" />
                     <el-radio-button label="按月" :value="2" />
                     <el-radio-button label="按季度" :value="3" />
                  </el-radio-group>
                  <!--                  <el-radio-group v-model="radio1" size="large" @change="statisticsReceivable" class="custom-radio-group">-->
                  <!--                     <el-radio-button label="按周" :value="1" />-->
                  <!--                     <el-radio-button label="按月" :value="2" />-->
                  <!--                     <el-radio-button label="按季度" :value="3" />-->
                  <!--                  </el-radio-group>-->
               </div>
               <Echarts ref="chart"
                            :color="barColors2"
                            :chartStyle="chartStyle"
                            :grid="grid"
                   :legend="barLegend2"
                            :legend="barLegend2"
                            :series="barSeries"
                            :tooltip="tooltip"
                            :xAxis="xAxis"
@@ -223,18 +289,18 @@
                            :options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}"
                            style="height: 260px"></Echarts>
            </div>
        <!-- 回款与开票分析 -->
         <div class="panel-header">
            <!-- 回款与开票分析 -->
            <div class="panel-header">
               <span class="panel-title">回款与开票分析</span>
            </div>
        <div class="panel-item-customers" style="padding-top: 60px;">
            <div class="panel-item-customers" style="padding-top: 60px;">
               <Echarts ref="chart" :chartStyle="chartStyle" :grid="grid" :legend="lineLegend" :series="lineSeries"
                         :tooltip="tooltipLine" :xAxis="xAxis2" :yAxis="yAxis2" :options="{backgroundColor: 'transparent', textStyle: {color: '#FFFFFF'}}" style="height: 270px;"></Echarts>
                            :tooltip="tooltipLine" :xAxis="xAxis2" :yAxis="yAxis2" :options="{backgroundColor: 'transparent', textStyle: {color: '#FFFFFF'}}" style="height: 270px;"></Echarts>
            </div>
      </div>
      </div>
    </div>
         </div>
      </div>
   </div>
</template>
<script setup>
@@ -245,7 +311,7 @@
import useUserStore from '@/store/modules/user'
import {
   analysisCustomerContractAmounts, getAmountHalfYear,
   homeTodos,
   homeTodos, inventoryStatistics, qualityProductQualifiedRate,
   qualityStatistics,
   statisticsReceivablePayable
} from "@/api/viewIndex.js";
@@ -257,6 +323,8 @@
import {getUpkeepPage} from "@/api/equipmentManagement/upkeep.js";
import {measuringInstrumentListPage} from "@/api/equipmentManagement/measurementEquipment.js";
import {listPageAnalysis} from "@/api/financialManagement/expenseManagement.js";
import {workListPage} from "@/api/productionManagement/productionReporting.js";
import {listPageProcess} from "@/api/productionManagement/operationScheduling.js";
// 全屏相关状态
const isFullscreen = ref(false);
@@ -312,6 +380,16 @@
const equipmentRepair = ref(0)
const equipmentMaintain = ref(0)
const totalMeasuring = ref(0)
const rawMaterialQualifiedRate = ref(0)
const processQualifiedRate = ref(0)
const factoryQualifiedRate = ref(0)
const inventoryTurnoverRate = ref(0)
const noWorkListLength = ref(0)
const workListLength = ref(0)
const noListPageProcessLength = ref(0)
const listPageProcessLength = ref(0)
const supplierNum = ref(0)
const factoryNum = ref(0)
const pieTooltip = reactive({
   trigger: 'item',
   formatter: function (params) {
@@ -371,7 +449,7 @@
}
const lineLegend = {
   show: true,
  textStyle: { color: '#B8C8E0' },
   textStyle: { color: '#B8C8E0' },
   data: ['开票', '回款']
}
const lineSeries = ref([
@@ -412,7 +490,7 @@
const barLegend = {
   show: true,
   textStyle: { color: '#B8C8E0' },
   data: ['原材料不合格数', '过程不合格数', '出厂不合格数']
   data: ['原材料合格数', '过程合格数', '出厂合格数']
}
const barLegend1 = {
   show: true,
@@ -487,7 +565,7 @@
])
const barSeries1 = ref([
   {
      name: '原材料不合格数',
      name: '入库数量',
      type: 'bar',
      barGap: 0,
      emphasis: {
@@ -509,7 +587,7 @@
      data: []
   },
   {
      name: '过程不合格数',
      name: '出库数量',
      type: 'bar',
      emphasis: {
         focus: 'series'
@@ -524,27 +602,6 @@
            colorStops: [
               { offset: 1, color: '#3378FF' },
               { offset: 0, color: '#4E8AFF' }
            ]
         }
      },
      data: []
   },
   {
      name: '出厂不合格数',
      type: 'bar',
      emphasis: {
         focus: 'series'
      },
      itemStyle: {
         color: {
            type: 'linear',
            x: 0,
            y: 0,
            x2: 0,
            y2: 1,
            colorStops: [
               { offset: 1, color: '#537EF5' },
               { offset: 0, color: '#9061F8' }
            ]
         }
      },
@@ -597,21 +654,21 @@
// 窗口大小变化处理
const handleResize = () => {
  charts.value.forEach(chart => {
    if (chart && chart.resize) {
      chart.resize()
    }
  })
   charts.value.forEach(chart => {
      if (chart && chart.resize) {
         chart.resize()
      }
   })
}
// 销毁图表实例
const disposeCharts = () => {
  charts.value.forEach(chart => {
    if (chart && chart.dispose) {
      chart.dispose()
    }
  })
  charts.value = []
   charts.value.forEach(chart => {
      if (chart && chart.dispose) {
         chart.dispose()
      }
   })
   charts.value = []
}
// 合同金额
const analysisCustomer = () => {
@@ -640,6 +697,27 @@
      qualityStatisticsObject.value.factoryNum = res.data.factoryNum
   })
}
// 产品合格率
const qualityProductQualifiedRateInfo = () => {
   qualityProductQualifiedRate().then((res) => {
      rawMaterialQualifiedRate.value = res.data.rawMaterialQualifiedRate
      processQualifiedRate.value = res.data.processQualifiedRate
      factoryQualifiedRate.value = res.data.factoryQualifiedRate
      inventoryTurnoverRate.value = res.data.inventoryTurnoverRate
   })
}
// 产品合格率
const inventoryStatisticsInfo = () => {
   inventoryStatistics().then((res) => {
      supplierNum.value = res.data.supplierNum
      factoryNum.value = res.data.factoryNum
      res.data.item.forEach(item => {
         xAxis1.value[0].data.push(item.date)
         barSeries1.value[0].data.push(item.supplierNum)
         barSeries1.value[1].data.push(item.factoryNum)
      })
   })
}
// 财务统计
const accountStatisticsInfo = () => {
   listPageAnalysis().then((res) => {
@@ -649,6 +727,36 @@
      barSeries11.value[2].data = res.data.netIncome
   })
}
// 生产数据
const workListPageInfo = () => {
   const params = {
      current: -1,
      size: -1,
      status: 3
   }
   const params1 = {
      current: -1,
      size: -1,
      status: 1
   }
   // 已报工查询
   workListPage(params).then(res => {
      workListLength.value = res.data.records.length
   })
   // 已排产查询
   listPageProcess(params).then(res => {
      listPageProcessLength.value = res.data.records.length
   })
   // 待报工查询
   workListPage(params1).then(res => {
      noWorkListLength.value = res.data.records.length
   })
   // 待排产查询
   listPageProcess(params1).then(res => {
      noListPageProcessLength.value = res.data.records.length
   })
}
const getNum = () => {
   const params = {
      pageNum: -1,
@@ -669,7 +777,7 @@
      pageNum: -1,
      pageSize: -1,
   }
   getLedgerPage(params).then((res) => {
   getLedgerPage({}).then((res) => {
      equipmentNum.value = res.data.total
   });
   getRepairPage(params).then((res) => {
@@ -866,20 +974,20 @@
// 更新时间
const updateTime = () => {
  const now = new Date()
  currentTime.value = now.toLocaleTimeString('zh-CN', { hour12: false })
  currentDate.value = now.toLocaleDateString('zh-CN', {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    weekday: 'long'
  })
   const now = new Date()
   currentTime.value = now.toLocaleTimeString('zh-CN', { hour12: false })
   currentDate.value = now.toLocaleDateString('zh-CN', {
      year: 'numeric',
      month: '2-digit',
      day: '2-digit',
      weekday: 'long'
   })
}
// 初始化时间
const initTime = () => {
  updateTime()
  timer.value = setInterval(updateTime, 1000)
   updateTime()
   timer.value = setInterval(updateTime, 1000)
}
// 全屏功能实现 - 针对data-dashboard元素
const toggleFullscreen = () => {
@@ -908,146 +1016,149 @@
// 监听全屏变化事件
const handleFullscreenChange = () => {
  const fullscreenElement = document.fullscreenElement ||
                           document.webkitFullscreenElement ||
                           document.msFullscreenElement
  isFullscreen.value = fullscreenElement && fullscreenElement.classList.contains('data-dashboard')
   const fullscreenElement = document.fullscreenElement ||
      document.webkitFullscreenElement ||
      document.msFullscreenElement
   isFullscreen.value = fullscreenElement && fullscreenElement.classList.contains('data-dashboard')
}
// 生命周期钩子
onMounted(() => {
  initTime()
  // 使用nextTick确保DOM完全渲染后再初始化图表
  nextTick(() => {
    // 初始化autofit自适应
    autofit.init({ dh: 1080, dw: 1920, el: '.data-dashboard', resize: true }, false)
    // 添加自动滚动动画效果 - 客户信息列表
    const contractList = refContractList.value
    if (contractList && contractList.scrollHeight > contractList.clientHeight) {
      // 创建一个克隆项,用于实现无缝滚动
      const scrollItems = Array.from(contractList.querySelectorAll('li'))
      const itemHeight = scrollItems[0]?.offsetHeight || 0
      const containerHeight = contractList.clientHeight
      const cloneCount = Math.ceil(containerHeight / itemHeight) + 2
      // 克隆前几个项目并添加到列表末尾,实现无缝滚动
      for (let i = 0; i < cloneCount; i++) {
        const clone = scrollItems[i % scrollItems.length].cloneNode(true)
        contractList.appendChild(clone)
      }
      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 (!isPaused) {
          scrollPosition += scrollSpeed * (deltaTime / 16) // 标准化为60fps的速度
          // 当滚动超过原始内容长度时,重置位置实现无缝滚动
          if (scrollPosition >= contractList.scrollHeight - containerHeight - cloneCount * itemHeight) {
            scrollPosition = 0
            contractList.scrollTop = 0
          } else {
            contractList.scrollTop = scrollPosition
          }
        }
        timerScroll.value = requestAnimationFrame(scrollAnimation)
      }
      // 启动滚动动画
      timerScroll.value = requestAnimationFrame(scrollAnimation)
      // 设置滚动-暂停-滚动的循环效果
      const pauseTimer = setInterval(() => {
        isPaused = !isPaused
      }, pauseTime)
      // 清理定时器
      contractList._pauseTimer = pauseTimer
    }
    // 待办事项列表滚动功能已移至todoInfoS函数中,在获取数据后初始化
  })
  window.addEventListener('resize', handleResize)
  analysisCustomer()
  qualityStatisticsInfo()
   initTime()
   // 使用nextTick确保DOM完全渲染后再初始化图表
   nextTick(() => {
      // 初始化autofit自适应
      autofit.init({ dh: 1080, dw: 1920, el: '.data-dashboard', resize: true }, false)
      // 添加自动滚动动画效果 - 客户信息列表
      const contractList = refContractList.value
      if (contractList && contractList.scrollHeight > contractList.clientHeight) {
         // 创建一个克隆项,用于实现无缝滚动
         const scrollItems = Array.from(contractList.querySelectorAll('li'))
         const itemHeight = scrollItems[0]?.offsetHeight || 0
         const containerHeight = contractList.clientHeight
         const cloneCount = Math.ceil(containerHeight / itemHeight) + 2
         // 克隆前几个项目并添加到列表末尾,实现无缝滚动
         for (let i = 0; i < cloneCount; i++) {
            const clone = scrollItems[i % scrollItems.length].cloneNode(true)
            contractList.appendChild(clone)
         }
         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 (!isPaused) {
               scrollPosition += scrollSpeed * (deltaTime / 16) // 标准化为60fps的速度
               // 当滚动超过原始内容长度时,重置位置实现无缝滚动
               if (scrollPosition >= contractList.scrollHeight - containerHeight - cloneCount * itemHeight) {
                  scrollPosition = 0
                  contractList.scrollTop = 0
               } else {
                  contractList.scrollTop = scrollPosition
               }
            }
            timerScroll.value = requestAnimationFrame(scrollAnimation)
         }
         // 启动滚动动画
         timerScroll.value = requestAnimationFrame(scrollAnimation)
         // 设置滚动-暂停-滚动的循环效果
         const pauseTimer = setInterval(() => {
            isPaused = !isPaused
         }, pauseTime)
         // 清理定时器
         contractList._pauseTimer = pauseTimer
      }
      // 待办事项列表滚动功能已移至todoInfoS函数中,在获取数据后初始化
   })
   window.addEventListener('resize', handleResize)
   analysisCustomer()
   // qualityStatisticsInfo()
   qualityProductQualifiedRateInfo()
   inventoryStatisticsInfo()
   accountStatisticsInfo()
  getNum()
  getLedgerNum()
  todoInfoS()
   workListPageInfo()
   getNum()
   getLedgerNum()
   todoInfoS()
   statisticsReceivable()
   getAmountHalfYearNum()
  // 设置自动轮换周、月、季度的定时器,每10秒切换一次
  autoSwitchTimer.value = setInterval(() => {
    // 循环切换:1(周) -> 2(月) -> 3(季度) -> 1(周)
    radio1.value = radio1.value === 3 ? 1 : radio1.value + 1
    statisticsReceivable()
  }, 10000) // 10秒切换一次
   // 设置自动轮换周、月、季度的定时器,每10秒切换一次
   autoSwitchTimer.value = setInterval(() => {
      // 循环切换:1(周) -> 2(月) -> 3(季度) -> 1(周)
      radio1.value = radio1.value === 3 ? 1 : radio1.value + 1
      statisticsReceivable()
   }, 10000) // 10秒切换一次
})
onBeforeUnmount(() => {
  if (timer.value) {
    clearInterval(timer.value)
  }
  if (timerScroll.value) {
    cancelAnimationFrame(timerScroll.value)
  }
  // 清理滚动列表的暂停定时器
  const contractList = refContractList.value
  if (contractList && contractList._pauseTimer) {
    clearInterval(contractList._pauseTimer)
  }
  // 清理待办事项列表的动画和定时器
  const todoList = refTodoList.value
  if (todoList) {
    if (todoList._animationFrame) {
      cancelAnimationFrame(todoList._animationFrame)
      todoList._animationFrame = null
    }
    if (todoList._pauseTimer) {
      clearInterval(todoList._pauseTimer)
      todoList._pauseTimer = null
    }
  }
  // 清理自动轮换周、月、季度的定时器
  if (autoSwitchTimer.value) {
    clearInterval(autoSwitchTimer.value)
    autoSwitchTimer.value = null
  }
  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
  }
  disposeCharts()
  // 关闭autofit
  autofit.off()
   if (timer.value) {
      clearInterval(timer.value)
   }
   if (timerScroll.value) {
      cancelAnimationFrame(timerScroll.value)
   }
   // 清理滚动列表的暂停定时器
   const contractList = refContractList.value
   if (contractList && contractList._pauseTimer) {
      clearInterval(contractList._pauseTimer)
   }
   // 清理待办事项列表的动画和定时器
   const todoList = refTodoList.value
   if (todoList) {
      if (todoList._animationFrame) {
         cancelAnimationFrame(todoList._animationFrame)
         todoList._animationFrame = null
      }
      if (todoList._pauseTimer) {
         clearInterval(todoList._pauseTimer)
         todoList._pauseTimer = null
      }
   }
   // 清理自动轮换周、月、季度的定时器
   if (autoSwitchTimer.value) {
      clearInterval(autoSwitchTimer.value)
      autoSwitchTimer.value = null
   }
   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
   }
   disposeCharts()
   // 关闭autofit
   autofit.off()
})
</script>
<style scoped>
.data-dashboard {
  position: relative;
  width: 100%;
   position: relative;
   width: 100%;
   height: 100%;
   background-image: url("@/assets/BI/backImage@2x.png");
   background-size: cover;
@@ -1057,114 +1168,114 @@
/* 全屏状态的样式 */
.data-dashboard:fullscreen {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  background-color: inherit;
  z-index: 9999;
   width: 100%;
   height: 100%;
   margin: 0;
   padding: 0;
   background-color: inherit;
   z-index: 9999;
}
/* Webkit浏览器前缀 */
.data-dashboard:-webkit-full-screen {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  background-color: inherit;
  z-index: 9999;
   width: 100%;
   height: 100%;
   margin: 0;
   padding: 0;
   background-color: inherit;
   z-index: 9999;
}
/* MS浏览器前缀 */
.data-dashboard:-ms-fullscreen {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  background-color: inherit;
  z-index: 9999;
   width: 100%;
   height: 100%;
   margin: 0;
   padding: 0;
   background-color: inherit;
   z-index: 9999;
}
.dashboard-header {
  position: relative;
  z-index: 1;
  height: 170px;
   position: relative;
   z-index: 1;
   height: 170px;
   background-image: url("@/assets/BI/biaoti.png");
   background-size: cover;
   background-position: center;
   background-repeat: no-repeat;
  display: flex;
  align-items: center;
  justify-content: center;
   display: flex;
   align-items: center;
   justify-content: center;
}
.factory-name {
  font-weight: 600;
font-size: 52px;
color: #FFFFFF;
top: 32px;
position: absolute;
   font-weight: 600;
   font-size: 52px;
   color: #FFFFFF;
   top: 32px;
   position: absolute;
}
.fullscreen-btn {
  position: absolute;
  top: 10px;
  left: 20px;
  width: 40px;
  height: 40px;
  background: rgba(0, 20, 60, 0.8);
  border: 1px solid rgba(0, 212, 255, 0.3);
  border-radius: 6px;
  color: #00d4ff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s;
  z-index: 10000;
   position: absolute;
   top: 10px;
   left: 20px;
   width: 40px;
   height: 40px;
   background: rgba(0, 20, 60, 0.8);
   border: 1px solid rgba(0, 212, 255, 0.3);
   border-radius: 6px;
   color: #00d4ff;
   cursor: pointer;
   display: flex;
   align-items: center;
   justify-content: center;
   transition: all 0.3s;
   z-index: 10000;
}
.fullscreen-btn:hover {
  background: rgba(0, 30, 90, 0.9);
  border-color: rgba(0, 212, 255, 0.5);
   background: rgba(0, 30, 90, 0.9);
   border-color: rgba(0, 212, 255, 0.5);
}
.dashboard-content {
  position: relative;
  z-index: 1;
  display: flex;
  gap: 30px;
  padding: 0 30px;
  height: calc(100% - 120px);
  overflow: hidden;
   position: relative;
   z-index: 1;
   display: flex;
   gap: 30px;
   padding: 0 30px;
   height: calc(100% - 120px);
   overflow: hidden;
}
/* 确保各面板能够正确显示 */
.left-panel, .center-panel, .right-panel {
  overflow: hidden;
   overflow: hidden;
}
.left-panel,
.right-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 24px;
   flex: 1;
   display: flex;
   flex-direction: column;
   gap: 24px;
   width: 520px;
}
.center-panel {
  flex: 1.5;
  display: flex;
  flex-direction: column;
  gap: 20px;
   flex: 1.5;
   display: flex;
   flex-direction: column;
   gap: 20px;
}
.panel-item-customers {
   border: 1px solid #1A58B0;
   padding: 18px;
   width: 100%;
   height: 540px;
   height: 520px;
}
.panel-title-second {
   height: 60px;
@@ -1297,40 +1408,40 @@
   margin-top: 10px;
}
.stats-cards {
  display: flex;
  gap: 30px;
   display: flex;
   gap: 30px;
}
.stat-card {
  flex: 1;
  display: flex;
  align-items: center;
   flex: 1;
   display: flex;
   align-items: center;
   background-image: url("@/assets/BI/border@2x.png");
   background-size: 100% 100%;
   background-position: center;
   background-repeat: no-repeat;
  height: 142px;
   height: 142px;
}
.card-icon {
  width: 100px;
  height: 100px;
  margin: 20px 20px 0 10px;
   width: 100px;
   height: 100px;
   margin: 20px 20px 0 10px;
}
.card-content {
  display: flex;
  flex-direction: column;
   display: flex;
   flex-direction: column;
   gap: 10px;
}
.card-value {
   font-weight: 500;
   font-size: 40px;
  background: linear-gradient(360deg, #008BFD 0%, #FFFFFF 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
   background: linear-gradient(360deg, #008BFD 0%, #FFFFFF 100%);
   -webkit-background-clip: text;
   -webkit-text-fill-color: transparent;
   background-clip: text;
}
.card-label {
@@ -1341,8 +1452,8 @@
.equipment-stats {
   border: 1px solid #1A58B0;
  padding: 18px;
  height: 240px;
   padding: 18px;
   height: 240px;
}
.equipment-header {
   font-weight: 500;
@@ -1366,17 +1477,17 @@
   height: 50px;
}
.equipment-items {
  display: flex;
  justify-content: space-around;
  gap: 30px;
   display: flex;
   justify-content: space-around;
   gap: 30px;
}
.equipment-item {
  text-align: center;
   text-align: center;
}
.equipment-value {
  display: block;
   display: block;
   font-weight: 500;
   font-size: 40px;
   color: #FFFFFF;
@@ -1387,7 +1498,7 @@
   background-size: 100% 100%;
   background-position: center;
   background-repeat: no-repeat;
  margin-bottom: 8px;
   margin-bottom: 8px;
}
.equipment-label {
@@ -1401,8 +1512,8 @@
   background-size: 100% 100%;
   background-position: center;
   background-repeat: no-repeat;
  padding: 20px;
  height: 186px;
   padding: 20px;
   height: 186px;
}
.event-header {
   display: flex;
@@ -1419,12 +1530,12 @@
   line-height: 30px;
}
.todo-list {
  list-style: none;
  padding: 0;
  margin: 0;
  height: 120px; /* 按用户要求调整高度 */
  overflow: hidden;
  font-size: 15px;
   list-style: none;
   padding: 0;
   margin: 0;
   height: 120px; /* 按用户要求调整高度 */
   overflow: hidden;
   font-size: 15px;
}
.todo-list li {
   border-radius: 8px;
@@ -1479,15 +1590,15 @@
/* 自定义单选按钮组样式 */
.custom-radio-group :deep(.el-radio-button__inner) {
  background-color: transparent;
  color: white;
  border-color: rgba(255, 255, 255, 0.3);
   background-color: transparent;
   color: white;
   border-color: rgba(255, 255, 255, 0.3);
}
.custom-radio-group :deep(.el-radio-button__original-radio:checked + .el-radio-button__inner) {
  background-color: rgba(255, 255, 255, 0.2);
  color: white;
  border-color: rgba(255, 255, 255, 0.5);
  box-shadow: -1px 0 0 0 rgba(255, 255, 255, 0.5);
   background-color: rgba(255, 255, 255, 0.2);
   color: white;
   border-color: rgba(255, 255, 255, 0.5);
   box-shadow: -1px 0 0 0 rgba(255, 255, 255, 0.5);
}
</style>