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 | 1328 ++++++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 938 insertions(+), 390 deletions(-)

diff --git a/src/views/reportAnalysis/productionStatistics/index.vue b/src/views/reportAnalysis/productionStatistics/index.vue
index b457e61..47822ce 100644
--- a/src/views/reportAnalysis/productionStatistics/index.vue
+++ b/src/views/reportAnalysis/productionStatistics/index.vue
@@ -55,13 +55,14 @@
         </div>
         <div class="bi-panel-body">
           <div class="chart-filter-tabs">
-            <span v-for="area in salesAreas"
-                  :key="area"
+            <span v-for="name in blockMaterialList"
+                  :key="name"
                   class="cf-tab"
-                  :class="{ active: blockSelectedArea === area }"
-                  @click="handleBlockAreaChange(area)">{{ area }}</span>
+                  :class="{ active: blockSelectedMaterial === name }"
+                  @click="selectBlockMaterial(name)">{{ name }}</span>
           </div>
-          <div class="material-info-card">
+          <div v-if="blockSelectedMaterial !== '鍏ㄩ儴'"
+               class="material-info-card">
             <div class="material-icon">
               <svg width="24"
                    height="24"
@@ -74,16 +75,16 @@
               </svg>
             </div>
             <div class="material-details">
-              <div class="material-name">{{ blockMaterialType }}AAA</div>
+              <div class="material-name">{{ blockMaterialSummary.materialName || "鈥�" }}</div>
               <div class="material-stats">
                 <div class="stat-item">
                   <span class="stat-label">鏈堢疮璁″崟鑰�</span>
-                  <span class="stat-value">78/12</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">78/12</span>
+                  <span class="stat-value">{{ blockMaterialSummary.yearlyConsumption }}</span>
                   <span class="stat-unit">鍚�</span>
                 </div>
               </div>
@@ -109,6 +110,13 @@
                 @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="chart-unit-row">
             <span>鍗曚綅锛氫欢</span>
           </div>
@@ -118,28 +126,28 @@
       </div>
       <!-- 涓棿涓績鐜� -->
       <div class="center-ring">
-        <!-- <div class="center-ring-box">
-          <div class="center-metric m1">
-            <div class="center-metric-label">椤圭洰浜ч噺</div>
-            <div class="center-metric-value">{{ projectProduction }}</div>
-            <div class="center-metric-unit">浠�</div>
+        <div class="center-ring-box">
+          <div class="ring-box-topright">
+            <div class="topright-label">鍥哄簾澶勭悊閲�</div>
           </div>
-          <div class="center-metric m2">
-            <div class="center-metric-label">鍥轰綋澶勭悊閲�</div>
-            <div class="center-metric-value">{{ solidWaste澶勭悊閲� }}</div>
-            <div class="center-metric-unit">鍚�</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="center-metric m3">
-            <div class="center-metric-label">鐮屽潡浜ч噺</div>
-            <div class="center-metric-value">{{ blockProduction }}</div>
-            <div class="center-metric-unit">浠�</div>
+          <div class="ring-box-topleft">
+            <div class="topleft-label">椤圭洰浜ч噺</div>
           </div>
-          <div class="center-metric m4">
-            <div class="center-metric-label">鏉挎潗浜ч噺</div>
-            <div class="center-metric-value">{{ boardProduction }}</div>
-            <div class="center-metric-unit">浠�</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>
       </div>
       <!-- 宸︿笅锛氱敓浜ф垚鏈崟鑰楃粺璁★紙鏉挎潗锛� -->
       <div class="bi-panel bi-panel-bottom-left">
@@ -155,13 +163,14 @@
         </div>
         <div class="bi-panel-body">
           <div class="chart-filter-tabs">
-            <span v-for="area in salesAreas"
-                  :key="area"
+            <span v-for="name in boardMaterialList"
+                  :key="name"
                   class="cf-tab"
-                  :class="{ active: blockSelectedArea === area }"
-                  @click="handleBlockAreaChange(area)">{{ area }}</span>
+                  :class="{ active: boardSelectedMaterial === name }"
+                  @click="selectBoardMaterial(name)">{{ name }}</span>
           </div>
-          <div class="material-info-card">
+          <div v-if="boardSelectedMaterial !== '鍏ㄩ儴'"
+               class="material-info-card">
             <div class="material-icon">
               <svg width="24"
                    height="24"
