From 0fa137570bf7ac2bf58c8af2828cd595625fa400 Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期日, 19 四月 2026 18:53:45 +0800
Subject: [PATCH] Merge branch 'dev' of http://115.159.85.185:8098/r/SuZhouGuanHong/ShanMeiXinNengYuan into dev

---
 Code/WMS/WIDESEA_WMSClient/src/views/Home.vue |  381 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 373 insertions(+), 8 deletions(-)

diff --git a/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue b/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue
index 820437a..ea951db 100644
--- a/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue
+++ b/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue
@@ -1,24 +1,389 @@
 <template>
-  <div class="title"></div>
+  <div class="dashboard-container">
+    <!-- 椤堕儴锛氭湰鏈堝嚭鍏ュ簱瓒嬪娍 (鍏ㄥ) -->
+    <div class="chart-row full-width">
+      <div class="chart-card">
+        <div class="card-title">姣忔湀鍑哄叆搴撹秼鍔�</div>
+        <div id="chart-monthly-trend" 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>
+        <div id="chart-warehouse" class="chart-content"></div>
+      </div>
+    </div>
+  </div>
 </template>
 
 <script>
-import { ref, reactive } from 'vue'
+import * as echarts from "echarts";
 
 export default {
-  setup() {
+  name: "Home",
+  data() {
     return {
+      charts: {},
+      dailyData: [],
+      monthlyData: [],
+      warehouseData: []
+    };
+  },
+  mounted() {
+    this.initCharts();
+    this.loadData();
+    window.addEventListener("resize", this.handleResize);
+  },
+  beforeUnmount() {
+    window.removeEventListener("resize", this.handleResize);
+    Object.values(this.charts).forEach(chart => chart.dispose());
+  },
+  methods: {
+    handleResize() {
+      Object.values(this.charts).forEach(chart => chart.resize());
+    },
 
+    initCharts() {
+      this.charts.monthlyTrend = echarts.init(document.getElementById("chart-monthly-trend"));
+      this.charts.daily = echarts.init(document.getElementById("chart-daily"));
+      this.charts.warehouse = echarts.init(document.getElementById("chart-warehouse"));
+    },
+
+    async loadData() {
+      await this.loadMonthlyStats();
+      await this.loadDailyStats();
+      await this.loadStockByWarehouse();
+    },
+
+    async loadMonthlyStats() {
+      try {
+        const res = await this.http.get("/api/Dashboard/MonthlyStats", { months: 12 });
+        if (res.status && res.data) {
+          console.log("姣忔湀缁熻鏁版嵁:", res.data);
+          this.monthlyData = res.data;
+          this.updateMonthlyTrendChart();
+        }
+      } catch (e) {
+        console.error("鍔犺浇姣忔湀缁熻澶辫触", e);
+      }
+    },
+
+    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 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);
+      }
+    },
+
+    updateMonthlyTrendChart() {
+      const option = {
+        tooltip: { trigger: "axis" },
+        legend: { data: ["鍏ュ簱", "鍑哄簱"], textStyle: { color: "#fff" } },
+        xAxis: {
+          type: "category",
+          data: this.monthlyData.map(m => m.month),
+          axisLabel: { color: "#fff", rotate: 45 }
+        },
+        yAxis: [
+          {
+            type: "value",
+            name: "鏁伴噺",
+            axisLabel: { color: "#fff" }
+          }
+        ],
+        series: [
+          { name: "鍏ュ簱", type: "bar", data: this.monthlyData.map(m => m.inbound), itemStyle: { color: "#5470c6" } },
+          { name: "鍑哄簱", type: "line", data: this.monthlyData.map(m => m.outbound), itemStyle: { color: "#91cc75" } }
+        ]
+      };
+      this.charts.monthlyTrend.setOption(option, true);
+    },
+
+    updateDailyChart() {
+      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() {
+      const warehouseNames = this.warehouseData.map(w => w.warehouse);
+      const totalStocks = this.warehouseData.map(w => w.total);
+      const hasStocks = this.warehouseData.map(w => w.hasStock);
+      const noStocks = this.warehouseData.map(w => w.noStock);
+      const hasStockPercentages = this.warehouseData.map(w => w.hasStockPercentage);
+      const noStockPercentages = this.warehouseData.map(w => w.noStockPercentage);
+      
+      const option = {
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'shadow'
+          },
+          formatter: function(params) {
+            let tip = params[0].name + '<br/>';
+            params.forEach(param => {
+              const dataIndex = param.dataIndex;
+              const warehouse = window.homeComponent.warehouseData[dataIndex];
+              
+              if (param.seriesName === '宸茬敤瀹归噺') {
+                tip += `${param.marker}${param.seriesName}: ${param.value} (${warehouse.hasStockPercentage})<br/>`;
+                tip += `鏈夊簱瀛�: ${warehouse.hasStock}<br/>`;
+                tip += `鏃犲簱瀛�: ${warehouse.noStock}<br/>`;
+                tip += `鎬诲閲�: ${warehouse.total}`;
+              } else if (param.seriesName === '鍓╀綑瀹归噺') {
+                tip += `${param.marker}${param.seriesName}: ${param.value} (${warehouse.noStockPercentage})<br/>`;
+                tip += `鏈夊簱瀛�: ${warehouse.hasStock}<br/>`;
+                tip += `鏃犲簱瀛�: ${warehouse.noStock}<br/>`;
+                tip += `鎬诲閲�: ${warehouse.total}`;
+              }
+            });
+            return tip;
+          }
+        },
+        legend: {
+          data: ['宸茬敤瀹归噺', '鍓╀綑瀹归噺'],
+          textStyle: { color: '#fff' }
+        },
+        xAxis: {
+          type: 'category',
+          data: warehouseNames,
+          axisLabel: { color: '#fff', rotate: 30 }
+        },
+        yAxis: {
+          type: 'value',
+          axisLabel: { color: '#fff' }
+        },
+        series: [
+          {
+            name: '宸茬敤瀹归噺',
+            type: 'bar',
+            data: hasStocks.map((value, index) => ({
+              value: value,
+              label: {
+                show: true,
+                position: 'top',
+                formatter: '{c} {a|' + hasStockPercentages[index] + '}',
+                rich: {
+                  a: {
+                    lineHeight: 20,
+                    borderColor: '#91cc75',
+                    color: '#91cc75'
+                  }
+                }
+              }
+            })),
+            itemStyle: { color: '#91cc75' }
+          },
+          {
+            name: '鍓╀綑瀹归噺',
+            type: 'bar',
+            data: noStocks.map((value, index) => ({
+              value: value,
+              label: {
+                show: true,
+                position: 'top',
+                formatter: '{c} {a|' + noStockPercentages[index] + '}',
+                rich: {
+                  a: {
+                    lineHeight: 20,
+                    borderColor: '#fac858',
+                    color: '#fac858'
+                  }
+                }
+              }
+            })),
+            itemStyle: { color: '#fac858' }
+          }
+        ]
+      };
+      
+      window.homeComponent = this;
+      
+      this.charts.warehouse.setOption(option, true);
     }
   }
