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