From 470a838491ea9d0e3f4a85a47e9da710f042d513 Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期一, 30 三月 2026 11:56:47 +0800
Subject: [PATCH] feat(Home): 重写首页为仪表盘图表页面

---
 Code/WMS/WIDESEA_WMSClient/src/views/Home.vue |  409 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 399 insertions(+), 10 deletions(-)

diff --git a/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue b/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue
index 820437a..bb42d01 100644
--- a/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue
+++ b/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue
@@ -1,24 +1,413 @@
 <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">
+      <div class="chart-card">
+        <div class="card-title">浠婃棩鍑哄叆搴撳姣�</div>
+        <div id="chart-today" class="chart-content"></div>
+      </div>
+      <div class="chart-card">
+        <div class="card-title">鏈懆鍑哄叆搴撳姣�</div>
+        <div id="chart-week" class="chart-content"></div>
+      </div>
+    </div>
+
+    <!-- 绗笁琛岋細鏈湀瀵规瘮/搴撳瓨鎬婚噺 -->
+    <div class="chart-row">
+      <div class="chart-card">
+        <div class="card-title">鏈湀鍑哄叆搴撳姣�</div>
+        <div id="chart-month" class="chart-content"></div>
+      </div>
+      <div class="chart-card">
+        <div class="card-title">褰撳墠搴撳瓨鎬婚噺</div>
+        <div class="stock-total">
+          <div class="total-number">{{ overviewData.TotalStock || 0 }}</div>
+          <div class="total-label">鎵樼洏</div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 绗洓琛岋細搴撻緞鍒嗗竷/浠撳簱鍒嗗竷 -->
+    <div class="chart-row">
+      <div class="chart-card">
+        <div class="card-title">搴撳瓨搴撻緞鍒嗗竷</div>
+        <div id="chart-stock-age" class="chart-content"></div>
+      </div>
+      <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: {},
+      overviewData: {
+        TodayInbound: 0,
+        TodayOutbound: 0,
+        MonthInbound: 0,
+        MonthOutbound: 0,
+        TotalStock: 0
+      },
+      weeklyData: [],
+      monthlyData: [],
+      stockAgeData: [],
+      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.today = echarts.init(document.getElementById("chart-today"));
+      this.charts.week = echarts.init(document.getElementById("chart-week"));
+      this.charts.month = echarts.init(document.getElementById("chart-month"));
+      this.charts.stockAge = echarts.init(document.getElementById("chart-stock-age"));
+      this.charts.warehouse = echarts.init(document.getElementById("chart-warehouse"));
+    },
+
+    async loadData() {
+      await this.loadOverview();
+      await this.loadWeeklyStats();
+      await this.loadMonthlyStats();
+      await this.loadStockAgeDistribution();
+      await this.loadStockByWarehouse();
+    },
+
+    async loadOverview() {
+      try {
+        const res = await this.http.get("/api/Dashboard/Overview");
+        if (res.Status && res.Data) {
+          this.overviewData = res.Data;
+          this.updateTodayChart();
+          this.updateWeekChart();
+          this.updateMonthChart();
+        }
+      } catch (e) {
+        console.error("鍔犺浇鎬昏鏁版嵁澶辫触", e);
+      }
+    },
+
+    async loadWeeklyStats() {
+      try {
+        const res = await this.http.get("/api/Dashboard/WeeklyStats", { weeks: 12 });
+        if (res.Status && res.Data) {
+          this.weeklyData = res.Data;
+          this.updateWeekChart();
+        }
+      } catch (e) {
+        console.error("鍔犺浇姣忓懆缁熻澶辫触", e);
+      }
+    },
+
+    async loadMonthlyStats() {
+      try {
+        const res = await this.http.get("/api/Dashboard/MonthlyStats", { months: 12 });
+        if (res.Status && res.Data) {
+          this.monthlyData = res.Data;
+          this.updateMonthlyTrendChart();
+        }
+      } catch (e) {
+        console.error("鍔犺浇姣忔湀缁熻澶辫触", e);
+      }
+    },
+
+    async loadStockAgeDistribution() {
+      try {
+        const res = await this.http.get("/api/Dashboard/StockAgeDistribution");
+        if (res.Status && res.Data) {
+          this.stockAgeData = res.Data;
+          this.updateStockAgeChart();
+        }
+      } catch (e) {
+        console.error("鍔犺浇搴撻緞鍒嗗竷澶辫触", e);
+      }
+    },
+
+    async loadStockByWarehouse() {
+      try {
+        const res = await this.http.get("/api/Dashboard/StockByWarehouse");
+        if (res.Status && res.Data) {
+          this.warehouseData = res.Data;
+          this.updateWarehouseChart();
+        }
+      } catch (e) {
+        console.error("鍔犺浇浠撳簱鍒嗗竷澶辫触", e);
+      }
+    },
+
+    updateTodayChart() {
+      const option = {
+        tooltip: { trigger: "axis" },
+        legend: { data: ["鍏ュ簱", "鍑哄簱"], textStyle: { color: "#fff" } },
+        xAxis: {
+          type: "category",
+          data: ["浠婃棩"],
+          axisLabel: { color: "#fff" }
+        },
+        yAxis: {
+          type: "value",
+          axisLabel: { color: "#fff" }
+        },
+        series: [
+          { name: "鍏ュ簱", type: "bar", data: [this.overviewData.TodayInbound], itemStyle: { color: "#5470c6" } },
+          { name: "鍑哄簱", type: "bar", data: [this.overviewData.TodayOutbound], itemStyle: { color: "#91cc75" } }
+        ]
+      };
+      this.charts.today.setOption(option, true);
+    },
+
+    updateWeekChart() {
+      const thisWeek = this.getThisWeekData(this.weeklyData);
+      const option = {
+        tooltip: { trigger: "axis" },
+        legend: { data: ["鍏ュ簱", "鍑哄簱"], textStyle: { color: "#fff" } },
+        xAxis: {
+          type: "category",
+          data: ["鏈懆"],
+          axisLabel: { color: "#fff" }
+        },
+        yAxis: {
+          type: "value",
+          axisLabel: { color: "#fff" }
+        },
+        series: [
+          { name: "鍏ュ簱", type: "bar", data: [thisWeek.Inbound], itemStyle: { color: "#5470c6" } },
+          { name: "鍑哄簱", type: "bar", data: [thisWeek.Outbound], itemStyle: { color: "#91cc75" } }
+        ]
+      };
+      this.charts.week.setOption(option, true);
+    },
+
+    getThisWeekData(weeklyData) {
+      if (!weeklyData || weeklyData.length === 0) return { Inbound: 0, Outbound: 0 };
+      const thisWeekKey = this.getCurrentWeekKey();
+      const thisWeek = weeklyData.find(w => w.Week === thisWeekKey);
+      return thisWeek || { Inbound: 0, Outbound: 0 };
+    },
+
+    getCurrentWeekKey() {
+      const now = new Date();
+      const diff = (7 + (now.getDay() - 1)) % 7;
+      const monday = new Date(now);
+      monday.setDate(now.getDate() - diff);
+      const year = monday.getFullYear();
+      const jan1 = new Date(year, 0, 1);
+      const weekNum = Math.ceil(((monday - jan1) / 86400000 + jan1.getDay() + 1) / 7);
+      return `${year}-W${String(weekNum).padStart(2, "0")}`;
+    },
+
+    updateMonthChart() {
+      const option = {
+        tooltip: { trigger: "axis" },
+        legend: { data: ["鍏ュ簱", "鍑哄簱"], textStyle: { color: "#fff" } },
+        xAxis: {
+          type: "category",
+          data: ["鏈湀"],
+          axisLabel: { color: "#fff" }
+        },
+        yAxis: {
+          type: "value",
+          axisLabel: { color: "#fff" }
+        },
+        series: [
+          { name: "鍏ュ簱", type: "bar", data: [this.overviewData.MonthInbound], itemStyle: { color: "#5470c6" } },
+          { name: "鍑哄簱", type: "bar", data: [this.overviewData.MonthOutbound], itemStyle: { color: "#91cc75" } }
+        ]
+      };
+      this.charts.month.setOption(option, true);
+    },
+
+    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: "line", 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);
+    },
+
+    updateStockAgeChart() {
+      const option = {
+        tooltip: { trigger: "item" },
+        legend: { data: this.stockAgeData.map(s => s.Range), textStyle: { color: "#fff" } },
+        series: [
+          {
+            type: "pie",
+            radius: "60%",
+            data: this.stockAgeData.map((s, i) => ({
+              name: s.Range,
+              value: s.Count
+            })),
+            emphasis: {
+              itemStyle: {
+                shadowBlur: 10,
+                shadowOffsetX: 0,
+                shadowColor: "rgba(0, 0, 0, 0.5)"
+              }
+            }
+          }
+        ]
+      };
+      this.charts.stockAge.setOption(option, true);
+    },
+
+    updateWarehouseChart() {
+      const option = {
+        tooltip: { trigger: "axis" },
+        xAxis: {
+          type: "category",
+          data: this.warehouseData.map(w => w.Warehouse),
+          axisLabel: { color: "#fff", rotate: 30 }
+        },
+        yAxis: {
+          type: "value",
+          axisLabel: { color: "#fff" }
+        },
+        series: [
+          {
+            type: "bar",
+            data: this.warehouseData.map(w => w.Count),
+            itemStyle: { color: "#5470c6" }
+          }
+        ]
+      };
+      this.charts.warehouse.setOption(option, true);
     }
   }
