From 51922d7093b9c8f52417bfdd0fe9aa087d1fb5be Mon Sep 17 00:00:00 2001
From: xiazhengtongxue <133085197+xiazhengtongxue@users.noreply.github.com>
Date: 星期五, 01 五月 2026 18:31:01 +0800
Subject: [PATCH] feat: 优化仓库仪表盘界面并添加电池和空托盘统计功能

---
 Code/WMS/WIDESEA_WMSClient/src/views/Home.vue |  721 +++++++++++++++++++++++++++---------------------------
 1 files changed, 358 insertions(+), 363 deletions(-)

diff --git a/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue b/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue
index 32359d5..96461c7 100644
--- a/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue
+++ b/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue
@@ -1,91 +1,78 @@
 <template>
   <div class="dashboard-container">
-    <!-- 椤堕儴KPI鍗$墖锛氭樉绀轰粨搴撴�绘暟鍜屾�诲簱瀛橀噺 -->
+    <!-- 椤堕儴KPI鍗$墖锛氭樉绀烘�昏揣浣嶅強鍚勪粨搴撹揣浣� -->
     <div class="kpi-cards">
       <div class="kpi-card">
         <div class="kpi-icon">馃彋锔�</div>
         <div class="kpi-info">
-          <div class="kpi-label">浠撳簱鎬绘暟</div>
-          <div class="kpi-value">{{ totalWarehouses }}</div>
+          <div class="kpi-label">鎬昏揣浣�</div>
+          <div class="kpi-value">{{ totalLocation }}</div>
         </div>
       </div>
       <div class="kpi-card">
-        <div class="kpi-icon">馃摝</div>
+        <div class="kpi-icon">馃敟</div>
         <div class="kpi-info">
-          <div class="kpi-label">鎬诲簱瀛橀噺</div>
-          <div class="kpi-value">{{ totalStock.toLocaleString() }}</div>
+          <div class="kpi-label">鍖栨垚搴�</div>
+          <div class="kpi-value">{{ warehouseLocations.hc }}</div>
         </div>
       </div>
       <div class="kpi-card">
-        <div class="kpi-icon">馃搳</div>
+        <div class="kpi-icon">馃尅锔�</div>
         <div class="kpi-info">
-          <div class="kpi-label">鏈湀鎬诲叆搴�</div>
-          <div class="kpi-value">{{ monthlyInboundTotal.toLocaleString() }}</div>
+          <div class="kpi-label">楂樻俯搴�</div>
+          <div class="kpi-value">{{ warehouseLocations.gw }}</div>
         </div>
       </div>
       <div class="kpi-card">
-        <div class="kpi-icon">馃摛</div>
+        <div class="kpi-icon">鉂勶笍</div>
         <div class="kpi-info">
-          <div class="kpi-label">鏈湀鎬诲嚭搴�</div>
-          <div class="kpi-value">{{ monthlyOutboundTotal.toLocaleString() }}</div>
+          <div class="kpi-label">甯告俯搴�</div>
+          <div class="kpi-value">{{ warehouseLocations.cw }}</div>
+        </div>
+      </div>
+      <div class="kpi-card">
+        <div class="kpi-icon">馃摐</div>
+        <div class="kpi-info">
+          <div class="kpi-label">鏋佸嵎搴�</div>
+          <div class="kpi-value">{{ warehouseLocations.jj }}</div>
         </div>
       </div>
     </div>
 
-    <!-- 椤堕儴锛氭湰鏈堝嚭鍏ュ簱瓒嬪娍 - 涓�3涓�2甯冨眬锛屾瘡涓崱鐗囩洿鎺ユ樉绀轰粨搴撴暟瀛� -->
-    <div class="chart-row top-three">
-      <div v-for="warehouse in topWarehouses" :key="warehouse.code" class="chart-card">
-        <div class="card-title">{{ warehouse.name }}</div>
-        <!-- 浠撳簱鏁板瓧鏄剧ず鍖哄煙 -->
+    <!-- 绗竴琛岋細4涓瘡鏃ュ嚭鍏ュ簱瓒嬪娍鍥撅紙姣忚2涓級 -->
+    <div class="chart-row daily-grid">
+      <div class="chart-card" v-for="warehouse in dailyWarehouses" :key="warehouse.code">
+        <div class="card-title">{{ warehouse.name }} - 姣忔棩瓒嬪娍</div>
+        <!-- 浠撳簱鏁板瓧鏄剧ず鍖哄煙锛氭樉绀烘瘡鏃ユ�婚噺鍜岀┖鎵樼洏鏁伴噺 -->
         <div class="warehouse-numbers">
