From 1cf342fa23a6c34bd9dd1ff4e416cd255c044fdd Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期四, 02 四月 2026 11:41:17 +0800
Subject: [PATCH] Merge branch 'dev_银川_中盛建材' of http://114.132.189.42:9002/r/product-inventory-management into dev_银川_中盛建材

---
 src/views/reportAnalysis/productionStatistics/index.vue | 3089 ++++++++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 2,226 insertions(+), 863 deletions(-)

diff --git a/src/views/reportAnalysis/productionStatistics/index.vue b/src/views/reportAnalysis/productionStatistics/index.vue
index cf00f0f..47822ce 100644
--- a/src/views/reportAnalysis/productionStatistics/index.vue
+++ b/src/views/reportAnalysis/productionStatistics/index.vue
@@ -1,157 +1,247 @@
 <template>
-  <div class="dashboard-container">
-    <div class="data-dashboard">
-      <!-- 椤堕儴鏍囬鏍� -->
-      <!-- <div class="dashboard-header">
-      <div class="factory-name">鐢熶骇缁熻鐪嬫澘</div>
-    </div> -->
-      <!-- 绛涢�夊尯鍩� -->
-      <div class="filter-area">
-        <div class="filter-section">
-          <span class="filter-label">鏃堕棿缁村害锛�</span>
-          <el-radio-group v-model="dateType"
-                          @change="handleDateTypeChange"
-                          class="radio-group">
-            <el-radio-button label="month">鏈堝害</el-radio-button>
-            <el-radio-button label="year">骞村害</el-radio-button>
-          </el-radio-group>
+  <div ref="screenRoot"
+       class="sales-statistics-container"
+       :class="{ 'is-fullscreen': isFullscreen }">
+    <div class="bi-bg"></div>
+    <div class="bi-topbar">
+      <img class="bi-topbar-title-bg"
+           src="@/assets/BI/biaoti.png"
+           alt="鐢熶骇鐪嬫澘缁熻" />
+      <div class="bi-topbar-content">
+        <div class="bi-topbar-left">
+          <button class="fullscreen-btn"
+                  @click="toggleFullscreen"
+                  :title="isFullscreen ? '閫�鍑哄叏灞�' : '鍏ㄥ睆鏄剧ず'">
+            <svg v-if="!isFullscreen"
+                 width="1.6vh"
+                 height="1.6vh"
+                 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="1.6vh"
+                 height="1.6vh"
+                 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>
-        <div class="filter-section">
-          <span class="filter-label">浜у搧绫诲瀷锛�</span>
-          <el-radio-group v-model="productType"
-                          @change="handleProductTypeChange"
-                          class="radio-group">
-            <el-radio-button label="block">鐮屽潡</el-radio-button>
-            <el-radio-button label="plate">鏉挎潗</el-radio-button>
-          </el-radio-group>
+        <div class="bi-topbar-title">鐢熶骇鐪嬫澘缁熻</div>
+        <div class="bi-topbar-meta">
+          <span class="bi-topbar-time">{{ currentTime }}</span>
+          <span class="bi-topbar-sep">|</span>
+          <span class="bi-topbar-date">{{ currentDateText }}</span>
         </div>
       </div>
-      <!-- 涓昏鍐呭鍖哄煙 -->
-      <div class="dashboard-content">
-        <!-- 绗竴琛� -->
-        <div class="row row-1">
-          <div class="panel-card card-1">
-            <div class="panel-title">浜ч噺鎸囨爣</div>
-            <div class="chart-container">
-              <div ref="productionChart"
-                   style="width: 100%; height: 100%"></div>
+    </div>
+    <div class="bi-dashboard-grid">
+      <!-- 宸︿笂锛氱敓浜ф垚鏈崟鑰楃粺璁★紙鐮屽潡锛� -->
+      <div class="bi-panel bi-panel-top-left">
+        <PanelHeader :isFullscreen="true"
+                     title="鐢熶骇鎴愭湰鍗曡�楃粺璁★紙鐮屽潡锛�" />
+        <div class="panel-tabs">
+          <span class="tab-item"
+                :class="{ active: blockTimeDimension === 'year' }"
+                @click="handleBlockTimeDimensionChange('year')">骞�</span>
+          <span class="tab-item"
+                :class="{ active: blockTimeDimension === 'month' }"
+                @click="handleBlockTimeDimensionChange('month')">鏈�</span>
+        </div>
+        <div class="bi-panel-body">
+          <div class="chart-filter-tabs">
+            <span v-for="name in blockMaterialList"
+                  :key="name"
+                  class="cf-tab"
+                  :class="{ active: blockSelectedMaterial === name }"
+                  @click="selectBlockMaterial(name)">{{ name }}</span>
+          </div>
+          <div v-if="blockSelectedMaterial !== '鍏ㄩ儴'"
+               class="material-info-card">
+            <div class="material-icon">
+              <svg width="24"
+                   height="24"
+                   viewBox="0 0 24 24"
+                   fill="none"
+                   stroke="currentColor"
+                   stroke-width="2">
+                <path d="M20 7h-4V4c0-1.1-.9-2-2-2h-4c-1.1 0-2 .9-2 2v3H4c-1.1 0-2 .9-2 2v11c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2z" />
+                <polyline points="22,7 12,13 2,7" />
+              </svg>
+            </div>
+            <div class="material-details">
+              <div class="material-name">{{ blockMaterialSummary.materialName || "鈥�" }}</div>
+              <div class="material-stats">
+                <div class="stat-item">
+                  <span class="stat-label">鏈堢疮璁″崟鑰�</span>
+                  <span class="stat-value">{{ blockMaterialSummary.monthlyConsumption }}</span>
+                  <span class="stat-unit">鍚�</span>
+                </div>
+                <div class="stat-item">
+                  <span class="stat-label">骞寸疮璁″崟鑰�</span>
+                  <span class="stat-value">{{ blockMaterialSummary.yearlyConsumption }}</span>
+                  <span class="stat-unit">鍚�</span>
+                </div>
+              </div>
             </div>
           </div>
-          <div class="panel-card card-2">
-            <div class="panel-title">鍥哄簾澶勭悊閲�</div>
-            <div class="chart-container">
-              <div ref="solidWasteChart"
-                   style="width: 100%; height: 100%"></div>
-            </div>
+          <!-- <div class="chart-unit-row">
+            <span>鍗曚綅锛氱珛鏂圭背</span>
+          </div> -->
+          <div ref="blockCostChart"
+               class="echart-fill"></div>
+        </div>
+      </div>
+      <!-- 鍙充笂锛氫骇閲忓垎鏋� -->
+      <div class="bi-panel bi-panel-top-right">
+        <PanelHeader :isFullscreen="true"
+                     title="鐗╂枡鐢熶骇閲忓垎鏋�" />
+        <div class="panel-tabs">
+          <span class="tab-item"
+                :class="{ active: productionTimeDimension === 'year' }"
+                @click="handleProductionTimeDimensionChange('year')">骞�</span>
+          <span class="tab-item"
+                :class="{ active: productionTimeDimension === 'month' }"
+                @click="handleProductionTimeDimensionChange('month')">鏈�</span>
+        </div>
+        <div class="bi-panel-body">
+          <div class="chart-filter-tabs">
+            <span v-for="cat in productionCategories"
+                  :key="cat"
+                  class="cf-tab"
+                  :class="{ active: productionCategory === cat }"
+                  @click="selectProductionCategory(cat)">{{ cat }}</span>
           </div>
-          <div class="panel-card card-3">
-            <div class="panel-title">缁煎悎缁熻</div>
-            <div class="stats-grid">
-              <div class="stat-item">
-                <div class="stat-label">鎬讳骇鑳�</div>
-                <div class="stat-value production-color">{{ totalProduction }}</div>
-                <div class="stat-unit">绔嬫柟绫�</div>
-              </div>
-              <div class="stat-item">
-                <div class="stat-label">鎬诲浐搴熷鐞�</div>
-                <div class="stat-value waste-color">{{ totalSolidWaste }}</div>
-                <div class="stat-unit">鍚�</div>
-              </div>
-              <div class="stat-item">
-                <div class="stat-label">骞冲潎鍗曡��</div>
-                <div class="stat-value consumption-color">{{ averageUnitConsumption }}</div>
-                <div class="stat-unit">鍚�/绔嬫柟绫�</div>
-              </div>
-              <div class="stat-item">
-                <div class="stat-label">鎬昏兘鑰�</div>
-                <div class="stat-value energy-color">{{ totalEnergy }}</div>
-                <div class="stat-unit">kWh</div>
-              </div>
-            </div>
+          <div class="chart-unit-row">
+            <span>鍗曚綅锛氫欢</span>
+          </div>
+          <div ref="productionChart"
+               class="echart-fill"></div>
+        </div>
+      </div>
+      <!-- 涓棿涓績鐜� -->
+      <div class="center-ring">
+        <div class="center-ring-box">
+          <div class="ring-box-topright">
+            <div class="topright-label">鍥哄簾澶勭悊閲�</div>
+          </div>
+          <div class="ring-box-left">
+            <div class="left-label">绮夌叅鐏�</div>
+            <div class="left-value">鏈堝鐞� <span style="font-weight: bold;font-size: 1.3vh;">{{ middleRingStats.flyAshMonth }}</span> 鍚� 骞村鐞� <span style="font-weight: bold;font-size: 1.3vh;">{{ middleRingStats.flyAshYear }}</span> 鍚�</div>
+            <div class="left-label"
+                 style="margin-top: 2vh;">鐭宠啅</div>
+            <div class="left-value">鏈堝鐞� <span style="font-weight: bold;font-size: 1.3vh;">{{ middleRingStats.gypsumMonth }}</span> 鍚� 骞村鐞� <span style="font-weight: bold;font-size: 1.3vh;">{{ middleRingStats.gypsumYear }}</span> 鍚�</div>
+          </div>
+          <div class="ring-box-topleft">
+            <div class="topleft-label">椤圭洰浜ч噺</div>
+          </div>
+          <div class="ring-box-right">
+            <div class="right-label">鐮屽潡浜ч噺</div>
+            <div class="right-value">鏈堜骇閲� <span style="font-weight: bold;font-size: 1.3vh;">{{ middleRingStats.blockMonth }}</span> 鍚� 骞翠骇閲� <span style="font-weight: bold;font-size: 1.3vh;">{{ middleRingStats.blockYear }}</span> 鍚�</div>
+            <div class="right-label"
+                 style="margin-top: 2vh;">鏉挎潗浜ч噺</div>
+            <div class="right-value">鏈堜骇閲� <span style="font-weight: bold;font-size: 1.3vh;">{{ middleRingStats.plateMonth }}</span> 鍚� 骞翠骇閲� <span style="font-weight: bold;font-size: 1.3vh;">{{ middleRingStats.plateYear }}</span> 鍚�</div>
           </div>
         </div>
-        <!-- 绗簩琛� -->
-        <div class="row row-2">
-          <div class="panel-card card-4">
-            <div class="panel-title">鐢熶骇鎴愭湰鍗曡��</div>
-            <div class="chart-container">
-              <div ref="costChart"
-                   style="width: 100%; height: 100%"></div>
-            </div>
-          </div>
-          <div class="panel-card card-5">
-            <div class="panel-title">鐢熶骇鑳借�楁暟鎹�</div>
-            <div class="chart-container">
-              <div ref="energyChart"
-                   style="width: 100%; height: 100%"></div>
-            </div>
-          </div>
+      </div>
+      <!-- 宸︿笅锛氱敓浜ф垚鏈崟鑰楃粺璁★紙鏉挎潗锛� -->
+      <div class="bi-panel bi-panel-bottom-left">
+        <PanelHeader :isFullscreen="true"
+                     title="鐢熶骇鎴愭湰鍗曡�楃粺璁★紙鏉挎潗锛�" />
+        <div class="panel-tabs">
+          <span class="tab-item"
+                :class="{ active: boardTimeDimension === 'year' }"
+                @click="handleBoardTimeDimensionChange('year')">骞�</span>
+          <span class="tab-item"
+                :class="{ active: boardTimeDimension === 'month' }"
+                @click="handleBoardTimeDimensionChange('month')">鏈�</span>
         </div>