-}
+};
 </script>
 
 <style scoped>
-.title {
-  line-height: 70vh;
-  text-align: center;
-  font-size: 28px;
-  color: orange;
+.dashboard-container {
+  padding: 20px;
+  background-color: #0e1a2b;
+  min-height: calc(100vh - 60px);
 }
-</style>
\ No newline at end of file
+
+.chart-row {
+  display: flex;
+  gap: 20px;
+  margin-bottom: 20px;
+}
+
+.chart-row.full-width {
+  width: 100%;
+}
+
+.chart-card {
+  flex: 1;
+  background: rgba(255, 255, 255, 0.05);
+  border: 1px solid rgba(25, 186, 139, 0.17);
+  border-radius: 4px;
+  padding: 15px;
+  position: relative;
+}
+
+.chart-card::before {
+  content: "";
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 10px;
+  height: 10px;
+  border-top: 2px solid #02a6b5;
+  border-left: 2px solid #02a6b5;
+}
+
+.chart-card::after {
+  content: "";
+  position: absolute;
+  top: 0;
+  right: 0;
+  width: 10px;
+  height: 10px;
+  border-top: 2px solid #02a6b5;
+  border-right: 2px solid #02a6b5;
+}
+
+.card-title {
+  color: #fff;
+  font-size: 16px;
+  text-align: center;
+  margin-bottom: 10px;
+}
+
+.chart-content {
+  height: 280px;
+  width: 100%;
+}
+
+.stock-total {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 280px;
+}
+
+.total-number {
+  font-size: 64px;
+  font-weight: bold;
+  color: #67caca;
+  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, PingFang SC, Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif;
+}
+
+.total-label {
+  font-size: 18px;
+  color: #fcf0d8;
+  margin-top: 10px;
+}
+
+/* 鍏ㄥ鍥捐〃 */
+.full-width .chart-card {
+  flex: none;
+  width: 100%;
+}
+
+.full-width .chart-content {
+  height: 350px;
+}
+</style>

--
Gitblit v1.9.3