-}
+};
 </script>
 
 <style scoped>
-.title {
-  line-height: 70vh;
+.dashboard-container {
+  padding: 20px;
+  color: #e0e0e0;
+  min-height: calc(100vh - 60px);
+  background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
+  background-attachment: fixed;
+}
+
+.chart-row {
+  display: flex;
+  gap: 20px;
+  margin-bottom: 20px;
+}
+
+.chart-row.full-width {
+  width: 100%;
+}
+
+.chart-card {
+  flex: 1;
+  background: rgba(10, 16, 35, 0.6);
+  backdrop-filter: blur(10px);
+  border: 1px solid rgba(64, 224, 208, 0.3);
+  border-radius: 12px;
+  padding: 15px;
+  position: relative;
+  box-shadow: 
+    0 0 15px rgba(0, 255, 255, 0.1),
+    inset 0 0 10px rgba(64, 224, 208, 0.1);
+  transition: all 0.3s ease;
+  overflow: hidden;
+}
+
+.chart-card:hover {
+  transform: translateY(-5px);
+  box-shadow: 
+    0 0 25px rgba(0, 255, 255, 0.3),
+    inset 0 0 15px rgba(64, 224, 208, 0.2);
+  border: 1px solid rgba(64, 224, 208, 0.6);
+}
+
+.chart-card::before {
+  content: "";
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 10px;
+  height: 10px;
+  border-top: 2px solid #00ffff;
+  border-left: 2px solid #00ffff;
+  box-shadow: -2px -2px 10px #00ffff, 0 0 10px rgba(0, 255, 255, 0.7);
+}
+
+.chart-card::after {
+  content: "";
+  position: absolute;
+  top: 0;
+  right: 0;
+  width: 10px;
+  height: 10px;
+  border-top: 2px solid #00ffff;
+  border-right: 2px solid #00ffff;
+  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: 16px;
   text-align: center;
-  font-size: 28px;
-  color: orange;
+  margin-bottom: 10px;
+  text-shadow: 0 0 10px rgba(0, 255, 255, 0.7);
+  font-weight: 500;
+}
+
+.chart-content {
+  height: 280px;
+  width: 100%;
+}
+
+/* 鍏ㄥ鍥捐〃 */
+.full-width .chart-card {
+  flex: none;
+  width: 100%;
+}
+
+.full-width .chart-content {
+  height: 350px;
+}
+
+/* 娣诲姞缃戞牸绾挎晥鏋� */
+.dashboard-container::before {
+  content: "";
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-image: 
+    linear-gradient(rgba(64, 224, 208, 0.05) 1px, transparent 1px),
+    linear-gradient(90deg, rgba(64, 224, 208, 0.05) 1px, transparent 1px);
+  background-size: 30px 30px;
+  pointer-events: none;
+  z-index: -1;
 }
 </style>
\ No newline at end of file

--
Gitblit v1.9.3