-          <div class="number-item inbound">
-            <span class="number-label">鍏ュ簱</span>
-            <span class="number-value">{{ getMonthlyInbound(warehouse.code) }}</span>
-          </div>
-          <div class="number-item outbound">
-            <span class="number-label">鍑哄簱</span>
-            <span class="number-value">{{ getMonthlyOutbound(warehouse.code) }}</span>
-          </div>
-          <div class="number-item stock">
-            <span class="number-label">搴撳瓨</span>
-            <span class="number-value">{{ getWarehouseStock(warehouse.code) }}</span>
-          </div>
+          <!-- 鏋佸嵎搴撴樉绀烘湁璐ф墭鐩橈紙鐢垫睜鏁伴噺锛夊拰绌烘墭鐩� -->
+          <template v-if="warehouse.code === 'ROLL'">
+            <div class="number-item battery">
+              <span class="number-label">鐢垫睜鏁伴噺</span>
+              <span class="number-value">{{ getBatteryCount(warehouse.code) }}</span>
+            </div>
+            <div class="number-item empty-tray">
+              <span class="number-label">绌烘墭鐩樻暟閲�</span>
+              <span class="number-value">{{ getEmptyTrayCount(warehouse.code) }}</span>
+            </div>
+          </template>
+          <!-- 鍏朵粬浠撳簱鏄剧ず鐢垫睜鏁伴噺鍜岀┖鎵樼洏鏁伴噺 -->
+          <template v-else>
+            <div class="number-item inbound">
+              <span class="number-label">鐢垫睜鏁伴噺</span>
+              <span class="number-value">{{ getBatteryCount(warehouse.code) }}</span>
+            </div>
+            <div class="number-item empty-tray">
+              <span class="number-label">绌烘墭鐩樻暟閲�</span>
+              <span class="number-value">{{ getEmptyTrayCount(warehouse.code) }}</span>
+            </div>
+          </template>
         </div>
-        <div :id="`chart-${warehouse.code}`" class="chart-content"></div>
+        <div :id="`daily-chart-${warehouse.code}`" class="chart-content"></div>
       </div>
     </div>
 
-    <div class="chart-row bottom-two">
-      <div v-for="warehouse in bottomWarehouses" :key="warehouse.code" class="chart-card">
-        <div class="card-title">{{ warehouse.name }}</div>
-        <!-- 浠撳簱鏁板瓧鏄剧ず鍖哄煙 -->
-        <div class="warehouse-numbers">
-          <div class="number-item inbound">
-            <span class="number-label">鍏ュ簱</span>
-            <span class="number-value">{{ getMonthlyInbound(warehouse.code) }}</span>
-          </div>
-          <div class="number-item outbound">
-            <span class="number-label">鍑哄簱</span>
-            <span class="number-value">{{ getMonthlyOutbound(warehouse.code) }}</span>
-          </div>
-          <div class="number-item stock">
-            <span class="number-label">搴撳瓨</span>
-            <span class="number-value">{{ getWarehouseStock(warehouse.code) }}</span>
-          </div>
-        </div>
-        <div :id="`chart-${warehouse.code}`" class="chart-content"></div>
-      </div>
-    </div>
-
-    <!-- 姣忔棩鍑哄叆搴撹秼鍔� (鍏ㄥ) -->
-    <div class="chart-row full-width">
-      <div class="chart-card">
-        <div class="card-title">姣忔棩鍑哄叆搴撹秼鍔�</div>
-        <div id="chart-daily" class="chart-content"></div>
-      </div>
-    </div>
-
-    <!-- 浠撳簱鍒嗗竷 -->
+    <!-- 浠撳簱鍒嗗竷锛堟煴鐘跺浘锛屾樉绀哄悇浠撳簱宸茬敤/鍓╀綑瀹归噺锛� -->
     <div class="chart-row">
       <div class="chart-card">
         <div class="card-title">鍚勪粨搴撳簱瀛樺垎甯�</div>