-        <!-- 绗笁琛� -->
-        <div class="row row-3">
-          <div class="panel-card card-6">
-            <div class="panel-title">鍗曡�楁暟鎹槑缁�</div>
-            <div class="table-container">
-              <el-table :data="costTableData"
-                        style="width: 100%">
-                <el-table-column prop="material"
-                                 label="鐗╂枡绫诲瀷"
-                                 width="120"
-                                 align="center">
-                  <template #default="scope">
-                    <el-tag :type="getMaterialTypeType(scope.row.material)">
-                      {{ scope.row.material }}
-                    </el-tag>
-                  </template>
-                </el-table-column>
-                <el-table-column prop="unit"
-                                 label="鍗曚綅"
-                                 width="100" />
-                <el-table-column prop="monthlyConsumption"
-                                 label="鏈堝害绱鐢ㄩ噺"
-                                 align="right">
-                  <template #default="scope">
-                    <span class="data-value">{{ scope.row.monthlyConsumption }}</span>
-                  </template>
-                </el-table-column>
-                <el-table-column prop="monthlyProduction"
-                                 label="鏈堝害绱浜ч噺"
-                                 align="right">
-                  <template #default="scope">
-                    <span class="data-value">{{ scope.row.monthlyProduction }}</span>
-                  </template>
-                </el-table-column>
-                <el-table-column prop="monthlyUnitConsumption"
-                                 label="鏈堝害绱鍗曡��"
-                                 align="right">
-                  <template #default="scope">
-                    <span class="data-value">{{ scope.row.monthlyUnitConsumption }}</span>
-                  </template>
-                </el-table-column>
-                <el-table-column prop="yearlyConsumption"
-                                 label="骞村害绱鐢ㄩ噺"
-                                 align="right">
-                  <template #default="scope">
-                    <span class="data-value">{{ scope.row.yearlyConsumption }}</span>
-                  </template>
-                </el-table-column>
-                <el-table-column prop="yearlyProduction"
-                                 label="骞村害绱浜ч噺"
-                                 align="right">
-                  <template #default="scope">
-                    <span class="data-value">{{ scope.row.yearlyProduction }}</span>
-                  </template>
-                </el-table-column>
-                <el-table-column prop="yearlyUnitConsumption"
-                                 label="骞村害绱鍗曡��"
-                                 align="right">
-                  <template #default="scope">
-                    <span class="data-value">{{ scope.row.yearlyUnitConsumption }}</span>
-                  </template>
-                </el-table-column>
-              </el-table>
+        <div class="bi-panel-body">
+          <div class="chart-filter-tabs">
+            <span v-for="name in boardMaterialList"
+                  :key="name"
+                  class="cf-tab"
+                  :class="{ active: boardSelectedMaterial === name }"
+                  @click="selectBoardMaterial(name)">{{ name }}</span>
+          </div>
+          <div v-if="boardSelectedMaterial !== '鍏ㄩ儴'"
+               class="material-info-card">
+            <div class="material-icon">
+              <svg width="24"
+                   height="24"
+                   viewBox="0 0 24 24"
+                   fill="none"
+                   stroke="currentColor"
+                   stroke-width="2">
+                <path d="M20 7h-4V4c0-1.1-.9-2-2-2h-4c-1.1 0-2 .9-2 2v3H4c-1.1 0-2 .9-2 2v11c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2z" />
+                <polyline points="22,7 12,13 2,7" />
+              </svg>
+            </div>
+            <div class="material-details">
+              <div class="material-name">{{ boardMaterialSummary.materialName || "鈥�" }}</div>
+              <div class="material-stats">
+                <div class="stat-item">
+                  <span class="stat-label">鏈堢疮璁″崟鑰�</span>
+                  <span class="stat-value">{{ boardMaterialSummary.monthlyConsumption }}</span>
+                  <span class="stat-unit">鍚�</span>
+                </div>
+                <div class="stat-item">
+                  <span class="stat-label">骞寸疮璁″崟鑰�</span>
+                  <span class="stat-value">{{ boardMaterialSummary.yearlyConsumption }}</span>
+                  <span class="stat-unit">鍚�</span>
+                </div>
+              </div>
             </div>
           </div>
+          <!-- <div class="chart-unit-row">
+            <span>鍗曚綅锛氱珛鏂圭背</span>
+          </div> -->
+          <div ref="boardCostChart"
+               class="echart-fill"></div>
+        </div>
+      </div>
+      <!-- 涓笅锛氭柊澧炲鎴疯秼鍔垮垎鏋� -->
+      <div class="bi-panel bi-panel-bottom-center">
+        <PanelHeader :isFullscreen="true"
+                     title="鍥哄簾澶勭悊閲�" />
+        <div class="panel-tabs">
+          <span class="tab-item"
+                :class="{ active: customerTimeDimension === 'year' }"
+                @click="handleCustomerTimeDimensionChange('year')">骞�</span>
+          <span class="tab-item"
+                :class="{ active: customerTimeDimension === 'month' }"
+                @click="handleCustomerTimeDimensionChange('month')">鏈�</span>
+        </div>
+        <div ref="customerTrendChart"
+             class="echart-fill"></div>
+        <!-- <div class="bi-panel-body">
+          <div class="chart-unit-row chart-unit-single">
+            <span>鍗曚綅锛氬</span>
+          </div>
+          <div ref="customerTrendChart"
+               class="echart-fill"></div>
+        </div> -->
+      </div>
+      <!-- 鍙充笅锛氶攢閲忔帓鍚嶅垎鏋� -->
+      <div class="bi-panel bi-panel-bottom-right">
+        <PanelHeader :isFullscreen="true"
+                     title="鑳借�楃粺璁�" />
+        <div class="panel-tabs">
+          <span class="tab-item"
+                :class="{ active: salesTimeDimension === 'year' }"
+                @click="handleSalesTimeDimensionChange('year')">骞�</span>
+          <span class="tab-item"
+                :class="{ active: salesTimeDimension === 'month' }"
+                @click="handleSalesTimeDimensionChange('month')">鏈�</span>
+        </div>
+        <div class="bi-panel-body">
+          <div ref="salesRankingChart"
+               class="echart-fill"></div>
         </div>
       </div>
     </div>
@@ -165,839 +255,2112 @@
     onMounted,
     onBeforeUnmount,
     nextTick,
-    watch,
   } from "vue";
   import * as echarts from "echarts";
+  import dayjs from "dayjs";
+  import PanelHeader from "@/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue";
+  import {
+    getMaterialProductionAnalysis,
+    getProductionMaterials,
+    getProductionStatisticsBlocks,
+    getProductionStatisticsPlates,
+    getProductionStatisticsMiddle,
+    getProductionStatisticsSolidWaste,
+    getProductionStatisticsEnergy,
+  } from "@/api/reportAnalysis/productionStatistics.js";
 
-  // 绛涢�夋潯浠�
-  const dateType = ref("month"); // month 鎴� year
-  const productType = ref("block"); // block 鎴� plate
+  const screenRoot = ref(null);
+  const isFullscreen = ref(false);
 
