wanshenmean
16 小时以前 0fa137570bf7ac2bf58c8af2828cd595625fa400
Code/WMS/WIDESEA_WMSClient/src/views/Home.vue
@@ -3,44 +3,21 @@
    <!-- 顶部:本月出入库趋势 (全宽) -->
    <div class="chart-row full-width">
      <div class="chart-card">
        <div class="card-title">本月出入库趋势</div>
        <div class="card-title">每月出入库趋势</div>
        <div id="chart-monthly-trend" class="chart-content"></div>
      </div>
    </div>
    <!-- 第二行:今日/本周出入库对比 -->
    <div class="chart-row">
    <!-- 第二行:每日出入库趋势 (全宽) -->
    <div class="chart-row full-width">
      <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 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-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>
@@ -57,16 +34,8 @@
  data() {
    return {
      charts: {},
      overviewData: {
        TodayInbound: 0,
        TodayOutbound: 0,
        MonthInbound: 0,
        MonthOutbound: 0,
        TotalStock: 0
      },
      weeklyData: [],
      dailyData: [],
      monthlyData: [],
      stockAgeData: [],
      warehouseData: []
    };
  },
@@ -86,53 +55,22 @@
    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.daily = echarts.init(document.getElementById("chart-daily"));
      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.loadDailyStats();
      await this.loadStockByWarehouse();
    },
    async loadOverview() {
      try {
        const res = await this.http.get("/api/Dashboard/Overview");
        console.log("总览数据", res.Data);
        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;
        if (res.status && res.data) {
          console.log("每月统计数据:", res.data);
          this.monthlyData = res.data;
          this.updateMonthlyTrendChart();
        }
      } catch (e) {
@@ -140,110 +78,30 @@
      }
    },
    async loadStockAgeDistribution() {
    async loadDailyStats() {
      try {
        const res = await this.http.get("/api/Dashboard/StockAgeDistribution");
        if (res.Status && res.Data) {
          this.stockAgeData = res.Data;
          this.updateStockAgeChart();
        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);
        console.error("加载每日统计失败", e);
      }
    },
    async loadStockByWarehouse() {
      try {
        const res = await this.http.get("/api/Dashboard/StockByWarehouse");
        if (res.Status && res.Data) {
          this.warehouseData = res.Data;
        if (res.status && res.data) {
          console.log("仓库分布数据:", res.data);
          this.warehouseData = res.data.data || 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() {
@@ -252,7 +110,7 @@
        legend: { data: ["入库", "出库"], textStyle: { color: "#fff" } },
        xAxis: {
          type: "category",
          data: this.monthlyData.map(m => m.Month),
          data: this.monthlyData.map(m => m.month),
          axisLabel: { color: "#fff", rotate: 45 }
        },
        yAxis: [
@@ -263,56 +121,144 @@
          }
        ],
        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" } }
          { 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);
    },
    updateStockAgeChart() {
    updateDailyChart() {
      const option = {
        tooltip: { trigger: "axis" },
        legend: { data: ["入库", "出库"], textStyle: { color: "#fff" } },
        xAxis: {
          type: "category",
          data: this.stockAgeData.map(s => s.Range),
          axisLabel: { color: "#fff" }
          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: [
          {
            type: "bar",
            data: this.stockAgeData.map(s => s.Count),
            itemStyle: { color: "#5470c6" }
          }
          { 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.stockAge.setOption(option, true);
      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" },
        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: this.warehouseData.map(w => w.Warehouse),
          axisLabel: { color: "#fff", rotate: 30 }
          type: 'category',
          data: warehouseNames,
          axisLabel: { color: '#fff', rotate: 30 }
        },
        yAxis: {
          type: "value",
          axisLabel: { color: "#fff" }
          type: 'value',
          axisLabel: { color: '#fff' }
        },
        series: [
          {
            type: "bar",
            data: this.warehouseData.map(w => w.Count),
            itemStyle: { color: "#5470c6" }
            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);
    }
  }
@@ -322,8 +268,10 @@
<style scoped>
.dashboard-container {
  padding: 20px;
  background-color: #0e1a2b;
  color: #e0e0e0;
  min-height: calc(100vh - 60px);
  background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
  background-attachment: fixed;
}
.chart-row {
@@ -338,11 +286,25 @@
.chart-card {
  flex: 1;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(25, 186, 139, 0.17);
  border-radius: 4px;
  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 {
@@ -352,8 +314,9 @@
  left: 0;
  width: 10px;
  height: 10px;
  border-top: 2px solid #02a6b5;
  border-left: 2px solid #02a6b5;
  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 {
@@ -363,41 +326,39 @@
  right: 0;
  width: 10px;
  height: 10px;
  border-top: 2px solid #02a6b5;
  border-right: 2px solid #02a6b5;
  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: #fff;
  color: #00ffff;
  font-size: 16px;
  text-align: center;
  margin-bottom: 10px;
  text-shadow: 0 0 10px rgba(0, 255, 255, 0.7);
  font-weight: 500;
}
.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;
}
/* 全宽图表 */
@@ -409,4 +370,20 @@
.full-width .chart-content {
  height: 350px;
}
</style>
/* 添加网格线效果 */
.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>