@@ -103,41 +90,54 @@
   data() {
     return {
       charts: {},
-      // 浜斾釜浠撳簱瀹氫箟 - 涓�3涓�
-      topWarehouses: [
-        { code: "GWSC1", name: "楂樻俯1鍙蜂粨搴�" },
-        { code: "CWSC1", name: "甯告俯1鍙蜂粨搴�" },
-        { code: "HCSC1", name: "鍒嗗1鍙蜂粨搴�" }
+      // 鍥涗釜鏍稿績浠撳簱锛堝悎骞朵簡姝h礋鏋佸嵎搴撲负鏋佸嵎搴擄級
+      dailyWarehouses: [
+        { code: "HCSC1", name: "鍖栨垚搴�", type: "hc" },
+        { code: "GWSC1", name: "楂樻俯搴�", type: "gw" },
+        { code: "CWSC1", name: "甯告俯搴�", type: "cw" },
+        { code: "ROLL", name: "鏋佸嵎搴�", type: "jj" }
       ],
-      // 涓�2涓�
-      bottomWarehouses: [
-        { code: "FJSC1", name: "璐熸瀬鍗�1鍙蜂粨搴�" },
-        { code: "ZJSC1", name: "姝f瀬鍗�1鍙蜂粨搴�" }
-      ],
-      dailyData: [],
-      // 瀛樺偍姣忎釜浠撳簱鐨勬湀搴︽暟鎹�
-      monthlyData: {
+      // 鍘熷姣忔棩鏁版嵁瀛樺偍 (鍏朵腑ROLL涓哄悎骞跺悗鐨勬瀬鍗峰簱鏁版嵁)
+      dailyDataMap: {
         GWSC1: [],
         CWSC1: [],
         HCSC1: [],
-        FJSC1: [],
-        ZJSC1: []
+        ROLL: []
       },
-      // 瀛樺偍姣忎釜浠撳簱鐨勫綋鍓嶅簱瀛�
+      // 瀛樺偍姣忎釜浠撳簱鐨勭數姹犳暟閲�
       warehouseStocks: {
         GWSC1: 0,
         CWSC1: 0,
         HCSC1: 0,
-        FJSC1: 0,
-        ZJSC1: 0
+        ROLL: 0
       },
-      warehouseData: [],
-      // KPI 姹囨�绘暟鎹�
-      totalWarehouses: 5,
-      totalStock: 0,
-      monthlyInboundTotal: 0,
-      monthlyOutboundTotal: 0
+      // 鏋佸嵎搴撶壒娈婃暟鎹�
+      rollData: {
+        batteryCount: 0,    // 鐢垫睜鏁伴噺
+        emptyTrayCount: 0   // 绌烘墭鐩樻暟閲�
+      },
+      // 鍏朵粬浠撳簱鐨勭┖鎵樼洏鏁伴噺
+      emptyTrayCounts: {
+        GWSC1: 0,
+        CWSC1: 0,
+        HCSC1: 0
+      },
+      warehouseData: [],     // 浠撳簱鍒嗗竷鍥炬暟鎹�
+      // 浠撳簱璐т綅鏁版嵁锛堝浐瀹氶厤缃級
+      warehouseLocations: {
+        hc: 35,   // 鍖栨垚搴�
+        gw: 324,  // 楂樻俯搴�
+        cw: 140,  // 甯告俯搴�
+        jj: 104   // 鏋佸嵎搴�
+      }
     };
+  },
+  computed: {
+    // 鎬昏揣浣嶈绠�
+    totalLocation() {
+      return this.warehouseLocations.hc + this.warehouseLocations.gw + 
+             this.warehouseLocations.cw + this.warehouseLocations.jj;
+    }
   },
   mounted() {
     this.initCharts();
@@ -154,181 +154,265 @@
     },
 
     initCharts() {
-      // 鍒濆鍖栨墍鏈変粨搴撳浘琛�
-      const allWarehouses = [...this.topWarehouses, ...this.bottomWarehouses];
-      allWarehouses.forEach(warehouse => {
-        const chartId = `chart-${warehouse.code}`;
+      // 鍒濆鍖栨瘡鏃ュ浘琛�
+      this.dailyWarehouses.forEach(warehouse => {
+        const chartId = `daily-chart-${warehouse.code}`;
         const el = document.getElementById(chartId);
         if (el) {
-          this.charts[warehouse.code] = echarts.init(el);
+          this.charts[`daily-${warehouse.code}`] = echarts.init(el);
         }
       });
-      // 鍒濆鍖栨瘡鏃ュ浘琛ㄥ拰浠撳簱鍒嗗竷鍥捐〃
-      this.charts.daily = echarts.init(document.getElementById("chart-daily"));
+      // 鍒濆鍖栦粨搴撳垎甯冨浘琛�
       this.charts.warehouse = echarts.init(document.getElementById("chart-warehouse"));
     },
 
     async loadData() {
-      // 骞惰鍔犺浇鎵�鏈変粨搴撶殑鏈堝害鏁版嵁锛堝垎鍒紶鍏ヤ笉鍚岀殑Roadway鍙傛暟锛�
-      const allWarehouses = [...this.topWarehouses, ...this.bottomWarehouses];
-      const monthlyPromises = allWarehouses.map(warehouse =>
-        this.loadMonthlyStatsForWarehouse(warehouse.code)
-      );
-      await Promise.all(monthlyPromises);
-      // 鏇存柊鎵�鏈変粨搴撶殑鏈堝害鍥捐〃
-      this.updateAllMonthlyTrendCharts();
-
-      await this.loadDailyStats();
-      await this.loadStockByWarehouse();
-      await this.loadWarehouseStocks();
-      this.calculateKPIs();
-    },
-
-    async loadMonthlyStatsForWarehouse(roadway) {
-      console.log(`姝e湪鍔犺浇${roadway}鐨勬瘡鏈堢粺璁℃暟鎹�...`);
       try {
-        // 鍏抽敭淇锛氬垎鍒紶鍏ヤ笉鍚岀殑Roadway鍙傛暟
-        const res = await this.http.get("/api/Dashboard/MonthlyStats?monthly=12&roadway=" + roadway);
-        if (res.status && res.data) {
-          console.log(`${roadway} 姣忔湀缁熻鏁版嵁:`, res.data);
-          this.monthlyData[roadway] = res.data;
-        } else {
-          this.monthlyData[roadway] = [];
-        }
-      } catch (e) {
-        console.error(`鍔犺浇${roadway}姣忔湀缁熻澶辫触`, e);
-        this.monthlyData[roadway] = [];
+        // 骞惰鍔犺浇鎵�鏈夋暟鎹�
+        await Promise.all([
+          this.loadAllDailyStats(),
+          this.loadStockAndTrayCount(),
+          this.loadStockByWarehouse()
+        ]);
+        
+        // 鏇存柊鎵�鏈夊浘琛�
+        this.updateAllDailyCharts();
+      } catch (error) {
+        console.error("鍔犺浇鏁版嵁澶辫触:", error);
+        this.$message?.error("鏁版嵁鍔犺浇澶辫触锛岃绋嶅悗閲嶈瘯");
       }
     },
 
-    async loadDailyStats() {
-      try {
-        const res = await this.http.get("/api/Dashboard/DailyStats", { days: 30 });
-        if (res.status && res.data) {
-          console.log("姣忔棩缁熻鏁版嵁:", res.data);
-          this.dailyData = res.data;
-          this.updateDailyChart();
-        }
-      } catch (e) {
-        console.error("鍔犺浇姣忔棩缁熻澶辫触", e);
+    async loadAllDailyStats() {
+      console.log("姝e湪鍔犺浇鎵�鏈変粨搴撶殑姣忔棩缁熻鏁版嵁...");
+      const res = await this.http.get("/api/Dashboard/DailyStats?days=10");
+      if (res.status && res.data) {
+        console.log("鎵�鏈変粨搴撴瘡鏃ョ粺璁℃暟鎹�:", res.data);
+        
+        const dataArray = res.data;
+        
+        // 鎸変粨搴撳垎绫绘暟鎹�
+        dataArray.forEach(item => {
+          const roadway = item.roadway;
+          const dailyStats = item.dailyStats || [];
+          
+          switch(roadway) {
+            case "GWSC1":
+              this.dailyDataMap.GWSC1 = dailyStats;
+              break;
+            case "CWSC1":
+              this.dailyDataMap.CWSC1 = dailyStats;
+              break;
+            case "HCSC1":
+              this.dailyDataMap.HCSC1 = dailyStats;
+              break;
+            case "ZJSC1":
+            case "FJSC1":
+              // 鏋佸嵎搴撴暟鎹悎骞跺鐞�
+              this.mergeRollDailyStats(dailyStats);
+              break;
+          }
+        });
+        
+        console.log("GWSC1鏁版嵁:", this.dailyDataMap.GWSC1);
+        console.log("CWSC1鏁版嵁:", this.dailyDataMap.CWSC1);
+        console.log("HCSC1鏁版嵁:", this.dailyDataMap.HCSC1);
+        console.log("鏋佸嵎搴撳悎骞舵暟鎹�:", this.dailyDataMap.ROLL);
+      } else {
+        console.error("鑾峰彇姣忔棩鏁版嵁澶辫触");
+      }
+    },
+
+    mergeRollDailyStats(newData) {
+      // 鍚堝苟姝f瀬鍗峰簱鍜岃礋鏋佸嵎搴撶殑姣忔棩鏁版嵁
+      if (!this.dailyDataMap.ROLL.length) {
+        this.dailyDataMap.ROLL = [...newData];
+      } else {
+        const dateMap = new Map();
+        [...this.dailyDataMap.ROLL, ...newData].forEach(item => {
+          const date = item.date;
+          if (date) {
+            if (!dateMap.has(date)) {
+              dateMap.set(date, { date, inbound: 0, outbound: 0 });
+            }
+            const existing = dateMap.get(date);
+            existing.inbound += item.inbound || 0;
+            existing.outbound += item.outbound || 0;
+          }
+        });
+        
+        const sortedDates = Array.from(dateMap.keys()).sort();
+        const mergedData = sortedDates.map(date => dateMap.get(date));
+        this.dailyDataMap["ROLL"] = mergedData;
+      }
+    },
+
+    async loadStockAndTrayCount() {
+      // 鍔犺浇鐢垫睜鏁伴噺鍜岀┖鎵樼洏鏁伴噺
+      console.log("姝e湪鍔犺浇鐢垫睜鏁伴噺鍜岀┖鎵樼洏鏁版嵁...");
+      const res = await this.http.get("/api/Dashboard/StockAndTrayCount");
+      
+      if (res.status && res.data) {
+        console.log("鐢垫睜鍜岀┖鎵樼洏鏁版嵁:", res.data);
+        
+        // 閲嶇疆鏁版嵁
+        this.rollData.batteryCount = 0;
+        this.rollData.emptyTrayCount = 0;
+        
+        // 鏍规嵁杩斿洖鐨勬暟鎹粨鏋勮В鏋�
+        res.data.forEach(item => {
+          const warehouseName = item.warehouseName;
+          const batteryCount = item.batteryCount || 0;
+          const emptyTrayCount = item.emptyTrayCount || 0;
+          
+          // 鏍规嵁浠撳簱鍚嶇О鏄犲皠鍒板搴旂殑浠g爜
+          if (warehouseName === "楂樻俯搴�") {
+            this.emptyTrayCounts.GWSC1 = emptyTrayCount;
+            this.warehouseStocks.GWSC1 = batteryCount;
+          } else if (warehouseName === "甯告俯搴�") {
+            this.emptyTrayCounts.CWSC1 = emptyTrayCount;
+            this.warehouseStocks.CWSC1 = batteryCount;
+          } else if (warehouseName === "鍖栨垚搴�") {
+            this.emptyTrayCounts.HCSC1 = emptyTrayCount;
+            this.warehouseStocks.HCSC1 = batteryCount;
+          } else if (warehouseName === "鏋佸嵎搴�") {
+            // 鏋佸嵎搴撻渶瑕佸悎骞朵袱涓瀬鍗峰簱鐨勬暟鎹�
+            this.rollData.batteryCount += batteryCount;
+            this.rollData.emptyTrayCount += emptyTrayCount;
+          }
+        });
+        
+        // 璁剧疆鏋佸嵎搴撴�荤數姹犳暟閲�
+        this.warehouseStocks.ROLL = this.rollData.batteryCount;
+        
+        console.log("鐗规畩鏁版嵁鍔犺浇瀹屾垚:", { 
+          rollData: this.rollData, 
+          emptyTrayCounts: this.emptyTrayCounts,
+          warehouseStocks: this.warehouseStocks
+        });
+      } else {
+        console.error("鑾峰彇鐢垫睜鍜岀┖鎵樼洏鏁版嵁澶辫触");
+        throw new Error("鑾峰彇鐢垫睜鍜岀┖鎵樼洏鏁版嵁澶辫触");
       }
     },
 
     async loadStockByWarehouse() {
-      try {
-        const res = await this.http.get("/api/Dashboard/StockByWarehouse");
-        if (res.status && res.data) {
-          console.log("浠撳簱鍒嗗竷鏁版嵁:", res.data);
-          this.warehouseData = res.data.data || res.data;
-          this.updateWarehouseChart();
-        }
-      } catch (e) {
-        console.error("鍔犺浇浠撳簱鍒嗗竷澶辫触", e);
-      }
-    },
-
-    async loadWarehouseStocks() {
-      // 妯℃嫙鍔犺浇姣忎釜浠撳簱鐨勫綋鍓嶅簱瀛橀噺
-      // 濡傛灉鍚庣鏈夋帴鍙o紝鍙互鏇挎崲涓虹湡瀹濧PI璋冪敤
-      try {
-        // 灏濊瘯鍔犺浇搴撳瓨鏁版嵁锛屽鏋滄帴鍙d笉瀛樺湪鍒欎娇鐢ㄦā鎷熸暟鎹�
-        const allWarehouses = [...this.topWarehouses, ...this.bottomWarehouses];
-        for (const warehouse of allWarehouses) {
-          try {
-            const res = await this.http.get(`/api/Dashboard/WarehouseStock?warehouse=${warehouse.code}`);
-            if (res.status && res.data) {
-              this.warehouseStocks[warehouse.code] = res.data.stock || 0;
-            } else {
-              // 浠庢湀搴︽暟鎹腑璁$畻妯℃嫙搴撳瓨锛堟渶杩戞湀浠界疮璁″叆搴�-鍑哄簱锛�
-              const monthlyData = this.monthlyData[warehouse.code] || [];
-              let totalInbound = 0;
-              let totalOutbound = 0;
-              monthlyData.forEach(m => {
-                totalInbound += (m.inbound ?? m.Inbound) || 0;
-                totalOutbound += (m.outbound ?? m.Outbound) || 0;
-              });
-              this.warehouseStocks[warehouse.code] = Math.max(0, totalInbound - totalOutbound);
-            }
-          } catch (e) {
-            // 浣跨敤妯℃嫙鏁版嵁
-            const mockStocks = {
-              GWSC1: 12580,
-              CWSC1: 8920,
-              HCSC1: 15600,
-              FJSC1: 4300,
-              ZJSC1: 7200
-            };
-            this.warehouseStocks[warehouse.code] = mockStocks[warehouse.code] || 0;
+      console.log("姝e湪鍔犺浇浠撳簱鍒嗗竷鏁版嵁...");
+      const res = await this.http.get("/api/Dashboard/StockByWarehouse");
+      
+      if (res.status && res.data) {
+        console.log("浠撳簱鍒嗗竷鏁版嵁:", res.data);
+        const rawData = res.data.data || res.data;
+        
+        // 澶勭悊鏋佸嵎搴撳悎骞�
+        let rollHasStock = 0;
+        let rollNoStock = 0;
+        let rollTotal = 0;
+        const otherWarehouses = [];
+        
+        rawData.forEach(item => {
+          if (item.warehouse === "鏋佸嵎搴�" || item.warehouse.includes("鏋佸嵎搴�")) {
+            // 鍚堝苟鏋佸嵎搴撴暟鎹�
+            rollHasStock += item.hasStock || 0;
+            rollNoStock += item.noStock || 0;
+            rollTotal += item.total || 0;
+          } else {
+            otherWarehouses.push(item);
           }
+        });
+        
+        // 娣诲姞鍚堝苟鍚庣殑鏋佸嵎搴�
+        if (rollTotal > 0) {
+          const hasStockPercentage = ((rollHasStock / rollTotal) * 100).toFixed(1) + "%";
+          const noStockPercentage = ((rollNoStock / rollTotal) * 100).toFixed(1) + "%";
+          
+          otherWarehouses.push({
+            warehouse: "鏋佸嵎搴�",
+            hasStock: rollHasStock,
+            noStock: rollNoStock,
+            total: rollTotal,
+            hasStockPercentage: hasStockPercentage,
+            noStockPercentage: noStockPercentage
+          });
         }
-      } catch (e) {
-        console.error("鍔犺浇浠撳簱搴撳瓨澶辫触", e);
+        
+        this.warehouseData = otherWarehouses;
+        this.updateWarehouseChart();
+      } else {
+        console.error("鑾峰彇浠撳簱鍒嗗竷鏁版嵁澶辫触");
+        throw new Error("鑾峰彇浠撳簱鍒嗗竷鏁版嵁澶辫触");
       }
     },
 
-    getMonthlyInbound(warehouseCode) {
-      const data = this.monthlyData[warehouseCode] || [];
-      if (data.length === 0) return 0;
-      // 鑾峰彇鏈�杩戜竴涓湀锛堟渶鍚庝竴鏉★級鐨勫叆搴撴暟
-      const latest = data[data.length - 1];
-      return (latest.inbound ?? latest.Inbound) || 0;
+    getDailyTotalInbound(warehouseCode) {
+      const data = this.dailyDataMap[warehouseCode] || [];
+      return data.reduce((sum, item) => sum + (item.inbound || 0), 0);
     },
 
-    getMonthlyOutbound(warehouseCode) {
-      const data = this.monthlyData[warehouseCode] || [];
-      if (data.length === 0) return 0;
-      // 鑾峰彇鏈�杩戜竴涓湀锛堟渶鍚庝竴鏉★級鐨勫嚭搴撴暟
-      const latest = data[data.length - 1];
-      return (latest.outbound ?? latest.Outbound) || 0;
+    getDailyTotalOutbound(warehouseCode) {
+      const data = this.dailyDataMap[warehouseCode] || [];
+      return data.reduce((sum, item) => sum + (item.outbound || 0), 0);
     },
 
     getWarehouseStock(warehouseCode) {
       return this.warehouseStocks[warehouseCode] || 0;
     },
 
-    calculateKPIs() {
-      // 璁$畻鎬诲簱瀛�
-      let totalStock = 0;
-      for (const code in this.warehouseStocks) {
-        totalStock += this.warehouseStocks[code];
+    getBatteryCount(warehouseCode) {
+      if (warehouseCode === 'ROLL') {
+        return this.rollData.batteryCount;
+      } else if (warehouseCode === 'GWSC1') {
+        return this.warehouseStocks.GWSC1;
+      } else if (warehouseCode === 'CWSC1') {
+        return this.warehouseStocks.CWSC1;
+      } else if (warehouseCode === 'HCSC1') {
+        return this.warehouseStocks.HCSC1;
       }
-      this.totalStock = totalStock;
-
-      // 璁$畻鏈湀鎬诲叆搴撳拰鎬诲嚭搴擄紙鎵�鏈変粨搴撴渶杩戜竴涓湀鐨勫悎璁★級
-      let totalInbound = 0;
-      let totalOutbound = 0;
-      const allWarehouses = [...this.topWarehouses, ...this.bottomWarehouses];
-      allWarehouses.forEach(warehouse => {
-        totalInbound += this.getMonthlyInbound(warehouse.code);
-        totalOutbound += this.getMonthlyOutbound(warehouse.code);
-      });
-      this.monthlyInboundTotal = totalInbound;
-      this.monthlyOutboundTotal = totalOutbound;
+      return 0;
     },
 
-    // 鏇存柊鎵�鏈変粨搴撶殑鏈堝害瓒嬪娍鍥捐〃
-    updateAllMonthlyTrendCharts() {
-      const allWarehouses = [...this.topWarehouses, ...this.bottomWarehouses];
-      allWarehouses.forEach(warehouse => {
-        this.updateMonthlyTrendChartForWarehouse(warehouse.code);
+    getEmptyTrayCount(warehouseCode) {
+      if (warehouseCode === 'ROLL') {
+        return this.rollData.emptyTrayCount;
+      } else if (warehouseCode === 'GWSC1') {
+        return this.emptyTrayCounts.GWSC1;
+      } else if (warehouseCode === 'CWSC1') {
+        return this.emptyTrayCounts.CWSC1;
+      } else if (warehouseCode === 'HCSC1') {
+        return this.emptyTrayCounts.HCSC1;
+      }
+      return 0;
+    },
+
+    updateAllDailyCharts() {
+      this.dailyWarehouses.forEach(warehouse => {
+        this.updateDailyChartForWarehouse(warehouse.code);
       });
     },
 
-    updateMonthlyTrendChartForWarehouse(roadway) {
-      const chart = this.charts[roadway];
+    updateDailyChartForWarehouse(roadway) {
+      const chart = this.charts[`daily-${roadway}`];
       if (!chart) return;
 
-      const data = this.monthlyData[roadway] || [];
-      // 鍏煎澶у皬鍐欏瓧娈靛悕
-      const monthLabels = data.map(m => m.month || m.Month || "");
-      const inboundData = data.map(m => {
-        const val = m.inbound ?? m.Inbound;
-        return val !== undefined && val !== null ? Number(val) : 0;
-      });
-      const outboundData = data.map(m => {
-        const val = m.outbound ?? m.Outbound;
-        return val !== undefined && val !== null ? Number(val) : 0;
-      });
+      const data = this.dailyDataMap[roadway] || [];
+      
+      // 濡傛灉娌℃湁鏁版嵁锛屾樉绀虹┖鍥捐〃鎻愮ず
+      if (!data.length) {
+        chart.setOption({
+          title: {
+            show: true,
+            text: '鏆傛棤鏁版嵁',
+            left: 'center',
+            top: 'center',
+            textStyle: { color: '#ccc', fontSize: 14 }
+          }
+        }, true);
+        return;
+      }
+
+      const dates = data.map(d => d.date);
+      const inboundData = data.map(d => d.inbound || 0);
+      const outboundData = data.map(d => d.outbound || 0);
 
       const option = {
         tooltip: { 
@@ -358,7 +442,7 @@
         },
         xAxis: {
           type: "category",
-          data: monthLabels,
+          data: dates,
           axisLabel: {
             color: "#ccc",
             rotate: 45,
@@ -370,7 +454,7 @@
         },
         yAxis: {
           type: "value",
-          name: "浠诲姟鏁伴噺",
+          name: "鏁伴噺",
           nameTextStyle: { color: "#ccc", fontSize: 11 },
           axisLabel: { color: "#ccc" },
           splitLine: { lineStyle: { color: "#2a3a4a", type: "dashed" } }
@@ -384,12 +468,13 @@
               color: "#5470c6",
               borderRadius: [4, 4, 0, 0]
             },
-            barWidth: "35%",
+            barWidth: "40%",
             label: {
-              show: inboundData.length <= 8,
+              show: true,
               position: "top",
               color: "#5470c6",
-              fontSize: 10
+              fontSize: 10,
+              formatter: (params) => params.value
             }
           },
           {
@@ -402,10 +487,11 @@
             lineStyle: { width: 2, type: "solid" },
             smooth: false,
             label: {
-              show: outboundData.length <= 8,
+              show: true,
               position: "top",
               color: "#91cc75",
-              fontSize: 10
+              fontSize: 10,
+              formatter: (params) => params.value
             }
           }
         ]
@@ -413,56 +499,22 @@
       chart.setOption(option, true);
     },
 
-    updateDailyChart() {
-      if (!this.charts.daily) return;
-      const option = {
-        tooltip: { trigger: "axis" },
-        legend: { data: ["鍏ュ簱", "鍑哄簱"], textStyle: { color: "#fff" } },
-        xAxis: {
-          type: "category",
-          data: this.dailyData.map(d => d.date),
-          axisLabel: {
-            color: "#fff",
-            interval: 0,
-            rotate: 45,
-            fontSize: 12,
-            margin: 10
-          },
-          axisTick: {
-            alignWithLabel: true
-          }
-        },
-        yAxis: {
-          type: "value",
-          axisLabel: { color: "#fff" }
-        },
-        grid: {
-          left: "3%",
-          right: "4%",
-          bottom: "15%",
-          top: "10%",
-          containLabel: true
-        },
-        series: [
-          {
-            name: "鍏ュ簱",
-            type: "bar",
-            data: this.dailyData.map(d => d.inbound),
-            itemStyle: { color: "#5470c6" }
-          },
-          {
-            name: "鍑哄簱",
-            type: "bar",
-            data: this.dailyData.map(d => d.outbound),
-            itemStyle: { color: "#91cc75" }
-          }
-        ]
-      };
-      this.charts.daily.setOption(option, true);
-    },
-
     updateWarehouseChart() {
       if (!this.charts.warehouse) return;
+      
+      if (!this.warehouseData.length) {
+        this.charts.warehouse.setOption({
+          title: {
+            show: true,
+            text: '鏆傛棤浠撳簱鏁版嵁',
+            left: 'center',
+            top: 'center',
+            textStyle: { color: '#ccc' }
+          }
+        });
+        return;
+      }
+      
       const warehouseNames = this.warehouseData.map(w => w.warehouse);
       const hasStocks = this.warehouseData.map(w => w.hasStock);
       const noStocks = this.warehouseData.map(w => w.noStock);
@@ -472,14 +524,12 @@
       const option = {
         tooltip: {
           trigger: "axis",
-          axisPointer: {
-            type: "shadow"
-          },
-          formatter: function(params) {
+          axisPointer: { type: "shadow" },
+          formatter: (params) => {
             let tip = params[0].name + "<br/>";
             params.forEach(param => {
               const dataIndex = param.dataIndex;
-              const warehouse = window.homeComponent?.warehouseData[dataIndex];
+              const warehouse = this.warehouseData[dataIndex];
               if (warehouse) {
                 if (param.seriesName === "宸茬敤瀹归噺") {
                   tip += `${param.marker}${param.seriesName}: ${param.value} (${warehouse.hasStockPercentage})<br/>`;
@@ -519,9 +569,9 @@
               label: {
                 show: true,
                 position: "top",
-                formatter: (params) => {
-                  const pct = hasStockPercentages[params.dataIndex];
-                  return `${params.value} (${pct})`;
+                formatter: () => {
+                  const pct = hasStockPercentages[index];
+                  return `${value} (${pct})`;
                 },
                 color: "#91cc75",
                 fontSize: 11
@@ -537,9 +587,9 @@
               label: {
                 show: true,
                 position: "top",
-                formatter: (params) => {
-                  const pct = noStockPercentages[params.dataIndex];
-                  return `${params.value} (${pct})`;
+                formatter: () => {
+                  const pct = noStockPercentages[index];
+                  return `${value} (${pct})`;
                 },
                 color: "#fac858",
                 fontSize: 11
@@ -550,7 +600,6 @@
         ]
       };
 
-      window.homeComponent = this;
       this.charts.warehouse.setOption(option, true);
     }
   }
@@ -566,10 +615,10 @@
   background-attachment: fixed;
 }
 
-/* KPI 鍗$墖鏍峰紡 */
+/* KPI 鍗$墖鏍峰紡 - 5鍒楀竷灞� */
 .kpi-cards {
   display: grid;
-  grid-template-columns: repeat(4, 1fr);
+  grid-template-columns: repeat(5, 1fr);
   gap: 20px;
   margin-bottom: 24px;
 }
@@ -617,24 +666,11 @@
   line-height: 1.2;
 }
 
-/* 涓�3涓浘琛ㄥ竷灞� */
-.chart-row.top-three {
-  display: grid;
-  grid-template-columns: repeat(3, 1fr);
-  gap: 20px;
-  margin-bottom: 20px;
-}
-
-/* 涓�2涓浘琛ㄥ竷灞� */
-.chart-row.bottom-two {
+/* 姣忔棩鍥捐〃甯冨眬 - 姣忚2涓� */
+.chart-row.daily-grid {
   display: grid;
   grid-template-columns: repeat(2, 1fr);
   gap: 20px;
-  margin-bottom: 20px;
-}
-
-.chart-row.full-width {
-  width: 100%;
   margin-bottom: 20px;
 }
 
@@ -680,23 +716,6 @@
   box-shadow: 2px -2px 10px #00ffff, 0 0 10px rgba(0, 255, 255, 0.7);
 }
 
-.chart-card::before,
-.chart-card::after {
-  animation: neon-flicker 2s infinite alternate;
-}
-
-@keyframes neon-flicker {
-  0%,
-  100% {
-    opacity: 1;
-    box-shadow: -2px -2px 10px #00ffff, 0 0 10px rgba(0, 255, 255, 0.7);
-  }
-  50% {
-    opacity: 0.8;
-    box-shadow: -2px -2px 5px #00ffff, 0 0 5px rgba(0, 255, 255, 0.5);
-  }
-}
-
 .card-title {
   color: #00ffff;
   font-size: 15px;
@@ -717,11 +736,13 @@
   padding: 8px 0;
   background: rgba(0, 0, 0, 0.3);
   border-radius: 8px;
+  flex-wrap: wrap;
 }
 
 .number-item {
   text-align: center;
   flex: 1;
+  min-width: 80px;
 }
 
 .number-label {
@@ -733,7 +754,7 @@
 
 .number-value {
   display: block;
-  font-size: 20px;
+  font-size: 18px;
   font-weight: 700;
   letter-spacing: 1px;
 }
@@ -742,67 +763,41 @@
   color: #5470c6;
 }
 
-.number-item.outbound .number-value {
-  color: #91cc75;
+.number-item.battery .number-value {
+  color: #ee6666;
 }
 
-.number-item.stock .number-value {
-  color: #fac858;
+.number-item.empty-tray .number-value {
+  color: #fc8452;
 }
 
 .chart-content {
-  height: 240px;
+  height: 280px;
   width: 100%;
-}
-
-/* 鍏ㄥ鍥捐〃 */
-.full-width .chart-card {
-  width: 100%;
-}
-
-.full-width .chart-content {
-  height: 350px;
-}
-
-/* 鍝嶅簲寮忚皟鏁� */
-@media (max-width: 1024px) {
-  .kpi-cards {
-    grid-template-columns: repeat(2, 1fr);
-  }
-  .chart-row.top-three {
-    grid-template-columns: repeat(2, 1fr);
-  }
-  .chart-row.bottom-two {
-    grid-template-columns: repeat(2, 1fr);
-  }
 }
 
 @media (max-width: 768px) {
   .kpi-cards {
-    grid-template-columns: 1fr;
+    grid-template-columns: repeat(2, 1fr);
   }
-  .chart-row.top-three {
-    grid-template-columns: 1fr;
-  }
-  .chart-row.bottom-two {
+  .chart-row.daily-grid {
     grid-template-columns: 1fr;
   }
   .chart-content {
-    height: 220px;
-  }
-  .full-width .chart-content {
-    height: 280px;
+    height: 240px;
   }
   .card-title {
     font-size: 13px;
     white-space: normal;
   }
   .number-value {
-    font-size: 16px;
+    font-size: 14px;
+  }
+  .number-item {
+    min-width: 60px;
   }
 }
 
-/* 娣诲姞缃戞牸绾挎晥鏋� */
 .dashboard-container::before {
   content: "";
   position: fixed;

--
Gitblit v1.9.3