@@ -174,16 +183,16 @@
               </svg>
             </div>
             <div class="material-details">
-              <div class="material-name">{{ boardMaterialType }}AAA</div>
+              <div class="material-name">{{ boardMaterialSummary.materialName || "鈥�" }}</div>
               <div class="material-stats">
                 <div class="stat-item">
                   <span class="stat-label">鏈堢疮璁″崟鑰�</span>
-                  <span class="stat-value">78/12</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">78/12</span>
+                  <span class="stat-value">{{ boardMaterialSummary.yearlyConsumption }}</span>
                   <span class="stat-unit">鍚�</span>
                 </div>
               </div>
@@ -208,6 +217,8 @@
                 :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>
@@ -243,12 +254,20 @@
     computed,
     onMounted,
     onBeforeUnmount,
-    watch,
     nextTick,
   } 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 screenRoot = ref(null);
   const isFullscreen = ref(false);
@@ -300,30 +319,80 @@
 
   // 閫夋嫨鍣ㄦ暟鎹�
   const blockTimeDimension = ref("year");
-  const blockMaterialType = ref("鐭崇伆");
   const boardTimeDimension = ref("year");
-  const boardMaterialType = ref("鐭崇伆");
   const productionTimeDimension = ref("year");
   const customerTimeDimension = ref("year");
   const salesTimeDimension = ref("year");
-  const selectedArea = ref("鍏ㄩ儴");
 
-  const salesAreas = [
-    "鍏ㄩ儴",
-    "鐭崇伆",
-    "姘存偿",
-    "閾濈矇鑶�",
-    "鑴辨ā鍓�",
-    "闃茶厫鍓�",
-    "姘у寲闀�",
-    "鍐锋嫈涓�",
-  ];
+  const productionCategories = ["鍏ㄩ儴", "鐮屽潡", "鏉挎潗"];
+  const productionCategory = ref("鍏ㄩ儴");
 
-  // 涓績鐜暟鎹�
-  const projectProduction = ref(12345);
-  const solidWaste澶勭悊閲� = ref(6789);
-  const blockProduction = ref(7812);
-  const boardProduction = ref(7812);
+  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;
@@ -331,47 +400,31 @@
   let productionChartInstance = null;
   let customerTrendChartInstance = null;
   let salesRankingChartInstance = null;
+  let blockCostChartResizeObserver = null;
+  let boardCostChartResizeObserver = null;
 
-  // 鐢熶骇鍗曡�楀浘琛ㄩ厤缃�
+  // 鐢熶骇鍗曡�楀浘琛ㄩ厤缃紙鐮屽潡锛屾帴鍙f暟鎹級
   const blockCostChartOption = computed(() => {
-    const materials = ["娑堣�楅噺"];
-    const colors = ["#8A6BFF"];
-    const year = 2024;
-    const periodType = blockTimeDimension.value;
-
-    // 鐢熸垚鏃堕棿娈�
-    let periods = [];
-    if (periodType === "year") {
-      // 骞村害鏁版嵁锛�6涓湀
-      for (let month = 9; month <= 12; month++) {
-        periods.push(`${month}/${year.toString().slice(2)}`);
-      }
-      for (let month = 1; month <= 3; month++) {
-        periods.push(`${month}/${(year + 1).toString().slice(2)}`);
-      }
-    } else {
-      // 鏈堝害鏁版嵁锛�30澶�
-      const month = 1;
-      for (let day = 1; day <= 30; day++) {
-        periods.push(`${month}/${day}`);
-      }
-    }
-
-    // 涓烘瘡绉嶆潗鏂欑敓鎴愭暟鎹�
-    const series = materials.map((material, index) => {
-      const data = periods.map(() => {
-        return periodType === "year"
-          ? Math.floor(Math.random() * 50) + 150
-          : Math.floor(Math.random() * 5) + 15;
-      });
-
-      return {
-        name: material,
-        data: data,
+    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[index] },
-      };
-    });
+        itemStyle: { color: colors[0] },
+      },
+      {
+        name: legendNames[1],
+        data: outputData,
+        type: "bar",
+        itemStyle: { color: colors[1] },
+      },
+    ];
 
     return {
       backgroundColor: "transparent",
@@ -382,22 +435,22 @@
         borderWidth: getResponsiveValue(1),
         textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
       },