-  // 鍥捐〃寮曠敤
-  const productionChart = ref(null);
-  const solidWasteChart = ref(null);
-  const costChart = ref(null);
-  const energyChart = ref(null);
-
-  // 鍥捐〃瀹炰緥
-  let productionChartInstance = null;
-  let solidWasteChartInstance = null;
-  let costChartInstance = null;
-  let energyChartInstance = null;
-
-  // 妯℃嫙鏁版嵁
-  const productionData = ref({
-    month: [
-      { name: "1鏈�", block: 1200, plate: 800 },
-      { name: "2鏈�", block: 1300, plate: 850 },
-      { name: "3鏈�", block: 1100, plate: 750 },
-      { name: "4鏈�", block: 1400, plate: 900 },
-      { name: "5鏈�", block: 1500, plate: 950 },
-      { name: "6鏈�", block: 1350, plate: 880 },
-      { name: "7鏈�", block: 1450, plate: 920 },
-      { name: "8鏈�", block: 1600, plate: 1000 },
-      { name: "9鏈�", block: 1550, plate: 980 },
-      { name: "10鏈�", block: 1700, plate: 1050 },
-      { name: "11鏈�", block: 1650, plate: 1020 },
-      { name: "12鏈�", block: 1800, plate: 1100 },
-    ],
-    year: [
-      { name: "2023", block: 15000, plate: 9500 },
-      { name: "2024", block: 16500, plate: 10200 },
-      { name: "2025", block: 18000, plate: 11000 },
-    ],
-  });
-
-  const solidWasteData = ref({
-    month: [
-      { name: "1鏈�", 绮夌叅鐏�: 200, 鐭宠啅: 150, 鐭崇伆: 100 },
-      { name: "2鏈�", 绮夌叅鐏�: 220, 鐭宠啅: 160, 鐭崇伆: 110 },
-      { name: "3鏈�", 绮夌叅鐏�: 190, 鐭宠啅: 140, 鐭崇伆: 95 },
-      { name: "4鏈�", 绮夌叅鐏�: 230, 鐭宠啅: 170, 鐭崇伆: 115 },
-      { name: "5鏈�", 绮夌叅鐏�: 240, 鐭宠啅: 180, 鐭崇伆: 120 },
-      { name: "6鏈�", 绮夌叅鐏�: 225, 鐭宠啅: 165, 鐭崇伆: 112 },
-    ],
-    year: [
-      { name: "2023", 绮夌叅鐏�: 2500, 鐭宠啅: 1800, 鐭崇伆: 1200 },
-      { name: "2024", 绮夌叅鐏�: 2700, 鐭宠啅: 1950, 鐭崇伆: 1300 },
-      { name: "2025", 绮夌叅鐏�: 2900, 鐭宠啅: 2100, 鐭崇伆: 1400 },
-    ],
-  });
-
-  const costData = ref({
-    materials: ["姘存偿", "閾濈矇鑶�", "鑴辨ā鍓�", "闃茶厫鍓�", "姘寲鍓�", "鍐锋嫈涓�"],
-    month: {
-      consumption: [1200, 50, 80, 30, 40, 60],
-      production: [12000, 12000, 12000, 8000, 8000, 8000],
-      unitConsumption: [0.1, 0.0042, 0.0067, 0.0038, 0.005, 0.0075],
-    },
-    year: {
-      consumption: [14000, 600, 950, 350, 480, 720],
-      production: [140000, 140000, 140000, 95000, 95000, 95000],
-      unitConsumption: [0.1, 0.0043, 0.0068, 0.0037, 0.0051, 0.0076],
-    },
-  });
-
-  const energyData = ref({
-    month: [
-      { name: "1鏈�", 鐢甸噺: 12000, 姘撮噺: 8000, 姘旈噺: 5000 },
-      { name: "2鏈�", 鐢甸噺: 13000, 姘撮噺: 8500, 姘旈噺: 5500 },
-      { name: "3鏈�", 鐢甸噺: 11000, 姘撮噺: 7500, 姘旈噺: 4800 },
-      { name: "4鏈�", 鐢甸噺: 14000, 姘撮噺: 9000, 姘旈噺: 6000 },
-      { name: "5鏈�", 鐢甸噺: 15000, 姘撮噺: 9500, 姘旈噺: 6500 },
-      { name: "6鏈�", 鐢甸噺: 13500, 姘撮噺: 8800, 姘旈噺: 5800 },
-    ],
-    year: [
-      { name: "2023", 鐢甸噺: 140000, 姘撮噺: 95000, 姘旈噺: 65000 },
-      { name: "2024", 鐢甸噺: 150000, 姘撮噺: 100000, 姘旈噺: 70000 },
-      { name: "2025", 鐢甸噺: 160000, 姘撮噺: 105000, 姘旈噺: 75000 },
-    ],
-  });
-
-  // 璁$畻灞炴��
-  const productionChartOption = computed(() => {
-    const data = productionData.value[dateType.value];
-    return {
-      tooltip: {
-        trigger: "axis",
-        axisPointer: {
-          type: "shadow",
-        },
-      },
-      legend: {
-        data: ["鐮屽潡", "鏉挎潗"],
-        textStyle: {
-          color: "#333",
-        },
-      },
-      grid: {
-        left: "3%",
-        right: "4%",
-        bottom: "3%",
-        containLabel: true,
-      },
-      xAxis: {
-        type: "category",
-        data: data.map(item => item.name),
-        axisLabel: {
-          color: "#333",
-        },
-      },
-      yAxis: {
-        type: "value",
-        name: "浜ч噺 (绔嬫柟绫�)",
-        axisLabel: {
-          color: "#333",
-        },
-      },
-      series: [
-        {
-          name: "鐮屽潡",
-          type: "line",
-          data: data.map(item => item.block),
-          smooth: true,
-          lineStyle: {
-            width: 3,
-          },
-          itemStyle: {
-            color: "#409EFF",
-          },
-        },
-        {
-          name: "鏉挎潗",
-          type: "line",
-          data: data.map(item => item.plate),
-          smooth: true,
-          lineStyle: {
-            width: 3,
-          },
-          itemStyle: {
-            color: "#67C23A",
-          },
-        },
-      ],
+  // 椤堕儴鏍忔椂闂�
+  const now = ref(dayjs());
+  const currentTime = computed(() => now.value.format("HH:mm:ss"));
+  const currentDateText = computed(() => {
+    const weekMap = {
+      0: "鏄熸湡鏃�",
+      1: "鏄熸湡涓�",
+      2: "鏄熸湡浜�",
+      3: "鏄熸湡涓�",
+      4: "鏄熸湡鍥�",
+      5: "鏄熸湡浜�",
+      6: "鏄熸湡鍏�",
     };
+    return `${now.value.format("YYYY-MM-DD")} ${weekMap[now.value.day()] || ""}`;
   });
+  let timeTicker = null;
 
-  const solidWasteChartOption = computed(() => {
-    const data = solidWasteData.value[dateType.value];
-    return {
-      tooltip: {
-        trigger: "axis",
-        axisPointer: {
-          type: "shadow",
-        },
-      },
-      legend: {
-        data: ["绮夌叅鐏�", "鐭宠啅", "鐭崇伆"],
-        textStyle: {
-          color: "#333",
-        },
-      },
-      grid: {
-        left: "3%",
-        right: "4%",
-        bottom: "3%",
-        containLabel: true,
-      },
-      xAxis: {
-        type: "category",
-        data: data.map(item => item.name),
-        axisLabel: {
-          color: "#333",
-        },
-      },
-      yAxis: {
-        type: "value",
-        name: "澶勭悊閲� (鍚�)",
-        axisLabel: {
-          color: "#333",
-        },
-      },
-      series: [
-        {
-          name: "绮夌叅鐏�",
-          type: "bar",
-          data: data.map(item => item.绮夌叅鐏�),
-          itemStyle: {
-            color: "#909399",
-          },
-        },
-        {
-          name: "鐭宠啅",
-          type: "bar",
-          data: data.map(item => item.鐭宠啅),
-          itemStyle: {
-            color: "#E6A23C",
-          },
-        },
-        {
-          name: "鐭崇伆",
-          type: "bar",
-          data: data.map(item => item.鐭崇伆),
-          itemStyle: {
-            color: "#F56C6C",
-          },
-        },
-      ],
-    };
-  });
-
-  const costChartOption = computed(() => {
-    const data = costData.value;
-    return {
-      tooltip: {
-        trigger: "axis",
-        axisPointer: {
-          type: "shadow",
-        },
-      },
-      legend: {
-        data: ["鏈堝害鍗曡��", "骞村害鍗曡��"],
-        textStyle: {
-          color: "#333",
-        },
-      },
-      grid: {
-        left: "3%",
-        right: "4%",
-        bottom: "3%",
-        containLabel: true,
-      },
-      xAxis: {
-        type: "category",
-        data: data.materials,
-        axisLabel: {
-          color: "#333",
-          rotate: 45,
-        },
-      },
-      yAxis: {
-        type: "value",
-        name: "鍗曡�� (鍚�/绔嬫柟绫�)",
-        axisLabel: {
-          color: "#333",
-        },
-      },
-      series: [
-        {
-          name: "鏈堝害鍗曡��",
-          type: "bar",
-          data: data.month.unitConsumption,
-          itemStyle: {
-            color: "#409EFF",
-          },
-        },
-        {
-          name: "骞村害鍗曡��",
-          type: "bar",
-          data: data.year.unitConsumption,
-          itemStyle: {
-            color: "#67C23A",
-          },
-        },
-      ],
-    };
-  });
-
-  const energyChartOption = computed(() => {
-    const data = energyData.value[dateType.value];
-    return {
-      tooltip: {
-        trigger: "axis",
-        axisPointer: {
-          type: "shadow",
-        },
-      },
-      legend: {
-        data: ["鐢甸噺", "姘撮噺", "姘旈噺"],
-        textStyle: {
-          color: "#333",
-        },
-      },
-      grid: {
-        left: "3%",
-        right: "4%",
-        bottom: "3%",
-        containLabel: true,
-      },
-      xAxis: {
-        type: "category",
-        data: data.map(item => item.name),
-        axisLabel: {
-          color: "#333",
-        },
-      },
-      yAxis: {
-        type: "value",
-        name: "鑳借�楅噺",
-        axisLabel: {
-          color: "#333",
-        },
-      },
-      series: [
-        {
-          name: "鐢甸噺",
-          type: "line",
-          data: data.map(item => item.鐢甸噺),
-          smooth: true,
-          lineStyle: {
-            width: 3,
-          },
-          itemStyle: {
-            color: "#409EFF",
-          },
-        },
-        {
-          name: "姘撮噺",
-          type: "line",
-          data: data.map(item => item.姘撮噺),
-          smooth: true,
-          lineStyle: {
-            width: 3,
-          },
-          itemStyle: {
-            color: "#67C23A",
-          },
-        },
-        {
-          name: "姘旈噺",
-          type: "line",
-          data: data.map(item => item.姘旈噺),
-          smooth: true,
-          lineStyle: {
-            width: 3,
-          },
-          itemStyle: {
-            color: "#E6A23C",
-          },
-        },
-      ],
-    };
-  });
-
-  const costTableData = computed(() => {
-    const data = costData.value;
-    const materials = data.materials;
-    const monthData = data.month;
-    const yearData = data.year;
-
-    return materials.map((material, index) => ({
-      material,
-      unit: "鍚�/绔嬫柟绫�",
-      monthlyConsumption: monthData.consumption[index],
-      monthlyProduction: monthData.production[index],
-      monthlyUnitConsumption: monthData.unitConsumption[index].toFixed(4),
-      yearlyConsumption: yearData.consumption[index],
-      yearlyProduction: yearData.production[index],
-      yearlyUnitConsumption: yearData.unitConsumption[index].toFixed(4),
-    }));
-  });
-
-  const totalProduction = computed(() => {
-    const data = productionData.value[dateType.value];
-    if (dateType.value === "month") {
-      return data.reduce(
-        (sum, item) =>
-          sum + item[productType.value === "block" ? "block" : "plate"],
-        0
-      );
-    } else {
-      return data[data.length - 1][
-        productType.value === "block" ? "block" : "plate"
-      ];
-    }
-  });
-
-  const totalSolidWaste = computed(() => {
-    const data = solidWasteData.value[dateType.value];
-    if (dateType.value === "month") {
-      return data.reduce(
-        (sum, item) => sum + item.绮夌叅鐏� + item.鐭宠啅 + item.鐭崇伆,
-        0
-      );
-    } else {
-      const lastItem = data[data.length - 1];
-      return lastItem.绮夌叅鐏� + lastItem.鐭宠啅 + lastItem.鐭崇伆;
-    }
-  });
-
-  const averageUnitConsumption = computed(() => {
-    const data = costData.value;
-    const unitConsumption =
-      dateType.value === "month"
-        ? data.month.unitConsumption
-        : data.year.unitConsumption;
-    const average =
-      unitConsumption.reduce((sum, value) => sum + value, 0) /
-      unitConsumption.length;
-    return average.toFixed(4);
-  });
-
-  const totalEnergy = computed(() => {
-    const data = energyData.value[dateType.value];
-    if (dateType.value === "month") {
-      return data.reduce(
-        (sum, item) => sum + item.鐢甸噺 + item.姘撮噺 + item.姘旈噺,
-        0
-      );
-    } else {
-      const lastItem = data[data.length - 1];
-      return lastItem.鐢甸噺 + lastItem.姘撮噺 + lastItem.姘旈噺;
-    }
-  });
-
-  // 浜嬩欢澶勭悊
-  const handleDateTypeChange = () => {
-    updateCharts();
+  const handleFullscreenChange = () => {
+    isFullscreen.value = !!document.fullscreenElement;
+    nextTick(() => {
+      handleResize();
+    });
   };
 
-  const handleProductTypeChange = () => {
-    updateCharts();
+  const toggleFullscreen = async () => {
+    const rootEl = screenRoot.value;
+    if (!rootEl) return;
+    try {
+      if (!document.fullscreenElement) {
+        await rootEl.requestFullscreen();
+      } else {
+        await document.exitFullscreen();
+      }
+    } catch (error) {
+      console.error("鍏ㄥ睆鍒囨崲澶辫触:", error);
+    }
+  };
+
+  // 鍥捐〃寮曠敤
+  const blockCostChart = ref(null);
+  const boardCostChart = ref(null);
+  const productionChart = ref(null);
+  const customerTrendChart = ref(null);
+  const salesRankingChart = ref(null);
+
+  // 閫夋嫨鍣ㄦ暟鎹�
+  const blockTimeDimension = ref("year");
+  const boardTimeDimension = ref("year");
+  const productionTimeDimension = ref("year");
+  const customerTimeDimension = ref("year");
+  const salesTimeDimension = ref("year");
+
+  const productionCategories = ["鍏ㄩ儴", "鐮屽潡", "鏉挎潗"];
+  const productionCategory = ref("鍏ㄩ儴");
+
+  const blockMaterialList = ref([]);
+  const blockSelectedMaterial = ref("");
+  const boardMaterialList = ref([]);
+  const boardSelectedMaterial = ref("");
+
+  const blockMaterialSummary = ref({
+    materialName: "",
+    monthlyConsumption: "--",
+    yearlyConsumption: "--",
+  });
+  const boardMaterialSummary = ref({
+    materialName: "",
+    monthlyConsumption: "--",
+    yearlyConsumption: "--",
+  });
+
+  /** xMode: time=妯酱涓烘椂闂达紱material=閫夈�屽叏閮ㄣ�嶆椂妯酱涓哄悇鐗╂枡鍚嶇О */
+  const blockCostChartSeries = ref({
+    xMode: "time",
+    categories: [],
+    input: [],
+    output: [],
+  });
+  const boardCostChartSeries = ref({
+    xMode: "time",
+    categories: [],
+    input: [],
+    output: [],
+  });
+  const productionChartSeries = ref({
+    categories: [],
+    /** single锛氬崟绾匡紱dual锛氬叏閮ㄦ椂鐮屽潡+鏉挎潗鍙岀嚎 */
+    mode: "single",
+    values: [],
+    blockValues: [],
+    plateValues: [],
+  });
+
+  // 鍥哄簾澶勭悊閲忔姌绾垮浘锛�/home/productionStatistics/solidWaste锛�
+  const solidWasteChartSeries = ref({
+    categories: [],
+    total: [],
+    flyAsh: [],
+    gypsum: [],
+    lime: [],
+  });
+
+  // 鑳借�楃粺璁★紙/home/productionStatistics/energy锛�
+  const energyChartSeries = ref({
+    categories: [],
+    water: [],
+    electricity: [],
+    steam: [],
+  });
+
+  // 涓績鐜細鍥哄簾锛堢矇鐓ょ伆/鐭宠啅锛�+ 椤圭洰浜ч噺锛堢爩鍧�/鏉挎潗锛夛紝鎺ュ彛 /home/productionStatistics/middle
+  const middleRingStats = ref({
+    flyAshMonth: 0,
+    flyAshYear: 0,
+    gypsumMonth: 0,
+    gypsumYear: 0,
+    blockMonth: 0,
+    blockYear: 0,
+    plateMonth: 0,
+    plateYear: 0,
+  });
+
+  // 鍥捐〃瀹炰緥
+  let blockCostChartInstance = null;
+  let boardCostChartInstance = null;
+  let productionChartInstance = null;
+  let customerTrendChartInstance = null;
+  let salesRankingChartInstance = null;
+  let blockCostChartResizeObserver = null;
+  let boardCostChartResizeObserver = null;
+
+  // 鐢熶骇鍗曡�楀浘琛ㄩ厤缃紙鐮屽潡锛屾帴鍙f暟鎹級
+  const blockCostChartOption = computed(() => {
+    const xMode = blockCostChartSeries.value.xMode || "time";
+    const periods = blockCostChartSeries.value.categories || [];
+    const inputData = blockCostChartSeries.value.input || [];
+    const outputData = blockCostChartSeries.value.output || [];
+    const legendNames = ["鎶曞叆閲�", "浜у嚭閲�"];
+    const colors = ["#6B9DFF", "#8A6BFF"];
+    const series = [
+      {
+        name: legendNames[0],
+        data: inputData,
+        type: "bar",
+        itemStyle: { color: colors[0] },
+      },
+      {
+        name: legendNames[1],
+        data: outputData,
+        type: "bar",
+        itemStyle: { color: colors[1] },
+      },
+    ];
+
+    return {
+      backgroundColor: "transparent",
+      tooltip: {
+        trigger: "axis",
+        backgroundColor: "rgba(0,0,0,0.55)",
+        borderColor: "rgba(64,158,255,0.25)",
+        borderWidth: getResponsiveValue(1),
+        textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
+      },
+      legend: {
+        data: legendNames,
+        top: "2%",
+        right: "1%",
+        textStyle: {
+          color: "#B8C8E0",
+          fontSize: getResponsiveValue(9),
+        },
+        itemWidth: getResponsiveValue(10),
+        itemHeight: getResponsiveValue(10),
+      },
+      grid: {
+        left: "1%",
+        right: "1%",
+        top: "18%",
+        bottom: xMode === "material" ? "0%" : "1%",
+        containLabel: true,
+      },
+      xAxis: {
+        type: "category",
+        data: periods,
+        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
+        axisTick: { show: false },
+        axisLabel: {
+          color: "#B8C8E0",
+          fontSize: getResponsiveValue(11),
+          margin:
+            xMode === "material"
+              ? getResponsiveValue(6)
+              : getResponsiveValue(10),
+          rotate: xMode === "material" && periods.length > 5 ? 28 : 0,
+          interval: 0,
+        },
+        splitLine: { show: false },
+      },
+      yAxis: {
+        type: "value",
+        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
+        axisLabel: {
+          color: "#B8C8E0",
+          fontSize: getResponsiveValue(11),
+          margin: getResponsiveValue(8),
+        },
+        splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
+      },
+      series,
+    };
+  });
+
+  // 鏉挎潗鍗曡�楀浘琛ㄩ厤缃紙鎺ュ彛鏁版嵁锛屼笌鐮屽潡缁撴瀯涓�鑷达級
+  const boardCostChartOption = computed(() => {
+    const xMode = boardCostChartSeries.value.xMode || "time";
+    const periods = boardCostChartSeries.value.categories || [];
+    const inputData = boardCostChartSeries.value.input || [];
+    const outputData = boardCostChartSeries.value.output || [];
+    const legendNames = ["鎶曞叆閲�", "浜у嚭閲�"];
+    const colors = ["#00A4ED", "#34D8F7"];
+    const series = [
+      {
+        name: legendNames[0],
+        data: inputData,
+        type: "bar",
+        itemStyle: { color: colors[0] },
+      },
+      {
+        name: legendNames[1],
+        data: outputData,
+        type: "bar",
+        itemStyle: { color: colors[1] },
+      },
+    ];
+
+    return {
+      backgroundColor: "transparent",
+      tooltip: {
+        trigger: "axis",
+        backgroundColor: "rgba(0,0,0,0.55)",
+        borderColor: "rgba(64,158,255,0.25)",
+        borderWidth: getResponsiveValue(1),
+        textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
+      },
+      legend: {
+        data: legendNames,
+        top: "2%",
+        right: "1%",
+        textStyle: {
+          color: "#B8C8E0",
+          fontSize: getResponsiveValue(9),
+        },
+        itemWidth: getResponsiveValue(10),
+        itemHeight: getResponsiveValue(10),
+      },
+      grid: {
+        left: "1%",
+        right: "1%",
+        top: "18%",
+        bottom: xMode === "material" ? "0%" : "1%",
+        containLabel: true,
+      },
+      xAxis: {
+        type: "category",
+        data: periods,
+        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
+        axisTick: { show: false },
+        axisLabel: {
+          color: "#B8C8E0",
+          fontSize: getResponsiveValue(11),
+          margin:
+            xMode === "material"
+              ? getResponsiveValue(6)
+              : getResponsiveValue(10),
+          rotate: xMode === "material" && periods.length > 5 ? 28 : 0,
+          interval: 0,
+        },
+        splitLine: { show: false },
+      },
+      yAxis: {
+        type: "value",
+        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
+        axisLabel: {
+          color: "#B8C8E0",
+          fontSize: getResponsiveValue(11),
+          margin: getResponsiveValue(8),
+        },
+        splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
+      },
+      series,
+    };
+  });
+
+  // 鐗╂枡鐢熶骇閲忓垎鏋愶紙鎺ュ彛鏁版嵁锛�
+  const productionChartOption = computed(() => {
+    const periods = productionChartSeries.value.categories || [];
+    const mode = productionChartSeries.value.mode || "single";
+    const blockLineColor = "#4A8BFF";
+    const plateLineColor = "#52C9A0";
+
+    const buildAreaLine = (name, data, lineColor) => ({
+      name,
+      data,
+      type: "line",
+      smooth: true,
+      lineStyle: { width: getResponsiveValue(2), color: lineColor },
+      itemStyle: { color: lineColor },
+      areaStyle: {
+        opacity: 0.3,
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          { offset: 0, color: lineColor + "80" },
+          { offset: 1, color: lineColor + "00" },
+        ]),
+      },
+    });
+
+    let series;
+    if (mode === "dual") {
+      series = [
+        buildAreaLine(
+          "鐮屽潡",
+          productionChartSeries.value.blockValues || [],
+          blockLineColor
+        ),
+        buildAreaLine(
+          "鏉挎潗",
+          productionChartSeries.value.plateValues || [],
+          plateLineColor
+        ),
+      ];
+    } else {
+      const cat = productionCategory.value;
+      const seriesName = cat === "鐮屽潡" ? "鐮屽潡" : "鏉挎潗";
+      series = [
+        buildAreaLine(
+          seriesName,
+          productionChartSeries.value.values || [],
+          blockLineColor
+        ),
+      ];
+    }
+
+    return {
+      backgroundColor: "transparent",
+      tooltip: {
+        trigger: "axis",
+        backgroundColor: "rgba(0,0,0,0.55)",
+        borderColor: "rgba(64,158,255,0.25)",
+        borderWidth: getResponsiveValue(1),
+        textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
+      },
+      legend: { show: false },
+      grid: {
+        left: "1%",
+        right: "1%",
+        bottom: "1%",
+        top: "10%",
+        containLabel: true,
+      },
+      xAxis: {
+        type: "category",
+        data: periods,
+        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
+        axisTick: { show: false },
+        axisLabel: {
+          color: "#B8C8E0",
+          fontSize: getResponsiveValue(11),
+          margin: getResponsiveValue(10),
+        },
+        splitLine: { show: false },
+      },
+      yAxis: {
+        type: "value",
+        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
+        axisLabel: {
+          color: "#B8C8E0",
+          fontSize: getResponsiveValue(11),
+          margin: getResponsiveValue(8),
+        },
+        splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
+      },
+      series,
+    };
+  });
+
+  // 鍥哄簾澶勭悊閲忓浘琛紙鎺ュ彛 solidWaste锛�
+  const customerTrendChartOption = computed(() => {
+    const legendNames = ["鍏ㄩ儴", "绮夌叅鐏�", "鐭宠啅", "鐭崇伆"];
+    const colors = ["#00A4ED", "#4A8BFF", "#8A6BFF", "#C8C447"];
+    const periods = solidWasteChartSeries.value.categories || [];
+    const dataBySeries = [
+      solidWasteChartSeries.value.total || [],
+      solidWasteChartSeries.value.flyAsh || [],
+      solidWasteChartSeries.value.gypsum || [],
+      solidWasteChartSeries.value.lime || [],
+    ];
+
+    const series = legendNames.map((name, index) => ({
+      name,
+      data: dataBySeries[index] || [],
+      type: "line",
+      smooth: true,
+      lineStyle: { width: getResponsiveValue(2), color: colors[index] },
+      itemStyle: { color: colors[index] },
+      areaStyle: {
+        opacity: 0.3,
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          { offset: 0, color: colors[index] + "80" },
+          { offset: 1, color: colors[index] + "00" },
+        ]),
+      },
+    }));
+
+    return {
+      backgroundColor: "transparent",
+      tooltip: {
+        trigger: "axis",
+        backgroundColor: "rgba(0,0,0,0.55)",
+        borderColor: "rgba(64,158,255,0.25)",
+        borderWidth: getResponsiveValue(1),
+        textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
+      },
+      legend: {
+        data: legendNames,
+        top: "10%",
+        right: "1%",
+        textStyle: {
+          color: "#B8C8E0",
+          fontSize: getResponsiveValue(9),
+        },
+        itemWidth: getResponsiveValue(10),
+        itemHeight: getResponsiveValue(10),
+      },
+      grid: {
+        left: "1%",
+        right: "1%",
+        bottom: "1%",
+        top: "28%",
+        containLabel: true,
+      },
+      xAxis: {
+        type: "category",
+        data: periods,
+        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
+        axisTick: { show: false },
+        axisLabel: {
+          color: "#B8C8E0",
+          fontSize: getResponsiveValue(11),
+          margin: getResponsiveValue(10),
+        },
+        splitLine: { show: false },
+      },
+      yAxis: {
+        type: "value",
+        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
+        axisLabel: {
+          color: "#B8C8E0",
+          fontSize: getResponsiveValue(11),
+          margin: getResponsiveValue(8),
+        },
+        splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
+      },
+      series,
+    };
+  });
+
+  // 鑳借�楃粺璁″浘琛ㄩ厤缃紙鎺ュ彛 energy锛�
+  const salesRankingChartOption = computed(() => {
+    const energyTypes = ["姘�", "鐢�", "钂告苯"];
+    const periodType = salesTimeDimension.value;
+    const periods = energyChartSeries.value.categories || [];
+    const waterData = energyChartSeries.value.water || [];
+    const electricityData = energyChartSeries.value.electricity || [];
+    const steamData = energyChartSeries.value.steam || [];
+
+    const series = [
+      {
+        name: "姘�",
+        type: "bar",
+        data: waterData,
+        itemStyle: {
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: "#00A4ED" },
+            { offset: 1, color: "#0F285A" },
+          ]),
+          borderRadius: [getResponsiveValue(4), getResponsiveValue(4), 0, 0],
+        },
+        barWidth: getResponsiveValue(6),
+      },
+      {
+        name: "鐢�",
+        type: "line",
+        data: electricityData,
+        itemStyle: {
+          color: "#AC43C2",
+        },
+        lineStyle: {
+          width: getResponsiveValue(1),
+          color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+            { offset: 0, color: "#AC43C2" },
+            { offset: 1, color: "#AC43C2" },
+          ]),
+        },
+        symbol: "circle",
+        symbolSize: getResponsiveValue(8),
+        areaStyle: {
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: "#AC43C250" },
+            { offset: 1, color: "#AC43C203" },
+          ]),
+        },
+      },
+      {
+        name: "钂告苯",
+        type: "bar",
+        data: steamData,
+        itemStyle: {
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: "#F5BC4A" },
+            { offset: 1, color: "#591C22" },
+          ]),
+          borderRadius: [getResponsiveValue(4), getResponsiveValue(4), 0, 0],
+        },
+        barWidth: getResponsiveValue(6),
+      },
+    ];
+
+    return {
+      tooltip: {
+        trigger: "axis",
+        axisPointer: { type: "cross" },
+        backgroundColor: "rgba(0,0,0,0.7)",
+        borderColor: "rgba(64,158,255,0.5)",
+        borderWidth: getResponsiveValue(1),
+        textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(12) },
+        formatter: function (params) {
+          let result = params[0].name + "<br/>";
+          params.forEach(param => {
+            const unit = param.seriesName === "鐢�" ? "搴�" : "鍚�";
+            result += `${param.marker}${param.seriesName}: ${param.value} ${unit}<br/>`;
+          });
+          return result;
+        },
+      },
+      legend: {
+        data: energyTypes,
+        top: "5%",
+        right: "1%",
+        textStyle: {
+          color: "#B8C8E0",
+          fontSize: getResponsiveValue(10),
+        },
+        itemWidth: getResponsiveValue(12),
+        itemHeight: getResponsiveValue(12),
+        itemGap: getResponsiveValue(15),
+      },
+      grid: {
+        left: "1%",
+        right: "1%",
+        top: "25%",
+        bottom: "0%",
+        containLabel: true,
+      },
+      xAxis: {
+        type: "category",
+        data: periods,
+        axisLabel: {
+          fontSize: getResponsiveValue(11),
+          color: "#93B9FF",
+          interval: 0,
+          rotate: periodType === "month" ? 45 : 0,
+        },
+        axisLine: {
+          show: true,
+          lineStyle: {
+            width: getResponsiveValue(1),
+            color: "#305B9A",
+          },
+        },
+        axisTick: {
+          show: false,
+        },
+      },
+      yAxis: {
+        type: "value",
+        axisLabel: {
+          fontSize: getResponsiveValue(11),
+          color: "#93B9FF",
+          formatter: function (value) {
+            return value;
+          },
+        },
+        axisLine: {
+          show: true,
+          lineStyle: {
+            color: "#305B9A",
+          },
+        },
+        splitLine: {
+          lineStyle: {
+            color: "#0F2E60",
+            type: "dashed",
+          },
+        },
+      },
+      series: series,
+    };
+  });
+
+  const baseWidth = ref(1650);
+  // 璁$畻鍝嶅簲寮忓��
+  const getResponsiveValue = baseValue => {
+    return Math.round((baseValue * window.innerWidth) / baseWidth.value);
+  };
+
+  const mapTimeDimensionToDateType = dim => (dim === "year" ? "2" : "1");
+
+  const productionOutputKey = {
+    鍏ㄩ儴: "totalOutput",
+    鐮屽潡: "blockOutput",
+    鏉挎潗: "plateOutput",
+  };
+
+  /** 鍏ㄩ儴锛氭寜 dateStr 鍚堝苟鐮屽潡/鏉挎潗涓ゆ潯搴忓垪 */
+  /** 灏嗘煇鐗╂枡鏃堕棿搴忓垪 chartData 姹囨�讳负鎶曞叆/浜у嚭鍚堣锛堢敤浜庛�屽叏閮ㄣ�嶆í杞�=鐗╂枡瀵规瘮锛� */
+  const sumChartDataInputOutput = chartData => {
+    const arr = Array.isArray(chartData) ? chartData : [];
+    const input = arr.reduce((s, c) => s + (Number(c.inputSum) || 0), 0);
+    const output = arr.reduce((s, c) => s + (Number(c.outputSum) || 0), 0);
+    return { input, output };
+  };
+
+  const mergeBlockPlateProductionSeries = (blockList, plateList) => {
+    const blocks = Array.isArray(blockList) ? blockList : [];
+    const plates = Array.isArray(plateList) ? plateList : [];
+    const blockByDate = new Map(blocks.map(i => [i.dateStr, i]));
+    const plateByDate = new Map(plates.map(i => [i.dateStr, i]));
+    const dates = [
+      ...new Set([...blockByDate.keys(), ...plateByDate.keys()]),
+    ].sort();
+    return {
+      categories: dates,
+      blockValues: dates.map(d => {
+        const row = blockByDate.get(d);
+        return row ? Number(row.blockOutput) || 0 : 0;
+      }),
+      plateValues: dates.map(d => {
+        const row = plateByDate.get(d);
+        return row ? Number(row.plateOutput) || 0 : 0;
+      }),
+    };
+  };
+
+  const loadBlockCost = async () => {
+    const materialName = blockSelectedMaterial.value;
+    if (!materialName) {
+      blockMaterialSummary.value = {
+        materialName: "",
+        monthlyConsumption: "--",
+        yearlyConsumption: "--",
+      };
+      blockCostChartSeries.value = {
+        xMode: "time",
+        categories: [],
+        input: [],
+        output: [],
+      };
+      updateCharts();
+      return;
+    }
+    const dateType = mapTimeDimensionToDateType(blockTimeDimension.value);
+    try {
+      if (materialName === "鍏ㄩ儴") {
+        const names = blockMaterialList.value.filter(n => n !== "鍏ㄩ儴");
+        if (!names.length) {
+          blockMaterialSummary.value = {
+            materialName: "鍏ㄩ儴",
+            monthlyConsumption: "--",
+            yearlyConsumption: "--",
+          };
+          blockCostChartSeries.value = {
+            xMode: "material",
+            categories: [],
+            input: [],
+            output: [],
+          };
+          updateCharts();
+          return;
+        }
+        const res = await getProductionStatisticsBlocks({ dateType });
+        const rows = Array.isArray(res.data) ? res.data : [];
+        const rowByName = new Map(
+          rows.filter(r => r && r.materialName).map(r => [r.materialName, r])
+        );
+        const useBulk = names.every(n => rowByName.has(n));
+
+        let categories;
+        let input;
+        let output;
+        if (useBulk) {
+          categories = [];
+          input = [];
+          output = [];
+          for (const name of names) {
+            const row = rowByName.get(name);
+            const chartData = Array.isArray(row.chartData) ? row.chartData : [];
+            const sums = sumChartDataInputOutput(chartData);
+            categories.push(name);
+            input.push(sums.input);
+            output.push(sums.output);
+          }
+        } else {
+          const parts = await Promise.all(
+            names.map(async name => {
+              const r = await getProductionStatisticsBlocks({
+                dateType,
+                materialName: name,
+              });
+              const rows2 = Array.isArray(r.data) ? r.data : [];
+              const row =
+                rows2.find(x => x.materialName === name) || rows2[0] || {};
+              const chartData = Array.isArray(row.chartData) ? row.chartData : [];
+              const sums = sumChartDataInputOutput(chartData);
+              return { name, ...sums };
+            })
+          );
+          categories = parts.map(p => p.name);
+          input = parts.map(p => p.input);
+          output = parts.map(p => p.output);
+        }
+
+        blockMaterialSummary.value = {
+          materialName: "鍏ㄩ儴",
+          monthlyConsumption: "--",
+          yearlyConsumption: "--",
+        };
+        blockCostChartSeries.value = {
+          xMode: "material",
+          categories,
+          input,
+          output,
+        };
+        updateCharts();
+        return;
+      }
+
+      const res = await getProductionStatisticsBlocks({
+        dateType,
+        materialName,
+      });
+      const rows = Array.isArray(res.data) ? res.data : [];
+      const row =
+        rows.find(r => r.materialName === materialName) || rows[0] || {};
+      const chartData = Array.isArray(row.chartData) ? row.chartData : [];
+      blockMaterialSummary.value = {
+        materialName: row.materialName || materialName,
+        monthlyConsumption: row.monthlyConsumption ?? "--",
+        yearlyConsumption: row.yearlyConsumption ?? "--",
+      };
+      blockCostChartSeries.value = {
+        xMode: "time",
+        categories: chartData.map(c => c.date),
+        input: chartData.map(c => c.inputSum ?? 0),
+        output: chartData.map(c => c.outputSum ?? 0),
+      };
+      updateCharts();
+    } catch (e) {
+      console.error(e);
+    }
+  };
+
+  const loadBoardCost = async () => {
+    const materialName = boardSelectedMaterial.value;
+    if (!materialName) {
+      boardMaterialSummary.value = {
+        materialName: "",
+        monthlyConsumption: "--",
+        yearlyConsumption: "--",
+      };
+      boardCostChartSeries.value = {
+        xMode: "time",
+        categories: [],
+        input: [],
+        output: [],
+      };
+      updateCharts();
+      return;
+    }
+    const dateType = mapTimeDimensionToDateType(boardTimeDimension.value);
+    try {
+      if (materialName === "鍏ㄩ儴") {
+        const names = boardMaterialList.value.filter(n => n !== "鍏ㄩ儴");
+        if (!names.length) {
+          boardMaterialSummary.value = {
+            materialName: "鍏ㄩ儴",
+            monthlyConsumption: "--",
+            yearlyConsumption: "--",
+          };
+          boardCostChartSeries.value = {
+            xMode: "material",
+            categories: [],
+            input: [],
+            output: [],
+          };
+          updateCharts();
+          return;
+        }
+        const res = await getProductionStatisticsPlates({ dateType });
+        const rows = Array.isArray(res.data) ? res.data : [];
+        const rowByName = new Map(
+          rows.filter(r => r && r.materialName).map(r => [r.materialName, r])
+        );
+        const useBulk = names.every(n => rowByName.has(n));
+
+        let categories;
+        let input;
+        let output;
+        if (useBulk) {
+          categories = [];
+          input = [];
+          output = [];
+          for (const name of names) {
+            const row = rowByName.get(name);
+            const chartData = Array.isArray(row.chartData) ? row.chartData : [];
+            const sums = sumChartDataInputOutput(chartData);
+            categories.push(name);
+            input.push(sums.input);
+            output.push(sums.output);
+          }
+        } else {
+          const parts = await Promise.all(
+            names.map(async name => {
+              const r = await getProductionStatisticsPlates({
+                dateType,
+                materialName: name,
+              });
+              const rows2 = Array.isArray(r.data) ? r.data : [];
+              const row =
+                rows2.find(x => x.materialName === name) || rows2[0] || {};
+              const chartData = Array.isArray(row.chartData) ? row.chartData : [];
+              const sums = sumChartDataInputOutput(chartData);
+              return { name, ...sums };
+            })
+          );
+          categories = parts.map(p => p.name);
+          input = parts.map(p => p.input);
+          output = parts.map(p => p.output);
+        }
+
+        boardMaterialSummary.value = {
+          materialName: "鍏ㄩ儴",
+          monthlyConsumption: "--",
+          yearlyConsumption: "--",
+        };
+        boardCostChartSeries.value = {
+          xMode: "material",
+          categories,
+          input,
+          output,
+        };
+        updateCharts();
+        return;
+      }
+
+      const res = await getProductionStatisticsPlates({
+        dateType,
+        materialName,
+      });
+      const rows = Array.isArray(res.data) ? res.data : [];
+      const row =
+        rows.find(r => r.materialName === materialName) || rows[0] || {};
+      const chartData = Array.isArray(row.chartData) ? row.chartData : [];
+      boardMaterialSummary.value = {
+        materialName: row.materialName || materialName,
+        monthlyConsumption: row.monthlyConsumption ?? "--",
+        yearlyConsumption: row.yearlyConsumption ?? "--",
+      };
+      boardCostChartSeries.value = {
+        xMode: "time",
+        categories: chartData.map(c => c.date),
+        input: chartData.map(c => c.inputSum ?? 0),
+        output: chartData.map(c => c.outputSum ?? 0),
+      };
+      updateCharts();
+    } catch (e) {
+      console.error(e);
+    }
+  };
+
+  const loadBlockMaterials = async () => {
+    try {
+      const res = await getProductionMaterials({ materialType: "1" });
+      const raw = Array.isArray(res.data) ? [...res.data] : [];
+      const list = ["鍏ㄩ儴", ...raw];
+      blockMaterialList.value = list;
+      if (list.length) {
+        if (!list.includes(blockSelectedMaterial.value)) {
+          blockSelectedMaterial.value = list[0];
+        }
+        await loadBlockCost();
+      } else {
+        blockSelectedMaterial.value = "";
+        blockMaterialSummary.value = {
+          materialName: "",
+          monthlyConsumption: "--",
+          yearlyConsumption: "--",
+        };
+        blockCostChartSeries.value = {
+          xMode: "time",
+          categories: [],
+          input: [],
+          output: [],
+        };
+        updateCharts();
+      }
+    } catch (e) {
+      console.error(e);
+    }
+  };
+
+  const loadBoardMaterials = async () => {
+    try {
+      const res = await getProductionMaterials({ materialType: "2" });
+      const raw = Array.isArray(res.data) ? [...res.data] : [];
+      const list = ["鍏ㄩ儴", ...raw];
+      boardMaterialList.value = list;
+      if (list.length) {
+        if (!list.includes(boardSelectedMaterial.value)) {
+          boardSelectedMaterial.value = list[0];
+        }
+        await loadBoardCost();
+      } else {
+        boardSelectedMaterial.value = "";
+        boardMaterialSummary.value = {
+          materialName: "",
+          monthlyConsumption: "--",
+          yearlyConsumption: "--",
+        };
+        boardCostChartSeries.value = {
+          xMode: "time",
+          categories: [],
+          input: [],
+          output: [],
+        };
+        updateCharts();
+      }
+    } catch (e) {
+      console.error(e);
+    }
+  };
+
+  const loadMaterialProduction = async () => {
+    const dateType = mapTimeDimensionToDateType(productionTimeDimension.value);
+    try {
+      const res = await getMaterialProductionAnalysis({ dateType });
+      const payload = res.data && typeof res.data === "object" ? res.data : {};
+      const cat = productionCategory.value;
+
+      if (cat === "鍏ㄩ儴") {
+        const merged = mergeBlockPlateProductionSeries(
+          payload["鐮屽潡"],
+          payload["鏉挎潗"]
+        );
+        productionChartSeries.value = {
+          categories: merged.categories,
+          mode: "dual",
+          values: [],
+          blockValues: merged.blockValues,
+          plateValues: merged.plateValues,
+        };
+      } else {
+        const list = Array.isArray(payload[cat]) ? payload[cat] : [];
+        const field = productionOutputKey[cat] || "totalOutput";
+        productionChartSeries.value = {
+          categories: list.map(i => i.dateStr),
+          mode: "single",
+          values: list.map(i => Number(i[field]) || 0),
+          blockValues: [],
+          plateValues: [],
+        };
+      }
+      updateCharts();
+    } catch (e) {
+      console.error(e);
+    }
+  };
+
+  const loadMiddleRingStats = async () => {
+    try {
+      const res = await getProductionStatisticsMiddle();
+      const d = res.data && typeof res.data === "object" ? res.data : {};
+      middleRingStats.value = {
+        flyAshMonth: Number(d.flyAshMonth) || 0,
+        flyAshYear: Number(d.flyAshYear) || 0,
+        gypsumMonth: Number(d.gypsumMonth) || 0,
+        gypsumYear: Number(d.gypsumYear) || 0,
+        blockMonth: Number(d.blockMonth) || 0,
+        blockYear: Number(d.blockYear) || 0,
+        plateMonth: Number(d.plateMonth) || 0,
+        plateYear: Number(d.plateYear) || 0,
+      };
+    } catch (e) {
+      console.error(e);
+    }
+  };
+
+  const loadSolidWasteData = async () => {
+    const dateType = mapTimeDimensionToDateType(customerTimeDimension.value);
+    try {
+      const res = await getProductionStatisticsSolidWaste({ dateType });
+      const list = Array.isArray(res.data) ? res.data : [];
+      solidWasteChartSeries.value = {
+        categories: list.map(i => i.dateStr),
+        total: list.map(i => Number(i.total) || 0),
+        flyAsh: list.map(i => Number(i.flyAsh) || 0),
+        gypsum: list.map(i => Number(i.gypsum) || 0),
+        lime: list.map(i => Number(i.lime) || 0),
+      };
+      updateCharts();
+    } catch (e) {
+      console.error(e);
+    }
+  };
+
+  const loadEnergyData = async () => {
+    const dateType = mapTimeDimensionToDateType(salesTimeDimension.value);
+    try {
+      const res = await getProductionStatisticsEnergy({ dateType });
+      const list = Array.isArray(res.data) ? res.data : [];
+      energyChartSeries.value = {
+        categories: list.map(i => i.dateStr),
+        water: list.map(i => Number(i.water) || 0),
+        electricity: list.map(i => Number(i.electricity) || 0),
+        steam: list.map(i => Number(i.steam) || 0),
+      };
+      updateCharts();
+    } catch (e) {
+      console.error(e);
+    }
+  };
+
+  const selectBlockMaterial = name => {
+    blockSelectedMaterial.value = name;
+    loadBlockCost();
+  };
+
+  const selectBoardMaterial = name => {
+    boardSelectedMaterial.value = name;
+    loadBoardCost();
+  };
+
+  const selectProductionCategory = cat => {
+    productionCategory.value = cat;
+    loadMaterialProduction();
   };
 
   // 鍒濆鍖栧浘琛�
   const initCharts = () => {
-    if (productionChart.value) {
+    // 鍒濆鍖栫爩鍧楁垚鏈浘琛�
+    if (blockCostChart.value && !blockCostChartInstance) {
+      blockCostChartInstance = echarts.init(blockCostChart.value);
+    }
+
+    // 鍒濆鍖栨澘鏉愭垚鏈浘琛�
+    if (boardCostChart.value && !boardCostChartInstance) {
+      boardCostChartInstance = echarts.init(boardCostChart.value);
+    }
+
+    // 鍒濆鍖栦骇閲忓垎鏋愬浘琛�
+    if (productionChart.value && !productionChartInstance) {
       productionChartInstance = echarts.init(productionChart.value);
-      productionChartInstance.setOption(productionChartOption.value);
     }
 
-    if (solidWasteChart.value) {
-      solidWasteChartInstance = echarts.init(solidWasteChart.value);
-      solidWasteChartInstance.setOption(solidWasteChartOption.value);
+    // 鍒濆鍖栨柊澧炲鎴疯秼鍔垮浘琛�
+    if (customerTrendChart.value && !customerTrendChartInstance) {
+      customerTrendChartInstance = echarts.init(customerTrendChart.value);
     }
 
-    if (costChart.value) {
-      costChartInstance = echarts.init(costChart.value);
-      costChartInstance.setOption(costChartOption.value);
+    // 鍒濆鍖栭攢閲忔帓鍚嶅垎鏋愬浘琛�
+    if (salesRankingChart.value && !salesRankingChartInstance) {
+      salesRankingChartInstance = echarts.init(salesRankingChart.value);
     }
 
-    if (energyChart.value) {
-      energyChartInstance = echarts.init(energyChart.value);
-      energyChartInstance.setOption(energyChartOption.value);
-    }
+    updateCharts();
+  };
+
+  /** 鐮屽潡/鏉挎潗瀹瑰櫒楂樺害鍙樺寲鍚庯紙濡傞殣钘忔眹鎬诲崱锛夐渶 resize锛屽惁鍒欏簳閮ㄧ暀鐧� */
+  const resizeCostPanelCharts = () => {
+    nextTick(() => {
+      requestAnimationFrame(() => {
+        blockCostChartInstance?.resize();
+        boardCostChartInstance?.resize();
+      });
+    });
   };
 
   // 鏇存柊鍥捐〃
   const updateCharts = () => {
+    // 鏇存柊鐮屽潡鎴愭湰鍥捐〃锛坮eplaceMerge锛氬叏閮ㄢ啍鍗曠墿鏂欐椂妯酱鏃堕棿/鐗╂枡鍒囨崲锛�
+    if (blockCostChartInstance) {
+      blockCostChartInstance.setOption(blockCostChartOption.value, {
+        replaceMerge: ["series", "xAxis"],
+      });
+    }
+
+    // 鏇存柊鏉挎潗鎴愭湰鍥捐〃
+    if (boardCostChartInstance) {
+      boardCostChartInstance.setOption(boardCostChartOption.value, {
+        replaceMerge: ["series", "xAxis"],
+      });
+    }
+
+    // 鏇存柊浜ч噺鍒嗘瀽鍥捐〃锛坮eplaceMerge锛氬叏閮ㄢ啍鐮屽潡/鏉挎潗鍒囨崲鏃跺幓鎺夊浣欐姌绾匡紝閬垮厤鍚堝苟娈嬬暀锛�
     if (productionChartInstance) {
-      productionChartInstance.setOption(productionChartOption.value);
+      productionChartInstance.setOption(productionChartOption.value, {
+        replaceMerge: ["series"],
+      });
     }
 
-    if (solidWasteChartInstance) {
-      solidWasteChartInstance.setOption(solidWasteChartOption.value);
+    // 鏇存柊鏂板瀹㈡埛瓒嬪娍鍥捐〃
+    if (customerTrendChartInstance) {
+      customerTrendChartInstance.setOption(customerTrendChartOption.value);
     }
 
-    if (costChartInstance) {
-      costChartInstance.setOption(costChartOption.value);
+    // 鏇存柊閿�閲忔帓鍚嶅垎鏋愬浘琛�
+    if (salesRankingChartInstance) {
+      salesRankingChartInstance.setOption(salesRankingChartOption.value);
     }
 
-    if (energyChartInstance) {
-      energyChartInstance.setOption(energyChartOption.value);
-    }
+    resizeCostPanelCharts();
   };
 
-  // 璋冩暣鍥捐〃澶у皬
-  const resizeCharts = () => {
-    productionChartInstance?.resize();
-    solidWasteChartInstance?.resize();
-    costChartInstance?.resize();
-    energyChartInstance?.resize();
+  // 澶勭悊鏃堕棿缁村害閫夋嫨
+  const handleBlockTimeDimensionChange = dimension => {
+    blockTimeDimension.value = dimension;
+    loadBlockCost();
   };
 
-  // 绐楀彛澶у皬鍙樺寲澶勭悊
+  const handleBoardTimeDimensionChange = dimension => {
+    boardTimeDimension.value = dimension;
+    loadBoardCost();
+  };
+
+  const handleProductionTimeDimensionChange = dimension => {
+    productionTimeDimension.value = dimension;
+    loadMaterialProduction();
+  };
+
+  const handleCustomerTimeDimensionChange = dimension => {
+    customerTimeDimension.value = dimension;
+    loadSolidWasteData();
+  };
+
+  const handleSalesTimeDimensionChange = dimension => {
+    salesTimeDimension.value = dimension;
+    loadEnergyData();
+  };
+
+  // 鐩戝惉绐楀彛澶у皬鍙樺寲
   const handleResize = () => {
-    // 寤惰繜鎵ц锛岀‘淇滵OM鏇存柊瀹屾垚
-    setTimeout(() => {
-      resizeCharts();
-    }, 100);
+    // 鍏堟洿鏂板浘琛ㄩ�夐」锛岄噸鏂拌绠楀搷搴斿紡鍊�
+    updateCharts();
+    // 鐒跺悗璋冩暣鍥捐〃澶у皬
+    if (blockCostChartInstance) {
+      blockCostChartInstance.resize();
+    }
+    if (boardCostChartInstance) {
+      boardCostChartInstance.resize();
+    }
+    if (productionChartInstance) {
+      productionChartInstance.resize();
+    }
+    if (customerTrendChartInstance) {
+      customerTrendChartInstance.resize();
+    }
+    if (salesRankingChartInstance) {
+      salesRankingChartInstance.resize();
+    }
   };
 
-  // 鑾峰彇鐗╂枡绫诲瀷鏍囩绫诲瀷
-  const getMaterialTypeType = material => {
-    const typeMap = {
-      姘存偿: "primary",
-      閾濈矇鑶�: "success",
-      鑴辨ā鍓�: "warning",
-      闃茶厫鍓�: "danger",
-      姘寲鍓�: "info",
-      鍐锋嫈涓�: "purple",
-    };
-    return typeMap[material] || "info";
-  };
-
-  // 鐢熷懡鍛ㄦ湡閽╁瓙
+  // 鐢熷懡鍛ㄦ湡
   onMounted(() => {
-    // 浣跨敤nextTick纭繚DOM瀹屽叏娓叉煋鍚庡啀鍒濆鍖�
-    nextTick(() => {
-      // 鍒濆鍖栧浘琛�
+    // 鍚姩椤堕儴鏍忔椂闂村埛鏂�
+    if (!timeTicker) {
+      timeTicker = setInterval(() => {
+        now.value = dayjs();
+      }, 1000);
+    }
+
+    // 绛夊緟DOM鏇存柊鍚庡垵濮嬪寲鍥捐〃骞舵媺鍙栨帴鍙f暟鎹�
+    nextTick(async () => {
       initCharts();
+      if (typeof ResizeObserver !== "undefined") {
+        if (blockCostChart.value) {
+          blockCostChartResizeObserver = new ResizeObserver(() => {
+            blockCostChartInstance?.resize();
+          });
+          blockCostChartResizeObserver.observe(blockCostChart.value);
+        }
+        if (boardCostChart.value) {
+          boardCostChartResizeObserver = new ResizeObserver(() => {
+            boardCostChartInstance?.resize();
+          });
+          boardCostChartResizeObserver.observe(boardCostChart.value);
+        }
+      }
+      await Promise.all([
+        loadBlockMaterials(),
+        loadBoardMaterials(),
+        loadMaterialProduction(),
+        loadMiddleRingStats(),
+        loadSolidWasteData(),
+        loadEnergyData(),
+      ]);
+      resizeCostPanelCharts();
     });
 
+    // 娣诲姞绐楀彛澶у皬鍙樺寲鐩戝惉
     window.addEventListener("resize", handleResize);
+    document.addEventListener("fullscreenchange", handleFullscreenChange);
   });
 
+  // 缁勪欢鍗歌浇鏃堕攢姣佸浘琛ㄥ疄渚�
   onBeforeUnmount(() => {
-    window.removeEventListener("resize", handleResize);
+    if (timeTicker) {
+      clearInterval(timeTicker);
+      timeTicker = null;
+    }
 
-    // 閿�姣佸浘琛ㄥ疄渚�
-    productionChartInstance?.dispose();
-    solidWasteChartInstance?.dispose();
-    costChartInstance?.dispose();
-    energyChartInstance?.dispose();
+    blockCostChartResizeObserver?.disconnect();
+    blockCostChartResizeObserver = null;
+    boardCostChartResizeObserver?.disconnect();
+    boardCostChartResizeObserver = null;
+
+    if (blockCostChartInstance) {
+      blockCostChartInstance.dispose();
+    }
+    if (boardCostChartInstance) {
+      boardCostChartInstance.dispose();
+    }
+    if (productionChartInstance) {
+      productionChartInstance.dispose();
+    }
+    if (customerTrendChartInstance) {
+      customerTrendChartInstance.dispose();
+    }
+    if (salesRankingChartInstance) {
+      salesRankingChartInstance.dispose();
+    }
+
+    // 绉婚櫎绐楀彛澶у皬鍙樺寲鐩戝惉
+    window.removeEventListener("resize", handleResize);
+    document.removeEventListener("fullscreenchange", handleFullscreenChange);
   });
 </script>
 
 <style scoped>
-  /* 澶栭儴瀹瑰櫒 - 鍗犳嵁鏁翠釜瑙嗗彛 */
-  .dashboard-container {
+  .sales-statistics-container {
     position: relative;
     width: 100%;
-    /* 椤甸潰鍦ㄥ父瑙勫竷灞�涓嬶紙鏈夐《鏍忥級榛樿鍑忓幓 84px锛岄伩鍏嶅唴瀹硅瑁佸垏 */
-    min-height: calc(100vh - 84px);
-    background-color: #f5f7fa;
+    min-height: calc(100vh - 8.4vh);
     overflow: hidden;
+    color: #b8c8e0;
+    background: #041026;
   }
 
-  /* 鍐呴儴鍐呭鍖哄煙 - 鑷�傚簲瀹藉害 */
-  .data-dashboard {
-    position: relative;
-    width: 100%;
-    min-height: 100%;
-    background-color: #ffffff;
-    box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
+  .sales-statistics-container.is-fullscreen {
+    min-height: 100vh;
+    height: 100vh;
   }
 
-  .dashboard-header {
+  /* 娣辫壊鑳屾櫙鍥� */
+  .bi-bg {
+    position: absolute;
+    inset: 0;
+    /* background-image: url("@/assets/BI/backImage@2x.png"); */
+    background-size: cover;
+    background-position: center;
+    background-repeat: no-repeat;
+    z-index: 0;
+  }
+
+  /* 椤堕儴鏍囬鏍� */
+  .bi-topbar {
     position: relative;
-    z-index: 1;
-    height: 86px;
-    background-color: #ffffff;
-    border-bottom: 1px solid #e4e7ed;
+    z-index: 2;
+    height: 5.8vh;
     display: flex;
     align-items: center;
     justify-content: center;
   }
 
-  .factory-name {
-    font-weight: 600;
-    font-size: 32px;
-    color: #303133;
+  .bi-topbar-title-bg {
+    position: absolute;
+    top: 0;
+    left: 0;
+    height: 8vh;
+    width: 100%;
+    object-fit: cover;
+    z-index: 0;
+    pointer-events: none;
   }
 
-  .filter-area {
-    padding: 20px;
-    background-color: #ffffff;
-    border-bottom: 1px solid #e4e7ed;
-    display: flex;
-    gap: 40px;
-    align-items: center;
-    flex-wrap: wrap;
-  }
-
-  .filter-section {
-    display: flex;
-    align-items: center;
-    gap: 10px;
-  }
-
-  .filter-label {
-    font-size: 14px;
-    font-weight: 500;
-    color: #303133;
-    white-space: nowrap;
-  }
-
-  .radio-group {
-    display: flex;
-    align-items: center;
-  }
-
-  /* 鎸夐挳鏍峰紡 */
-  :deep(.el-radio-button__inner) {
-    border-radius: 4px;
-    padding: 8px 20px;
-    font-size: 14px;
-    transition: all 0.3s ease;
-  }
-
-  :deep(.el-radio-button__orig-radio:checked + .el-radio-button__inner) {
-    background-color: #409eff;
-    border-color: #409eff;
-    color: #ffffff;
-    box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
-  }
-
-  :deep(.el-radio-button__inner:hover) {
-    color: #409eff;
-    border-color: #c6e2ff;
-  }
-
-  :deep(.el-radio-button:first-child .el-radio-button__inner) {
-    border-radius: 4px 0 0 4px;
-  }
-
-  :deep(.el-radio-button:last-child .el-radio-button__inner) {
-    border-radius: 0 4px 4px 0;
-  }
-
-  .dashboard-content {
+  .bi-topbar-content {
     position: relative;
     z-index: 1;
+    width: 100%;
+    padding: 0 2.8vh;
     display: flex;
-    flex-direction: column;
-    gap: 20px;
-    padding: 20px;
-    min-height: 800px;
-    overflow: hidden;
+    align-items: center;
+    justify-content: center;
   }
 
-  /* 琛屽竷灞� */
-  .row {
+  .bi-topbar-title {
+    position: absolute;
+    left: 50%;
+    transform: translateX(-50%);
+    font-size: 2.6vh;
+    font-weight: 800;
+    letter-spacing: 0.1vh;
+    background: linear-gradient(180deg, #ffffff 0%, #b8dfff 100%);
+    -webkit-background-clip: text;
+    background-clip: text;
+    -webkit-text-fill-color: transparent;
+    color: transparent;
+    text-shadow: 0 0 2.6vh rgba(0, 164, 237, 0.55);
+  }
+
+  .bi-topbar-left {
+    position: absolute;
+    left: 1vh;
     display: flex;
-    gap: 20px;
-    align-items: stretch;
+    align-items: center;
+    gap: 0.8vh;
+    color: rgba(208, 231, 255, 0.85);
+    font-size: 1.3vh;
   }
 
-  /* 绗竴琛岋細3涓崱鐗� */
-  .row-1 {
-    height: 300px;
+  .status-sun {
+    color: #ffd85e;
+    text-shadow: 0 0 1vh rgba(255, 216, 94, 0.8);
+    font-size: 1.3vh;
+    line-height: 1;
   }
 
-  /* 绗簩琛岋細2涓崱鐗� */
-  .row-2 {
-    height: 300px;
-  }
-
-  /* 绗笁琛岋細1涓崱鐗� */
-  .row-3 {
-    min-height: 250px;
-  }
-
-  /* 鍗$墖鏍峰紡 */
-  .panel-card {
-    background-color: #ffffff;
-    border-radius: 8px;
-    border: 1px solid #e4e7ed;
-    overflow: hidden;
-    display: flex;
-    flex-direction: column;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
-    transition: all 0.3s ease;
-  }
-
-  .panel-card:hover {
-    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
-    transform: translateY(-2px);
-  }
-
-  /* 鍗$墖甯冨眬 */
-  .card-1 {
-    flex: 1;
-  }
-
-  .card-2 {
-    flex: 1;
-  }
-
-  .card-3 {
-    flex: 0.8;
-  }
-
-  .card-4 {
-    flex: 1.2;
-  }
-
-  .card-5 {
-    flex: 0.8;
-  }
-
-  .card-6 {
-    flex: 1;
-  }
-
-  .panel-card {
-    background-color: #ffffff;
-    border-radius: 8px;
-    border: 1px solid #e4e7ed;
-    overflow: hidden;
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-  }
-
-  .panel-title {
-    padding: 15px 20px;
-    font-size: 16px;
+  .bi-topbar-meta {
+    position: absolute;
+    right: 5.2vh;
+    /* top: 1.6vh; */
+    font-size: 1.2vh;
     font-weight: 500;
-    color: #303133;
-    border-bottom: 1px solid #e4e7ed;
-    background-color: #fafafa;
+    letter-spacing: 0.05vh;
+    color: rgba(208, 231, 255, 0.85);
+    display: flex;
+    align-items: center;
+    gap: 1vh;
   }
 
-  .card-1 .panel-title {
-    border-left: 4px solid #409eff;
+  .fullscreen-btn {
+    position: absolute;
+    bottom: -1vh;
+    transform: none;
+    border: 0.1vh solid rgba(64, 158, 255, 0.45);
+    background: rgba(0, 164, 237, 0.14);
+    color: #d0e7ff;
+    width: 3.4vh;
+    height: 3.4vh;
+    border-radius: 0.6vh;
+    padding: 0;
+    cursor: pointer;
+    transition: all 0.2s ease;
+    z-index: 10;
+    display: flex;
+    align-items: center;
+    justify-content: center;
   }
 
-  .card-2 .panel-title {
-    border-left: 4px solid #f56c6c;
+  .fullscreen-btn:hover {
+    background: rgba(0, 164, 237, 0.24);
+    box-shadow: 0 0 1.2vh rgba(0, 164, 237, 0.3);
   }
 
-  .card-3 .panel-title {
-    border-left: 4px solid #e6a23c;
+  .bi-topbar-sep {
+    opacity: 0.7;
   }
 
-  .card-4 .panel-title {
-    border-left: 4px solid #409eff;
+  /* 涓讳綋缃戞牸甯冨眬 */
+  .bi-dashboard-grid {
+    position: relative;
+    z-index: 2;
+    height: calc(100vh - 8.4vh - 5.8vh);
+    min-height: 45vh;
+    padding: 1vh 1.8vh 1.4vh;
+    display: grid;
+    grid-template-columns: 1fr 1.05fr 1fr;
+    grid-template-rows: 1fr 1fr;
+    gap: 1.2vh;
   }
 
-  .card-5 .panel-title {
-    border-left: 4px solid #67c23a;
+  .sales-statistics-container.is-fullscreen .bi-dashboard-grid {
+    height: calc(100vh - 5.8vh);
   }
 
-  .card-6 .panel-title {
-    border-left: 4px solid #e6a23c;
+  .bi-panel {
+    background: rgba(3, 18, 46, 0.62);
+    border: 0.1vh solid rgba(64, 158, 255, 0.35);
+    border-radius: 0.4vh;
+    overflow: hidden;
+    box-shadow: 0 0 2.2vh rgba(0, 164, 237, 0.12);
+    display: flex;
+    flex-direction: column;
+    position: relative;
   }
 
-  .chart-container {
+  .bi-panel-title {
+    height: 4.4vh;
+    display: flex;
+    align-items: center;
+    padding: 0 1.8vh;
+    font-size: 1.5vh;
+    font-weight: 700;
+    color: #b8c8e0;
+    background: linear-gradient(
+      90deg,
+      rgba(0, 164, 237, 0.2),
+      rgba(0, 164, 237, 0.04)
+    );
+    border-bottom: 0.1vh solid rgba(64, 158, 255, 0.25);
+  }
+
+  .panel-tabs,
+  .panel-tabs2 {
+    position: absolute;
+    top: 0.8vh;
+    display: flex;
+    gap: 0.6vh;
+    z-index: 4;
+  }
+
+  .panel-tabs {
+    right: 1.2vh;
+  }
+
+  .panel-tabs2 {
+    right: 8vh;
+  }
+  .tab-item {
+    font-size: 1.2vh;
+    color: rgba(184, 200, 224, 0.75);
+    padding: 0.1vh 0.5vh;
+    border: 0.1vh solid rgba(64, 158, 255, 0.25);
+    border-radius: 0.3vh;
+    line-height: 1.4;
+    cursor: pointer;
+  }
+
+  .tab-item.active {
+    color: #ffffff;
+    border-color: rgba(0, 164, 237, 0.65);
+    background: rgba(0, 164, 237, 0.22);
+  }
+
+  .bi-panel-body {
     flex: 1;
-    padding: 20px;
+    padding: 0.8vh 1vh;
+    position: relative;
   }
 
-  .table-container {
+  .scroll-table-container {
+    height: 33vh;
+    overflow: hidden;
+    position: relative;
+  }
+
+  .scroll-table {
+    width: 100%;
+    border-collapse: collapse;
+    color: #b8c8e0;
+  }
+
+  .scroll-table th {
+    /* background-color: #0e2a54; */
+    padding: 1.2vh;
+    text-align: left;
+    font-size: 1.2vh;
+    font-weight: bold;
+    border: 1px solid rgba(184, 200, 224, 0.2);
+  }
+
+  .scroll-table td {
+    padding: 1vh;
+    font-size: 1.1vh;
+    border-bottom: 1px solid rgba(184, 200, 224, 0.1);
+  }
+
+  .scroll-table tbody {
+    display: block;
+    height: 35vh;
+    overflow: hidden;
+  }
+
+  .scroll-table thead,
+  .scroll-table tbody tr {
+    display: table;
+    width: 100%;
+    table-layout: fixed;
+  }
+
+  .scroll-table th,
+  .scroll-table td {
+    width: 25%;
+    box-sizing: border-box;
+    font-size: 1.4vh;
+  }
+
+  .scroll-table tbody tr {
+    transition: all 0.5s ease-in-out;
+  }
+
+  /* .scroll-table tbody tr:nth-child(odd) {
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              background-color: rgba(64, 158, 255, 0.05);
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              }
+
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            .scroll-table tbody tr:nth-child(even) {
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                background-color: rgba(64, 158, 255, 0.1);
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  } */
+  .oddTableTr {
+    background-color: rgba(64, 158, 255, 0.05);
+  }
+  .evenTableTr {
+    background-color: rgba(64, 158, 255, 0.1);
+  }
+
+  .scroll-table-container:hover tbody {
+    overflow: hidden;
+  }
+
+  .echart-fill {
+    width: 100%;
+    height: 100%;
+  }
+
+  .chart-filter-tabs {
+    display: flex;
+    gap: 0.6vh;
+    margin: 0 0 0.5vh 0;
+    justify-self: end;
+  }
+
+  .cf-tab {
+    font-size: 1.1vh;
+    color: rgba(184, 200, 224, 0.68);
+    background: rgba(18, 56, 106, 0.65);
+    border: 0.1vh solid rgba(64, 158, 255, 0.25);
+    padding: 0.3vh 0.9vh;
+    line-height: 1;
+    cursor: pointer;
+  }
+
+  .cf-tab.active {
+    color: #d9ecff;
+    background: rgba(0, 108, 208, 0.85);
+    border-color: rgba(64, 158, 255, 0.65);
+  }
+
+  .chart-unit-row {
+    display: flex;
+    justify-content: space-between;
+    font-size: 1.2vh;
+    color: rgba(208, 231, 255, 0.88);
+    margin-bottom: 0.4vh;
+    padding: 0 0.2vh;
+  }
+
+  .dot-legend::before {
+    content: "";
+    display: inline-block;
+    width: 0.8vh;
+    height: 0.8vh;
+    background: #65a0ff;
+    margin-right: 0.6vh;
+  }
+
+  .chart-mini-title {
+    display: flex;
+    align-items: center;
+    gap: 0.8vh;
+    font-size: 1.8vh;
+    color: #d9ecff;
+  }
+
+  /* 闈㈡澘搴曢儴鍚堣琛� */
+  .panel-summary-row {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 0.8vh 1.2vh;
+    /* margin-top: 0.8vh; */
+    background: #041e3c;
+    border-top: 0.1vh solid rgba(64, 158, 255, 0.25);
+    border-radius: 0 0 0.4vh 0.4vh;
+    width: 100%;
+    position: absolute;
+    bottom: 0;
+  }
+
+  .summary-label {
+    font-size: 1.3vh;
+    font-weight: 700;
+    color: #b8c8e0;
+  }
+
+  .summary-value {
+    font-size: 1.4vh;
+    font-weight: 800;
+    color: #00a4ed;
+    margin-right: 3.8vh;
+    text-shadow: 0 0 1vh rgba(0, 164, 237, 0.5);
+  }
+
+  .summary-value2 {
+    font-size: 1.4vh;
+    font-weight: 800;
+    color: #00a4ed;
+    margin-right: 5.8vh;
+    text-shadow: 0 0 1vh rgba(0, 164, 237, 0.5);
+  }
+  .diamond {
+    width: 1vh;
+    height: 1vh;
+    background: #1e8bff;
+    transform: rotate(45deg);
+    display: inline-block;
+  }
+
+  .chart-unit-single {
+    justify-content: flex-start;
+    margin-bottom: 0.2vh;
+  }
+
+  /* 鐮屽潡/鏉挎潗锛氬浘琛ㄥ崰婊� Tab 涓庢眹鎬诲崱涓嬫柟鐨勫墿浣欓珮搴︼紱闅愯棌姹囨�诲崱鏃惰嚜鍔ㄦ媺楂� */
+  .bi-panel-top-left,
+  .bi-panel-bottom-left {
+    min-height: 0;
+  }
+
+  .bi-panel-top-left .bi-panel-body,
+  .bi-panel-bottom-left .bi-panel-body {
+    display: flex;
+    flex-direction: column;
+    min-height: 0;
+  }
+
+  .bi-panel-top-left .chart-filter-tabs,
+  .bi-panel-bottom-left .chart-filter-tabs {
+    flex-shrink: 0;
+  }
+
+  .bi-panel-top-left .echart-fill,
+  .bi-panel-bottom-left .echart-fill {
     flex: 1;
-    padding: 20px;
+    min-height: 0;
+    height: auto;
+    width: 100%;
+  }
+
+  .bi-panel-bottom-right .echart-fill {
+    height: calc(100% - 2.8vh);
+  }
+
+  .bi-panel-bottom-center .echart-fill,
+  .bi-panel-top-right .echart-fill {
+    height: calc(100% - 4.4vh);
+  }
+
+  .bi-panel-top-left {
+    grid-column: 1;
+    grid-row: 1;
+    position: relative;
+  }
+
+  .bi-panel-top-right {
+    grid-column: 3;
+    grid-row: 1;
+    position: relative;
+  }
+
+  .bi-panel-bottom-left {
+    grid-column: 1;
+    grid-row: 2;
+    overflow-y: auto;
+  }
+  .bi-panel-bottom-left::-webkit-scrollbar {
+    width: 0vh;
+    height: 0vh;
+  }
+
+  .bi-panel-bottom-center {
+    grid-column: 2;
+    grid-row: 2;
+  }
+
+  .bi-panel-bottom-right {
+    grid-column: 3;
+    grid-row: 2;
+    overflow-y: auto;
+  }
+  .bi-panel-bottom-right::-webkit-scrollbar {
+    width: 0vh;
+    height: 0vh;
+  }
+
+  /* 涓績鐜诞灞傦紙缁濆瀹氫綅鍦ㄧ綉鏍间笂鏂癸級 */
+  .center-ring {
+    grid-column: 2;
+    grid-row: 1 / span 2;
+    position: absolute;
+    background: url("@/assets/BI/imageSS@2x.png") no-repeat bottom center;
+    background-size: 80% 30%;
+    left: 25%;
+    top: 25%;
+    transform: translate(-50%, -45%);
+    width: 50%;
+    height: 40.5vh;
+    z-index: 3;
+    pointer-events: none;
+  }
+  .center-ring-box {
+    position: absolute;
+    /* inset: 0; */
+    height: 88%;
+    width: 100%;
+    margin-top: 3%;
+    /* background-color: #fff; */
+    background: url("@/assets/BI/SCbg.png") no-repeat center center;
+    background-size: 100% 100%;
+  }
+  .ring-box-topright {
+    position: absolute;
+    top: 6vh;
+    right: 0;
+    width: 25%;
+    height: 15%;
+    background: url("@/assets/BI/SCbgright.png") no-repeat center center;
+    background-size: 100% 100%;
+    text-align: right;
+  }
+  .ring-box-topleft {
+    position: absolute;
+    top: 6vh;
+    left: 0;
+    width: 25%;
+    height: 15%;
+    background: url("@/assets/BI/SCbgleft.png") no-repeat center center;
+    background-size: 100% 100%;
+    text-align: left;
+  }
+  .topright-label {
+    font-size: 1.8vh;
+    font-weight: 500;
+    color: rgba(234, 246, 255, 0.9);
+    margin-top: 0;
+    position: relative;
+    bottom: 3vh;
+    right: 1vh;
+  }
+
+  .topleft-label {
+    font-size: 1.8vh;
+    font-weight: 500;
+    color: rgba(234, 246, 255, 0.9);
+    margin-top: 0;
+    position: relative;
+    bottom: 3vh;
+    left: 1vh;
+  }
+  .ring-box-left {
+    /* background-color: #ebebeb; */
+    width: 30%;
+    position: absolute;
+    left: 1vh;
+    top: 56%;
+    transform: translateY(-50%);
+  }
+  .left-label {
+    font-size: 1.4vh;
+    font-weight: 500;
+    color: #0effef;
+    margin-top: 0;
+    position: relative;
+    bottom: 3vh;
+  }
+  .left-value {
+    font-size: 1.2vh;
+    font-weight: 500;
+    color: rgba(234, 246, 255, 0.9);
+    margin-top: 0;
+    position: relative;
+    bottom: 3vh;
+    margin-top: 0.4vh;
+  }
+  .ring-box-right {
+    /* background-color: #ebebeb; */
+    width: 30%;
+    float: right;
+    position: absolute;
+    right: -1vh;
+    top: 56%;
+    transform: translateY(-50%);
+  }
+  .right-label {
+    font-size: 1.4vh;
+    font-weight: 500;
+    color: #ffa60e;
+    margin-top: 0;
+    position: relative;
+    bottom: 3vh;
+  }
+
+  .right-value {
+    font-size: 1.2vh;
+    font-weight: 500;
+    color: rgba(234, 246, 255, 0.9);
+    margin-top: 0;
+    position: relative;
+    bottom: 3vh;
+    margin-top: 0.4vh;
+  }
+
+  .center-ring-bg {
+    width: 100%;
+    height: 100%;
+    object-fit: contain;
+    filter: drop-shadow(0 0 2vh rgba(0, 164, 237, 0.35));
+  }
+
+  .center-ring-content {
+    position: absolute;
+    inset: 0;
+  }
+
+  .center-ring-content::before,
+  .center-ring-content::after {
+    content: "";
+    position: absolute;
+    left: 50%;
+    top: 56%;
+    width: 37vh;
+    height: 14.6vh;
+    transform: translate(-50%, -50%) rotate(-18deg);
+    border: 0.2vh solid rgba(40, 186, 255, 0.45);
+    border-radius: 50%;
+    filter: drop-shadow(0 0 0.8vh rgba(0, 164, 237, 0.35));
+    opacity: 0.7;
+  }
+
+  .center-ring-content::after {
+    width: 36vh;
+    height: 15vh;
+    transform: translate(-50%, -50%) rotate(26deg);
+    border-color: rgba(80, 220, 255, 0.35);
+    opacity: 0.55;
+  }
+
+  .center-ring-title {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    font-size: 3.6vh;
+    line-height: 1.05;
+    text-align: center;
+    font-weight: 900;
+    color: #eaf6ff;
+    text-shadow: 0 0 2.2vh rgba(0, 164, 237, 0.55);
+    z-index: 2;
+  }
+
+  .center-ring-title::before {
+    content: "";
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    width: 15.5vh;
+    height: 15.5vh;
+    transform: translate(-50%, -50%);
+    background: radial-gradient(
+      circle,
+      rgba(43, 199, 255, 0.26) 0%,
+      rgba(8, 28, 61, 0.86) 70%
+    );
+    border: 0.2vh solid rgba(39, 198, 255, 0.46);
+    border-radius: 50%;
+    box-shadow: 0 0 2vh rgba(0, 164, 237, 0.45),
+      inset 0 0 2.6vh rgba(0, 164, 237, 0.2);
+    z-index: -1;
+  }
+
+  .center-metric {
+    position: absolute;
+    width: 15.5vh;
+    z-index: 3;
+    text-align: center;
+    height: 12vh;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+  }
+
+  .center-metric-label {
+    font-size: 1.2vh;
+    font-weight: 500;
+    color: rgba(234, 246, 255, 0.9);
+    margin-top: 0;
+  }
+
+  .center-metric-value {
+    font-size: 3.4vh;
+    font-weight: 800;
+    color: #eaf6ff;
+    text-shadow: 0 0 0.8vh rgba(0, 229, 255, 0.22);
+    line-height: 1;
+  }
+
+  .center-metric-unit {
+    margin-top: 0;
+    font-size: 1.2vh;
+    color: rgba(208, 231, 255, 0.85);
+  }
+
+  .m1 {
+    top: 2.5vh;
+    left: 4.8vh;
+    text-align: left;
+  }
+
+  .m2 {
+    top: 4.1vh;
+    right: 8.6vh;
+    text-align: right;
+  }
+
+  .m3 {
+    bottom: 7.9vh;
+    left: 4vh;
+    text-align: left;
+  }
+
+  .m4 {
+    bottom: 7vh;
+    right: 5.4vh;
+    text-align: right;
+  }
+
+  @media (max-width: 1100px) {
+    .bi-topbar-content {
+      padding: 0 1.4vh;
+    }
+    .center-ring {
+      left: 45.2%;
+      width: 33vh;
+      height: 24.5vh;
+      top: 2.4vh;
+    }
+    .center-ring-title {
+      top: 50%;
+      font-size: 2.8vh;
+      transform: translate(-50%, -50%);
+    }
+    .center-metric {
+      height: 10.5vh;
+    }
+    .m1 {
+      top: 5.2vh;
+      left: 4.2vh;
+    }
+    .m2 {
+      top: 5.4vh;
+      right: 4.2vh;
+    }
+    .m3 {
+      bottom: 6.2vh;
+      left: 4.8vh;
+    }
+    .m4 {
+      bottom: 6.8vh;
+      right: 4.4vh;
+    }
+  }
+  .scroll-table-content {
+    height: 39vh;
     overflow: auto;
   }
+  .scroll-table-content::-webkit-scrollbar {
+    width: 0;
+    height: 0;
+    background-color: transparent;
+  }
+  .total-row {
+    position: absolute;
+    bottom: 0vh;
+    left: 0;
+    width: 100%;
+    display: flex;
+    height: 3.5vh;
+    justify-content: space-around;
+    align-items: center;
+    background-color: #081843;
+  }
 
-  .stats-grid {
+  .total-cell {
+    width: 20%;
+    font-size: 1.4vh;
+    margin-bottom: 0.5vh;
+    line-height: 3.5vh;
+    padding-left: 0.8vh;
+    color: #eaf6ff;
+    text-shadow: 0 0 0.8vh rgba(0, 229, 255, 0.22);
+    text-align: left;
+    color: #c3c3c3;
+  }
+  .total-cell2 {
+    width: 20%;
+    font-size: 1.4vh;
+    margin-bottom: 0.5vh;
+    line-height: 3.5vh;
+    color: #eaf6ff;
+    text-shadow: 0 0 0.8vh rgba(0, 229, 255, 0.22);
+    text-align: left;
+    color: #c3c3c3;
+  }
+  /* 鏉愭枡淇℃伅鍗$墖 */
+  .material-info-card {
+    display: flex;
+    align-items: center;
+    padding: 1.2vh 1.6vh;
+    background: rgba(0, 164, 237, 0.1);
+    border-radius: 0.8vh;
+    margin: 1.2vh 1.6vh;
+  }
+
+  .material-icon {
+    width: 4vh;
+    height: 4vh;
+    background: rgba(0, 164, 237, 0.2);
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-right: 1.2vh;
+    color: #00a4ed;
+  }
+
+  .material-details {
     flex: 1;
-    padding: 15px;
-    display: grid;
-    grid-template-columns: repeat(2, 1fr);
-    grid-template-rows: repeat(2, 1fr);
-    gap: 15px;
+  }
+
+  .material-name {
+    font-size: 1.3vh;
+    font-weight: 600;
+    color: #d0e7ff;
+    margin-bottom: 0.6vh;
+  }
+
+  .material-stats {
+    display: flex;
+    gap: 1.6vh;
   }
 
   .stat-item {
-    background-color: #fafafa;
-    border-radius: 8px;
-    padding: 15px;
     display: flex;
-    flex-direction: column;
     align-items: center;
-    justify-content: center;
-    border: 1px solid #e4e7ed;
-    min-height: 80px;
+    gap: 0.4vh;
   }
 
   .stat-label {
-    font-size: 13px;
-    color: #606266;
-    margin-bottom: 8px;
+    font-size: 1vh;
+    opacity: 0.7;
   }
 
   .stat-value {
-    font-size: 20px;
+    font-size: 1.2vh;
     font-weight: 600;
-    color: #303133;
-    margin-bottom: 3px;
-  }
-
-  .production-color {
-    color: #409eff;
-    text-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
-  }
-
-  .waste-color {
-    color: #f56c6c;
-    text-shadow: 0 2px 4px rgba(245, 108, 108, 0.3);
-  }
-
-  .consumption-color {
-    color: #e6a23c;
-    text-shadow: 0 2px 4px rgba(230, 162, 60, 0.3);
-  }
-
-  .energy-color {
-    color: #67c23a;
-    text-shadow: 0 2px 4px rgba(103, 194, 58, 0.3);
+    color: #00a4ed;
   }
 
   .stat-unit {
-    font-size: 11px;
-    color: #909399;
+    font-size: 1vh;
+    opacity: 0.7;
   }
-
-  /* 琛ㄦ牸鏍峰紡 */
-  :deep(.el-table) {
-    border-radius: 8px;
-    overflow: hidden;
-  }
-
-  :deep(.el-table th) {
-    background-color: #fafafa;
-    font-weight: 500;
-  }
-
-  :deep(.el-table tr:hover > td) {
-    background-color: #ecf5ff;
-  }
-
-  .data-value {
-    font-weight: bold;
-    color: #409eff;
-  }
-
-  /* 鎸夐挳鏍峰紡 */
-  :deep(.el-radio-button__inner) {
-    border-radius: 4px;
-  }
-
-  :deep(.el-radio-button__orig-radio:checked + .el-radio-button__inner) {
-    background-color: #409eff;
-    border-color: #409eff;
-    color: #ffffff;
-  }
-</style>
\ No newline at end of file
+</style>

--
Gitblit v1.9.3