-      // legend: {
-      //   data: materials,
-      //   top: "10%",
-      //   right: "1%",
-      //   textStyle: {
-      //     color: "#B8C8E0",
-      //     fontSize: getResponsiveValue(9),
-      //   },
-      //   itemWidth: getResponsiveValue(10),
-      //   itemHeight: getResponsiveValue(10),
-      // },
+      legend: {
+        data: legendNames,
+        top: "2%",
+        right: "1%",
+        textStyle: {
+          color: "#B8C8E0",
+          fontSize: getResponsiveValue(9),
+        },
+        itemWidth: getResponsiveValue(10),
+        itemHeight: getResponsiveValue(10),
+      },
       grid: {
         left: "1%",
         right: "1%",
-        bottom: "1%",
-        top: "8%",
+        top: "18%",
+        bottom: xMode === "material" ? "0%" : "1%",
         containLabel: true,
       },
       xAxis: {
@@ -408,7 +461,12 @@
         axisLabel: {
           color: "#B8C8E0",
           fontSize: getResponsiveValue(11),
-          margin: getResponsiveValue(10),
+          margin:
+            xMode === "material"
+              ? getResponsiveValue(6)
+              : getResponsiveValue(10),
+          rotate: xMode === "material" && periods.length > 5 ? 28 : 0,
+          interval: 0,
         },
         splitLine: { show: false },
       },
@@ -422,167 +480,32 @@
         },
         splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
       },
-      series: series,
+      series,
     };
   });
 
-  // 鏉挎潗鍗曡�楀浘琛ㄩ厤缃�
+  // 鏉挎潗鍗曡�楀浘琛ㄩ厤缃紙鎺ュ彛鏁版嵁锛屼笌鐮屽潡缁撴瀯涓�鑷达級
   const boardCostChartOption = computed(() => {
-    const materials = ["娑堣�楅噺"];
-    const colors = [
-      "#00A4ED",
-      "#34D8F7",
-      "#4A8BFF",
-      "#8A6BFF",
-      "#C8C447",
-      "#FF6B6B",
-    ];
-    const year = 2024;
-    const periodType = boardTimeDimension.value;
-
-    // 鐢熸垚鏃堕棿娈�
-    let periods = [];
-    if (periodType === "year") {
-      // 骞村害鏁版嵁锛�6涓湀
-      for (let month = 9; month <= 12; month++) {
-        periods.push(`${month}/${year.toString().slice(2)}`);
-      }
-      for (let month = 1; month <= 3; month++) {
-        periods.push(`${month}/${(year + 1).toString().slice(2)}`);
-      }
-    } else {
-      // 鏈堝害鏁版嵁锛�30澶�
-      const month = 1;
-      for (let day = 1; day <= 30; day++) {
-        periods.push(`${month}/${day}`);
-      }
-    }
-
-    // 涓烘瘡绉嶆潗鏂欑敓鎴愭暟鎹�
-    const series = materials.map((material, index) => {
-      const data = periods.map(() => {
-        return periodType === "year"
-          ? Math.floor(Math.random() * 50) + 150
-          : Math.floor(Math.random() * 5) + 15;
-      });
-
-      return {
-        name: material,
-        data: data,
+    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[index] },
-      };
-    });
-
-    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) },
+        itemStyle: { color: colors[0] },
       },
-      // legend: {
-      //   data: materials,
-      //   top: "10%",
-      //   right: "1%",
-      //   textStyle: {
-      //     color: "#B8C8E0",
-      //     fontSize: getResponsiveValue(9),
-      //   },
-      //   itemWidth: getResponsiveValue(10),
-      //   itemHeight: getResponsiveValue(10),
-      // },
-      grid: {
-        left: "1%",
-        right: "1%",
-        bottom: "1%",
-        top: "8%",
-        containLabel: true,
+      {
+        name: legendNames[1],
+        data: outputData,
+        type: "bar",
+        itemStyle: { color: colors[1] },
       },
-      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: series,
-    };
-  });
-
-  // 浜ч噺鍒嗘瀽鍥捐〃閰嶇疆
-  const productionChartOption = computed(() => {
-    const salesAreas = ["鍏ㄩ儴", "鐮屽潡", "鏉挎潗"];
-    const colors = [
-      "#00A4ED",
-      "#34D8F7",
-      "#4A8BFF",
-      "#8A6BFF",
-      "#C8C447",
-      "#FF6B6B",
     ];
-    const year = 2024;
-    const periodType = productionTimeDimension.value;
-
-    // 鐢熸垚鏃堕棿娈�
-    let periods = [];
-    if (periodType === "year") {
-      // 骞村害鏁版嵁锛�6涓湀
-      for (let month = 9; month <= 12; month++) {
-        periods.push(`${month}/${year.toString().slice(2)}`);
-      }
-      for (let month = 1; month <= 3; month++) {
-        periods.push(`${month}/${(year + 1).toString().slice(2)}`);
-      }
-    } else {
-      // 鏈堝害鏁版嵁锛�30澶�
-      const month = 1;
-      for (let day = 1; day <= 30; day++) {
-        periods.push(`${month}/${day}`);
-      }
-    }
-
-    // 涓烘瘡涓攢鍞尯鐢熸垚鏁版嵁
-    const series = salesAreas.map((area, index) => {
-      const data = periods.map(() => {
-        return periodType === "year"
-          ? Math.floor(Math.random() * 50) + 150
-          : Math.floor(Math.random() * 5) + 15;
-      });
-
-      return {
-        name: area,
-        data: data,
-        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",
@@ -594,8 +517,8 @@
         textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
       },
       legend: {
-        data: salesAreas,
-        top: "10%",
+        data: legendNames,
+        top: "2%",
         right: "1%",
         textStyle: {
           color: "#B8C8E0",
@@ -607,8 +530,105 @@
       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: "28%",
+        top: "10%",
         containLabel: true,
       },
       xAxis: {
@@ -633,59 +653,37 @@
         },
         splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
       },
-      series: series,
+      series,
     };
   });
 
-  // 鏂板瀹㈡埛瓒嬪娍鍥捐〃閰嶇疆
+  // 鍥哄簾澶勭悊閲忓浘琛紙鎺ュ彛 solidWaste锛�
   const customerTrendChartOption = computed(() => {
-    const customerTypes = ["鍏ㄩ儴", "鐭崇伆", "姘存偿", "閾濈矇鑶�", "鑴辨ā鍓�"];
-    const colors = ["#00A4ED", "#34D8F7", "#4A8BFF", "#8A6BFF", "#C8C447"];
-    const year = 2024;
-    const periodType = customerTimeDimension.value;
+    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 || [],
+    ];
 
-    // 鐢熸垚鏃堕棿娈�
-    let periods = [];
-    if (periodType === "year") {
-      // 骞村害鏁版嵁锛�6涓湀
-      for (let month = 9; month <= 12; month++) {
-        periods.push(`${month}/${year.toString().slice(2)}`);
-      }
-      for (let month = 1; month <= 5; month++) {
-        periods.push(`${month}/${(year + 1).toString().slice(2)}`);
-      }
-    } else {
-      // 鏈堝害鏁版嵁锛�30澶�
-      const month = 1;
-      for (let day = 1; day <= 30; day++) {
-        periods.push(`${month}/${day}`);
-      }
-    }
-
-    // 涓烘瘡绉嶅鎴风被鍨嬬敓鎴愭暟鎹�
-    const series = customerTypes.map((type, index) => {
-      const data = periods.map(() => {
-        return periodType === "year"
-          ? Math.floor(Math.random() * 10) + 5
-          : Math.floor(Math.random() * 3) + 1;
-      });
-
-      return {
-        name: type,
-        data: data,
-        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" },
-          ]),
-        },
-      };
-    });
+    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",
@@ -697,7 +695,7 @@
         textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
       },
       legend: {
-        data: customerTypes,
+        data: legendNames,
         top: "10%",
         right: "1%",
         textStyle: {
@@ -736,51 +734,18 @@
         },
         splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
       },
-      series: series,
+      series,
     };
   });
 
-  // 鑳借�楃粺璁″浘琛ㄩ厤缃�
+  // 鑳借�楃粺璁″浘琛ㄩ厤缃紙鎺ュ彛 energy锛�
   const salesRankingChartOption = computed(() => {
     const energyTypes = ["姘�", "鐢�", "钂告苯"];
-    const colors = ["#00A4ED", "#AC43C2", "#F5BC4A"];
-    const year = 2024;
     const periodType = salesTimeDimension.value;
-
-    // 鐢熸垚鏃堕棿娈�
-    let periods = [];
-    if (periodType === "year") {
-      // 骞村害鏁版嵁锛�6涓湀
-      for (let month = 9; month <= 12; month++) {
-        periods.push(`${month}/${year.toString().slice(2)}`);
-      }
-      for (let month = 1; month <= 3; month++) {
-        periods.push(`${month}/${(year + 1).toString().slice(2)}`);
-      }
-    } else {
-      // 鏈堝害鏁版嵁锛�7澶�
-      const month = 1;
-      for (let day = 1; day <= 7; day++) {
-        periods.push(`${month}/${day}`);
-      }
-    }
-
-    // 涓烘瘡绉嶈兘婧愮被鍨嬬敓鎴愭暟鎹�
-    const waterData = periods.map(() => {
-      return periodType === "year"
-        ? Math.floor(Math.random() * 300) + 400
-        : Math.floor(Math.random() * 30) + 40;
-    });
-    const steamData = periods.map(() => {
-      return periodType === "year"
-        ? Math.floor(Math.random() * 400) + 500
-        : Math.floor(Math.random() * 40) + 50;
-    });
-    const electricityData = periods.map(() => {
-      return periodType === "year"
-        ? Math.floor(Math.random() * 200) + 300
-        : Math.floor(Math.random() * 20) + 30;
-    });
+    const periods = energyChartSeries.value.categories || [];
+    const waterData = energyChartSeries.value.water || [];
+    const electricityData = energyChartSeries.value.electricity || [];
+    const steamData = energyChartSeries.value.steam || [];
 
     const series = [
       {
@@ -922,6 +887,447 @@
     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 = () => {
     // 鍒濆鍖栫爩鍧楁垚鏈浘琛�
@@ -952,21 +1358,37 @@
     updateCharts();
   };
 
+  /** 鐮屽潡/鏉挎潗瀹瑰櫒楂樺害鍙樺寲鍚庯紙濡傞殣钘忔眹鎬诲崱锛夐渶 resize锛屽惁鍒欏簳閮ㄧ暀鐧� */
+  const resizeCostPanelCharts = () => {
+    nextTick(() => {
+      requestAnimationFrame(() => {
+        blockCostChartInstance?.resize();
+        boardCostChartInstance?.resize();
+      });
+    });
+  };
+
   // 鏇存柊鍥捐〃
   const updateCharts = () => {
-    // 鏇存柊鐮屽潡鎴愭湰鍥捐〃
+    // 鏇存柊鐮屽潡鎴愭湰鍥捐〃锛坮eplaceMerge锛氬叏閮ㄢ啍鍗曠墿鏂欐椂妯酱鏃堕棿/鐗╂枡鍒囨崲锛�
     if (blockCostChartInstance) {
-      blockCostChartInstance.setOption(blockCostChartOption.value);
+      blockCostChartInstance.setOption(blockCostChartOption.value, {
+        replaceMerge: ["series", "xAxis"],
+      });
     }
 
     // 鏇存柊鏉挎潗鎴愭湰鍥捐〃
     if (boardCostChartInstance) {
-      boardCostChartInstance.setOption(boardCostChartOption.value);
+      boardCostChartInstance.setOption(boardCostChartOption.value, {
+        replaceMerge: ["series", "xAxis"],
+      });
     }
 
-    // 鏇存柊浜ч噺鍒嗘瀽鍥捐〃
+    // 鏇存柊浜ч噺鍒嗘瀽鍥捐〃锛坮eplaceMerge锛氬叏閮ㄢ啍鐮屽潡/鏉挎潗鍒囨崲鏃跺幓鎺夊浣欐姌绾匡紝閬垮厤鍚堝苟娈嬬暀锛�
     if (productionChartInstance) {
-      productionChartInstance.setOption(productionChartOption.value);
+      productionChartInstance.setOption(productionChartOption.value, {
+        replaceMerge: ["series"],
+      });
     }
 
     // 鏇存柊鏂板瀹㈡埛瓒嬪娍鍥捐〃
@@ -978,49 +1400,34 @@
     if (salesRankingChartInstance) {
       salesRankingChartInstance.setOption(salesRankingChartOption.value);
     }
+
+    resizeCostPanelCharts();
   };
 
   // 澶勭悊鏃堕棿缁村害閫夋嫨
   const handleBlockTimeDimensionChange = dimension => {
     blockTimeDimension.value = dimension;
-    updateCharts();
+    loadBlockCost();
   };
 
   const handleBoardTimeDimensionChange = dimension => {
     boardTimeDimension.value = dimension;
-    updateCharts();
+    loadBoardCost();
   };
 
   const handleProductionTimeDimensionChange = dimension => {
     productionTimeDimension.value = dimension;
-    updateCharts();
+    loadMaterialProduction();
   };
 
   const handleCustomerTimeDimensionChange = dimension => {
     customerTimeDimension.value = dimension;
-    updateCharts();
+    loadSolidWasteData();
   };
 
   const handleSalesTimeDimensionChange = dimension => {
     salesTimeDimension.value = dimension;
-    updateCharts();
-  };
-
-  // 澶勭悊鏉愭枡绫诲瀷閫夋嫨
-  const handleBlockMaterialTypeChange = type => {
-    blockMaterialType.value = type;
-    updateCharts();
-  };
-
-  const handleBoardMaterialTypeChange = type => {
-    boardMaterialType.value = type;
-    updateCharts();
-  };
-
-  // 澶勭悊閿�鍞尯閫夋嫨
-  const handleAreaChange = area => {
-    selectedArea.value = area;
-    updateCharts();
+    loadEnergyData();
   };
 
   // 鐩戝惉绐楀彛澶у皬鍙樺寲
@@ -1054,9 +1461,32 @@
       }, 1000);
     }
 
-    // 绛夊緟DOM鏇存柊鍚庡垵濮嬪寲鍥捐〃
-    nextTick(() => {
+    // 绛夊緟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();
     });
 
     // 娣诲姞绐楀彛澶у皬鍙樺寲鐩戝惉
@@ -1070,6 +1500,11 @@
       clearInterval(timeTicker);
       timeTicker = null;
     }
+
+    blockCostChartResizeObserver?.disconnect();
+    blockCostChartResizeObserver = null;
+    boardCostChartResizeObserver?.disconnect();
+    boardCostChartResizeObserver = null;
 
     if (blockCostChartInstance) {
       blockCostChartInstance.dispose();
@@ -1357,12 +1792,12 @@
   }
 
   /* .scroll-table tbody tr:nth-child(odd) {
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      background-color: rgba(64, 158, 255, 0.05);
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      }
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              background-color: rgba(64, 158, 255, 0.05);
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              }
 
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    .scroll-table tbody tr:nth-child(even) {
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        background-color: rgba(64, 158, 255, 0.1);
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          } */
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            .scroll-table tbody tr:nth-child(even) {
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                background-color: rgba(64, 158, 255, 0.1);
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  } */
   .oddTableTr {
     background-color: rgba(64, 158, 255, 0.05);
   }
@@ -1477,9 +1912,30 @@
     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 {
-    height: 24vh;
+    flex: 1;
+    min-height: 0;
+    height: auto;
+    width: 100%;
   }
 
   .bi-panel-bottom-right .echart-fill {
@@ -1534,11 +1990,11 @@
     grid-row: 1 / span 2;
     position: absolute;
     background: url("@/assets/BI/imageSS@2x.png") no-repeat bottom center;
-    background-size: 100% 30%;
+    background-size: 80% 30%;
     left: 25%;
     top: 25%;
-    transform: translate(-50%, -50%);
-    width: 60vh;
+    transform: translate(-50%, -45%);
+    width: 50%;
     height: 40.5vh;
     z-index: 3;
     pointer-events: none;
@@ -1546,11 +2002,103 @@
   .center-ring-box {
     position: absolute;
     /* inset: 0; */
-    height: 100%;
+    height: 88%;
     width: 100%;
+    margin-top: 3%;
     /* background-color: #fff; */
-    background: url("@/assets/BI/imageSStop.png") no-repeat center center;
-    background-size: 80% 90%;
+    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 {

--
Gitblit v1.9.3