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                                             |  409 ++++----
 Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_AGV.cs                     | 1347 +++++++++++++++---------------
 Code/WMS/WIDESEA_WMSClient/src/views/stock/stockChat.vue                                  |    4 
 Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Dashboard/DashboardController.cs |  645 ++++++++------
 Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/Extensions/WebSocketSetup.cs                      |   45 
 Code/WMS/WIDESEA_WMSClient/src/views/Index.vue                                            |  159 --
 6 files changed, 1,311 insertions(+), 1,298 deletions(-)

diff --git a/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue b/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue
index a14728a..ea951db 100644
--- a/Code/WMS/WIDESEA_WMSClient/src/views/Home.vue
+++ b/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>
\ No newline at end of file
diff --git a/Code/WMS/WIDESEA_WMSClient/src/views/Index.vue b/Code/WMS/WIDESEA_WMSClient/src/views/Index.vue
index 9fffb90..4ed49a1 100644
--- a/Code/WMS/WIDESEA_WMSClient/src/views/Index.vue
+++ b/Code/WMS/WIDESEA_WMSClient/src/views/Index.vue
@@ -3,22 +3,12 @@
     <div class="vol-aside" :style="{ width: menuWidth + 'px' }">
       <div class="header" :style="{ width: menuWidth - 1 + 'px' }">
         <img v-show="!isCollapse" v-bind:src="logo" />
-        <i
-          @click="toggleLeft"
-          class="collapse-menu"
-          :class="isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'"
-        />
+        <i @click="toggleLeft" class="collapse-menu" :class="isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'" />
       </div>
       <div class="vol-menu">
         <el-scrollbar style="height: 100%">
-          <VolMenu
-            :currentMenuId="currentMenuId"
-            :on-select="onSelect"
-            :enable="true"
-            :open-select="false"
-            :isCollapse="isCollapse"
-            :list="menuOptions"
-          ></VolMenu>
+          <VolMenu :currentMenuId="currentMenuId" :on-select="onSelect" :enable="true" :open-select="false"
+            :isCollapse="isCollapse" :list="menuOptions"></VolMenu>
         </el-scrollbar>
       </div>
     </div>
@@ -27,14 +17,9 @@
         <div class="project-name">WMS</div>
         <div class="header-text">
           <div class="h-link">
-            <a
-              href="javascript:void(0)"
-              @click="to(item)"
-              v-for="(item, index) in links.filter((c) => {
-                return !c.icon;
-              })"
-              :key="index"
-            >
+            <a href="javascript:void(0)" @click="to(item)" v-for="(item, index) in links.filter((c) => {
+              return !c.icon;
+            })" :key="index">
               <span v-if="!item.icon"> {{ item.text }}</span>
               <i v-else :class="item.icon"></i>
             </a>
@@ -42,14 +27,9 @@
         </div>
         <div class="header-info">
           <div class="h-link">
-            <a
-              href="javascript:void(0)"
-              @click="to(item)"
-              v-for="(item, index) in links.filter((c) => {
-                return c.icon;
-              })"
-              :key="index"
-            >
+            <a href="javascript:void(0)" @click="to(item)" v-for="(item, index) in links.filter((c) => {
+              return c.icon;
+            })" :key="index">
               <span v-if="!item.icon"> {{ item.text }}</span>
               <i v-else :class="item.icon"></i>
             </a>
@@ -57,15 +37,9 @@
           <!--娑堟伅绠$悊-->
 
           <div class="h-link" @click="messageModel = true">
-            <a
-              ><i class="el-icon-message-solid"
-                ><el-badge
-                  :value="messageList.length"
-                  :type="messageList.length > 0 ? 'danger' : 'success'"
-                  class="item"
-                  style="width: 10px"
-                ></el-badge></i
-            ></a>
+            <a><i class="el-icon-message-solid"><el-badge :value="messageList.length"
+                  :type="messageList.length > 0 ? 'danger' : 'success'" class="item"
+                  style="width: 10px"></el-badge></i></a>
           </div>
           <div>
             <img class="user-header" :src="userImg" :onerror="errorImg" />
@@ -75,62 +49,37 @@
             <span id="index-date"></span>
           </div>
           <div class="settings">
-            <i
-              style="font-size: 20px"
-              class="el-icon-s-tools"
-              @click="drawer_model = true"
-            />
+            <i style="font-size: 20px" class="el-icon-s-tools" @click="drawer_model = true" />
           </div>
         </div>
       </div>
       <div class="vol-path">
-        <el-tabs
-          @tab-click="selectNav"
-          @tab-remove="removeNav"
-          @contextmenu.prevent="bindRightClickMenu(false)"
-          type="border-card"
-          class="header-navigation"
-          v-model="selectId"
-          :strtch="false"
-        >
-          <el-tab-pane
-            v-for="(item, navIndex) in navigation"
-            type="card"
-            :name="navIndex + ''"
-            :closable="navIndex > 0"
-            :key="navIndex"
-            :label="item.name"
-          >
+        <el-tabs @tab-click="selectNav" @tab-remove="removeNav" @contextmenu.prevent="bindRightClickMenu(false)"
+          type="border-card" class="header-navigation" v-model="selectId" :strtch="false">
+          <el-tab-pane v-for="(item, navIndex) in navigation" type="card" :name="navIndex + ''" :closable="navIndex > 0"
+            :key="navIndex" :label="item.name">
             <span style="display: none">{{ navIndex }}</span>
           </el-tab-pane>
         </el-tabs>
         <!-- 鍙抽敭鑿滃崟 -->
         <div v-show="contextMenuVisible">
-          <ul
-            :style="{ left: menuLeft + 'px', top: menuTop + 'px' }"
-            class="contextMenu"
-          >
+          <ul :style="{ left: menuLeft + 'px', top: menuTop + 'px' }" class="contextMenu">
             <li v-show="visibleItem.all">
               <el-button link @click="closeTabs()">
                 <i class="el-icon-close"></i>
                 {{
                   navigation.length == 2 ? "鍏抽棴鑿滃崟" : "鍏抽棴鎵�鏈�"
-                }}</el-button
-              >
+                }}</el-button>
             </li>
             <li v-show="visibleItem.left">
-              <el-button link @click="closeTabs('left')"
-                ><i class="el-icon-back"></i>鍏抽棴宸﹁竟</el-button
-              >
+              <el-button link @click="closeTabs('left')"><i class="el-icon-back"></i>鍏抽棴宸﹁竟</el-button>
             </li>
             <li v-show="visibleItem.right">
               <el-button link @click="closeTabs('right')">
-                <i class="el-icon-right"></i>鍏抽棴鍙宠竟</el-button
-              >
+                <i class="el-icon-right"></i>鍏抽棴鍙宠竟</el-button>
             </li>
             <li v-show="visibleItem.other">
-              <el-button link @click="closeTabs('other')"
-                ><i class="el-icon-right"></i>鍏抽棴鍏朵粬
+              <el-button link @click="closeTabs('other')"><i class="el-icon-right"></i>鍏抽棴鍏朵粬
               </el-button>
             </li>
           </ul>
@@ -141,56 +90,29 @@
           <loading v-show="$store.getters.isLoading()"></loading>
           <router-view v-slot="{ Component }">
             <keep-alive>
-              <component
-                :is="Component"
-                :key="$route.name"
-                v-if="
-                  !$route.meta ||
-                  ($route.meta && !$route.meta.hasOwnProperty('keepAlive'))
-                "
-              />
+              <component :is="Component" :key="$route.name" v-if="
+                !$route.meta ||
+                ($route.meta && !$route.meta.hasOwnProperty('keepAlive'))
+              " />
             </keep-alive>
-            <component
-              :is="Component"
-              :key="$route.name"
-              v-if="$route.meta && $route.meta.hasOwnProperty('keepAlive')"
-            />
+            <component :is="Component" :key="$route.name"
+              v-if="$route.meta && $route.meta.hasOwnProperty('keepAlive')" />
           </router-view>
         </el-scrollbar>
       </div>
     </div>
-    <el-drawer
-      title="閫夋嫨涓婚"
-      v-model="drawer_model"
-      direction="rtl"
-      destroy-on-close
-    >
+    <el-drawer title="閫夋嫨涓婚" v-model="drawer_model" direction="rtl" destroy-on-close>
       <div class="theme-selector">
-        <div
-          @click="changeTheme(item.name)"
-          class="item"
-          v-for="(item, index) in theme_color"
-          :key="index"
-          :style="{ background: item.color }"
-        >
-          <div
-            v-show="item.leftColor"
-            :style="{ background: item.leftColor }"
-            style="height: 100%; width: 20px"
-            class="t-left"
-          ></div>
+        <div @click="changeTheme(item.name)" class="item" v-for="(item, index) in theme_color" :key="index"
+          :style="{ background: item.color }">
+          <div v-show="item.leftColor" :style="{ background: item.leftColor }" style="height: 100%; width: 20px"
+            class="t-left"></div>
           <div class="t-right"></div>
         </div>
       </div>
     </el-drawer>
 
-    <el-drawer
-      title="娑堟伅鍒楄〃"
-      v-model="messageModel"
-      direction="rtl"
-      destroy-on-close
-      size="40%"
-    >
+    <el-drawer title="娑堟伅鍒楄〃" v-model="messageModel" direction="rtl" destroy-on-close size="40%">
       <Message :list="messageList"></Message>
     </el-drawer>
   </div>
@@ -339,7 +261,7 @@
         setTimeout(createSocket, 10000);
       };
 
-      client.onerror = function () {};
+      client.onerror = function () { };
     };
 
     const changeTheme = (name) => {
@@ -606,7 +528,7 @@
       }
 
       createSocket("ws://127.0.0.1:9296/" + _userInfo.userName);
-
+      // createSocket("ws://127.0.0.1:9296");
       Object.assign(_config.$tabs, { open: open, close: close });
 
       http.get("api/Sys_Menu/getTreeMenu", {}, true).then((data) => {
@@ -792,6 +714,7 @@
   font-size: 14px;
   color: #333;
   box-shadow: 2px 2px 3px 0 rgb(182 182 182 / 20%);
+
   i,
   button {
     font-size: 14px !important;
@@ -814,12 +737,8 @@
   letter-spacing: 1px;
 }
 
-.el-tabs.el-tabs--top.el-tabs--border-card.header-navigation
-  > .el-tabs__header
-  .el-tabs__item:last-child,
-.el-tabs--top.el-tabs--border-card.header-navigation
-  > .el-tabs__header
-  .el-tabs__item:nth-child(2) {
+.el-tabs.el-tabs--top.el-tabs--border-card.header-navigation>.el-tabs__header .el-tabs__item:last-child,
+.el-tabs--top.el-tabs--border-card.header-navigation>.el-tabs__header .el-tabs__item:nth-child(2) {
   padding: 0;
 }
 
diff --git a/Code/WMS/WIDESEA_WMSClient/src/views/stock/stockChat.vue b/Code/WMS/WIDESEA_WMSClient/src/views/stock/stockChat.vue
index de418eb..c81ec7d 100644
--- a/Code/WMS/WIDESEA_WMSClient/src/views/stock/stockChat.vue
+++ b/Code/WMS/WIDESEA_WMSClient/src/views/stock/stockChat.vue
@@ -217,6 +217,10 @@
 }
 
 function hasCargo(location) {
+    // 濡傛灉LocationStatus=100锛屽嵆浣挎病鏈夊簱瀛樹俊鎭篃鏄剧ず璐т綅
+    if (location.locationStatus === 100) {
+        return true
+    }
     return Number(location.stockQuantity || 0) > 0 || ((location.details && location.details.length > 0) || false)
 }
 
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/Extensions/WebSocketSetup.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/Extensions/WebSocketSetup.cs
index 1c6b23a..f04b78e 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/Extensions/WebSocketSetup.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/Extensions/WebSocketSetup.cs
@@ -11,22 +11,37 @@
 {
     public static class WebSocketSetup
     {
-        public static void AddWebSocketSetup(this IServiceCollection services)
-        {
-            if (services == null) throw new ArgumentNullException(nameof(services));
+        //public static void AddWebSocketSetup(this IServiceCollection services)
+        //{
+        //    if (services == null) throw new ArgumentNullException(nameof(services));
 
-            int port = AppSettings.Get("WebSocketPort").ObjToInt();
-            if (port == 0)
-            {
-                port = 9296;
-            }
-
-            services.AddSingleton(x =>
-            {
-                WebSocketServer socketServer = new WebSocketServer();
-                socketServer.ServerStart(port);
-                return socketServer;
-            });
+        //    int port = AppSettings.Get("WebSocketPort").ObjToInt();
+        //    if (port == 0)
+        //    {
+        //        port = 9296;
+        //    }
+        //    services.AddSingleton(x =>
+        //    {
+        //        WebSocketServer socketServer = new WebSocketServer();
+        //        socketServer.ServerStart(port);
+        //        return socketServer;
+        //    });
+        //}
+        public static void AddWebSocketSetup(this IServiceCollection services)
+        {
+            if (services == null) throw new ArgumentNullException(nameof(services));
+
+            int port = AppSettings.Get("WebSocketPort").ObjToInt();
+            if (port == 0)
+            {
+                port = 9296;
+            }
+
+            // 鐩存帴鍒涘缓骞跺惎鍔� WebSocket 鏈嶅姟鍣�
+            WebSocketServer socketServer = new WebSocketServer();
+            socketServer.ServerStart(port);
+            services.AddSingleton(socketServer);
+
         }
     }
 }
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_AGV.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_AGV.cs
index 74dfd61..c0cb8f1 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_AGV.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_AGV.cs
@@ -1,681 +1,678 @@
-using Mapster;
-using System.Text.Json;
-using WIDESEA_Common.Constants;
-using WIDESEA_Common.LocationEnum;
-using WIDESEA_Common.StockEnum;
-using WIDESEA_Common.TaskEnum;
-using WIDESEA_Common.WareHouseEnum;
-using WIDESEA_Core;
-using WIDESEA_Core.Enums;
-using WIDESEA_Core.Helper;
-using WIDESEA_DTO.Task;
-using WIDESEA_IStockService;
-using WIDESEA_Model.Models;
-
-namespace WIDESEA_TaskInfoService
-{
-    public partial class TaskService
-    {
-
-        public string AGV_OutTaskComplete = WIDESEA_Core.Helper.AppSettings.Configuration["AGV_OutTaskComplete"];
-        public string WCS_ReceiveTask = WIDESEA_Core.Helper.AppSettings.Configuration["WCS_ReceiveTask"];
-
-        /// <summary>
-        /// 鏋佸嵎搴撳嚭鍏ュ簱鐢宠
-        /// </summary>
-        public async Task<AGVResponse> ApplyInOutAsync(ApplyInOutDto applyInOutDto)
-        {
-            AGVResponse response = new AGVResponse();
-
-            try
-            {
-                var validationMessage = ValidateApplyInOutRequest(applyInOutDto);
-                if (validationMessage != null)
-                    return response.Error(validationMessage);
-
-                var existingTask = await BaseDal.QueryFirstAsync(x => x.PalletCode == applyInOutDto.TrayNumber || x.OrderNo == applyInOutDto.TaskId);
-                if (existingTask != null)
-                    return response.Error($"WMS宸叉湁褰撳墠浠诲姟锛屼笉鍙噸澶嶄笅鍙戯紝浠诲姟鍙凤細{applyInOutDto.TaskId}");
-
-                var task = BuildAgvTask(applyInOutDto);
-
-                if (applyInOutDto.InOut == 1)
-                {
-                    var inboundResult = await CreateAgvInboundTaskAsync(task, applyInOutDto);
-                    if (inboundResult != null)
-                        return inboundResult;
-                }
-                else
-                {
-                    var outboundResult = await CreateAgvOutboundTaskAsync(task, applyInOutDto);
-                    if (outboundResult != null)
-                        return outboundResult;
-                }
-
-                return response.OK(BuildAgvDataDto(task, applyInOutDto));
-            }
-            catch (Exception ex)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return response.Error($"WMS浠诲姟鍒涘缓鎺ュ彛閿欒: {ex.Message}");
-            }
-        }
-
-        /// <summary>
-        /// 鎵嬪姩鍑哄簱瀹屾垚鍙嶉缁橝GV
-        /// </summary>
-        public async Task<WebResponseContent> OutTaskComplete(OutTaskCompleteDto outTaskCompleteDto)
-        {
-            WebResponseContent response = new WebResponseContent();
-
-            try
-            {
-                var validationMessage = ValidateOutTaskCompleteRequest(outTaskCompleteDto);
-                if (validationMessage != null)
-                    return response.Error(validationMessage);
-
-                var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == outTaskCompleteDto.TaskId);
-                if (task == null)
-                    return response.Error("鏈壘鍒颁换鍔′俊鎭�");
-
-                outTaskCompleteDto.ReqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
-                var httpResponse = _httpClientHelper.Post<AGVResponse>(AGV_OutTaskComplete, outTaskCompleteDto.ToJson()).Data;
-                if (httpResponse == null || httpResponse.Data == null)
-                    return response.Error(httpResponse?.Msg ?? "AGV鎺ュ彛璋冪敤寮傚父");
-
-                if (!httpResponse.Code)
-                        return response.Error(string.IsNullOrWhiteSpace(httpResponse.Msg) ? "AGV鎺ュ彛璋冪敤澶辫触" : httpResponse.Msg);
-
-                var syncResult = await CompleteLocalOutboundAfterAgvAckAsync(task);
-                return syncResult.Status ? response.OK(httpResponse.Msg) : syncResult;
-            }
-            catch (Exception ex)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return response.Error($"WMS浠诲姟瀹屾垚鎺ュ彛閿欒锛歿ex.Message}");
-            }
-        }
-
-        /// <summary>
-        /// 杈撻�佺嚎鐢宠杩涘叆
-        /// </summary>
-        public async Task<AGVResponse> ApplyEnterAsync(ApplyEnterDto applyEnterDto)
-        {
-            AGVResponse response = new AGVResponse();
-
-            try
-            {
-                var validationMessage = ValidateApplyEnterRequest(applyEnterDto);
-                if (validationMessage != null)
-                    return response.Error(validationMessage);
-
-                var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == applyEnterDto.TaskId);
-                if (task == null)
-                    return response.Error($"鏈壘鍒颁换鍔′俊鎭紝浠诲姟鍙凤細{applyEnterDto.TaskId}");
-
-                if (CanApplyEnter(task, applyEnterDto))
-                    return response.OK();
-
-                return response.Error($"杈撻�佺嚎{applyEnterDto.DevId}褰撳墠绻佸繖锛岃绋嶅悗閲嶈瘯");
-            }
-            catch (Exception ex)
-            {
-                return response.Error($"WMS杈撻�佺嚎鐢宠鎺ュ彛閿欒锛歿ex.Message}");
-            }
-        }
-
-        /// <summary>
-        /// 鍙栨斁璐у畬鎴�
-        /// </summary>
-        public async Task<AGVResponse> TaskCompleteAsync(TaskCompleteDto taskCompleteDto)
-        {
-            AGVResponse response = new AGVResponse();
-
-            try
-            {
-                var validationMessage = ValidateTaskCompleteRequest(taskCompleteDto);
-                if (validationMessage != null)
-                    return response.Error(validationMessage);
-
-                var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == taskCompleteDto.TaskId);
-                if (task == null)
-                    return response.Error($"鏈壘鍒颁换鍔′俊鎭紝浠诲姟鍙凤細{taskCompleteDto.TaskId}");
-
-                return taskCompleteDto.InOut == 2
-                    ? await CompleteAgvOutboundTaskAsync(task)
-                    : await CompleteAgvInboundTaskAsync(task);
-            }
-            catch (Exception ex)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return response.Error($"WMS鍙栨斁璐у畬鎴愭帴鍙i敊璇細{ex.Message}");
-            }
-        }
-
-        /// <summary>
-        /// 浠诲姟鍙栨秷
-        /// </summary>
-        public async Task<AGVResponse> TaskCancelAsync(TaskCancelDto taskCancelDto)
-        {
-            AGVResponse response = new AGVResponse();
-
-            try
-            {
-                var validationMessage = ValidateTaskCancelRequest(taskCancelDto);
-                if (validationMessage != null)
-                    return response.Error(validationMessage);
-
-                var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == taskCancelDto.TaskId);
-                if (task == null)
-                    return response.OK();
-
-                if (task.TaskStatus == (int)TaskInStatusEnum.InNew)
-                    return await CancelAgvInboundTask(task);
-
-                if (task.TaskStatus == (int)TaskOutStatusEnum.OutNew)
-                    return await CancelAgvOutboundTaskAsync(task);
-
-                return response.Error("浠诲姟宸茬粡鍦ㄦ墽琛屼腑锛屼笉鍙彇娑�");
-            }
-            catch (Exception ex)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return response.Error($"WMS浠诲姟鍙栨秷鎺ュ彛閿欒锛歿ex.Message}");
-            }
-        }
-
-        #region 鍙傛暟楠岃瘉
-        private static string? ValidateApplyInOutRequest(ApplyInOutDto dto)
-        {
-            if (dto == null) return "璇锋眰鍙傛暟涓嶈兘涓虹┖";
-            if (string.IsNullOrWhiteSpace(dto.TrayNumber)) return "鎵樼洏鍙蜂笉鑳戒负绌�";
-            if (string.IsNullOrWhiteSpace(dto.TaskId)) return "浠诲姟鍙蜂笉鑳戒负绌�";
-            if (string.IsNullOrWhiteSpace(dto.MaterialType)) return "鐗╂枡绫诲瀷涓嶈兘涓虹┖";
-            if (string.IsNullOrWhiteSpace(dto.MaterialName)) return "鐗╂枡鎻忚堪涓嶈兘涓虹┖";
-            if (string.IsNullOrWhiteSpace(dto.ReqTime)) return "璇锋眰鏃堕棿涓嶈兘涓虹┖";
-            if (dto.Floor != 1 && dto.Floor != 2) return $"妤煎眰娈甸敊璇紝蹇呴』涓�1(妯″垏娈�)鎴�2(鍗风粫娈�)锛屽綋鍓嶅�硷細{dto.Floor}";
-            if (dto.YinYang != 1 && dto.YinYang != 2) return $"闃撮槼鏋侀敊璇紝蹇呴』涓�1(闃存瀬)鎴�2(闃虫瀬)锛屽綋鍓嶅�硷細{dto.YinYang}";
-            if (dto.InOut != 1 && dto.InOut != 2) return $"鍑哄叆搴撶被鍨嬮敊璇紝蹇呴』涓�1(鍏ュ簱)鎴�2(鍑哄簱)锛屽綋鍓嶅�硷細{dto.InOut}";
-            if (dto.InOut == 1 && (dto.Width == null || dto.Width <= 0)) return "鍏ュ簱鏃跺搴︿笉鑳戒负绌轰笖蹇呴』澶т簬0";
-            if (dto.InOut == 1 && string.IsNullOrWhiteSpace(dto.Group)) return "鍏ュ簱鏃舵暣鎵樼粍鍒笉鑳戒负绌�";
-            return null;
-        }
-
-        private static string? ValidateOutTaskCompleteRequest(OutTaskCompleteDto dto)
-        {
-            if (dto == null) return "璇锋眰鍙傛暟涓嶈兘涓虹┖";
-            if (string.IsNullOrWhiteSpace(dto.TaskId)) return "浠诲姟鍙蜂笉鑳戒负绌�";
-            if (string.IsNullOrWhiteSpace(dto.DevId)) return "鍑哄簱鍙g紪鍙蜂笉鑳戒负绌�";
-            return null;
-        }
-
-        private static string? ValidateApplyEnterRequest(ApplyEnterDto dto)
-        {
-            if (dto == null) return "璇锋眰鍙傛暟涓嶈兘涓虹┖";
-            if (string.IsNullOrWhiteSpace(dto.DevId)) return "璁惧缂栧彿涓嶈兘涓虹┖";
-            if (string.IsNullOrWhiteSpace(dto.TaskId)) return "浠诲姟鍙蜂笉鑳戒负绌�";
-            if (dto.InOut != 1 && dto.InOut != 2) return $"鍑哄叆搴撶被鍨嬮敊璇紝蹇呴』涓�1(鍏ュ簱)鎴�2(鍑哄簱)锛屽綋鍓嶅�硷細{dto.InOut}";
-            return null;
-        }
-
-        private static string? ValidateTaskCompleteRequest(TaskCompleteDto dto)
-        {
-            if (dto == null) return "璇锋眰鍙傛暟涓嶈兘涓虹┖";
-            if (string.IsNullOrWhiteSpace(dto.TaskId)) return "浠诲姟鍙蜂笉鑳戒负绌�";
-            if (string.IsNullOrWhiteSpace(dto.DevId)) return "璁惧缂栧彿涓嶈兘涓虹┖";
-            if (dto.InOut != 1 && dto.InOut != 2) return $"鍑哄叆搴撶被鍨嬮敊璇紝蹇呴』涓�1(鍏ュ簱)鎴�2(鍑哄簱)锛屽綋鍓嶅�硷細{dto.InOut}";
-            return null;
-        }
-
-        private static string? ValidateTaskCancelRequest(TaskCancelDto dto)
-        {
-            if (dto == null) return "璇锋眰鍙傛暟涓嶈兘涓虹┖";
-            if (string.IsNullOrWhiteSpace(dto.TaskId)) return "浠诲姟鍙蜂笉鑳戒负绌�";
-            return null;
-        }
-        #endregion 鍙傛暟楠岃瘉
-
-        #region 鍏蜂綋瀹炵幇
-        // 鍑哄叆搴撳叡鐢ㄥ垱寤轰换鍔�
-        private Dt_Task BuildAgvTask(ApplyInOutDto dto)
-        {
-            var task = new Dt_Task
-            {
-                OrderNo = dto.TaskId,
-                PalletCode = dto.TrayNumber,
-                PalletType = dto.Floor,
-                Grade = 1,
-                Creater = "AGV",
-                CreateDate = DateTime.Now,
-                Remark = $"鐗╂枡绫诲瀷锛歿dto.MaterialType}锛岀墿鏂欐弿杩帮細{dto.MaterialName}"
-            };
-
-            if (dto.YinYang == 1)
-            {
-                task.Roadway = WarehouseEnum.FJ1.ToString();
-                task.WarehouseId = (int)WarehouseEnum.FJ1;
-                task.SourceAddress = dto.InOut == 1 ? "D10010" : "D10020";
-                task.NextAddress = "D10080";
-                task.TargetAddress = "闃存瀬鍗峰簱";
-            }
-            else
-            {
-                task.Roadway = WarehouseEnum.ZJ1.ToString();
-                task.WarehouseId = (int)WarehouseEnum.ZJ1;
-                task.SourceAddress = dto.InOut == 1 ? "D10100" : "D10090";
-                task.NextAddress = "D10160";
-                task.TargetAddress = "姝f瀬鍗峰簱";
-            }
-
-            return task;
-        }
-
-        // 鏋勫缓杩斿洖AGV鍑哄叆搴撹姹備綋
-        private AGVDataDto BuildAgvDataDto(Dt_Task task, ApplyInOutDto dto)
-        {
-            return new AGVDataDto
-            {
-                DevId = dto.InOut == 1 ? task.SourceAddress : task.TargetAddress,
-                TrayNumber = task.PalletCode,
-                Group = dto.Group,
-                Width = dto.Width ?? 0,
-                LabelNumber = dto.LabelNumber,
-                ProductNo = dto.ProductNo,
-                ProductName = dto.ProductName,
-                Quantity = dto.Quantity,
-                UomCode = dto.UomCode,
-                ProductType = dto.ProductType,
-                Equipment = dto.Equipment,
-                ProductionDate = dto.ProductionDate,
-                LowerLimitTime = dto.LowerLimitTime,
-                WarningTime = dto.WarningTime,
-                OverdueTime = dto.OverdueTime
-            };
-        }
-
-        // 鍏ュ簱鍒涘缓
-        private async Task<AGVResponse?> CreateAgvInboundTaskAsync(Dt_Task task, ApplyInOutDto dto)
-        {
-            AGVResponse response = new AGVResponse();
-            var stockInfo = await _stockInfoService.GetStockInfoAsync(dto.TrayNumber);
-            if (stockInfo != null)
-                return response.Error($"褰撳墠鎵樼洏{dto.TrayNumber}宸茬粡鍏ュ簱浜�");
-
-            // 鍒涘缓搴撳瓨鏄庣粏
-            var details = new Dt_StockInfoDetail
-            {
-                MaterielCode = dto.ProductNo,
-                MaterielName = dto.ProductName,
-                StockQuantity = int.TryParse(dto.Quantity, out int quantity) ? quantity : 0,
-                Unit = dto.UomCode,
-                OrderNo = dto.ProductNo,
-                ProductionDate =dto.ProductionDate,
-                EffectiveDate = dto.LowerLimitTime,
-                SerialNumber = dto.TrayNumber,
-                Status = (int)StockStatusEmun.鍏ュ簱纭,
-                InboundOrderRowNo = 1,
-                Creater = StockConstants.AGV_USER,
-                CreateDate = DateTime.Now,
-                Remark = $"AGV鍏ュ簱浠诲姟鍒涘缓锛屼换鍔″彿锛歿dto.TaskId}"
-            };
-
-            // 鍒涘缓搴撳瓨涓昏褰�
-            var stock = new Dt_StockInfo
-            {
-                PalletCode = dto.TrayNumber,
-                PalletType = dto.Floor,
-                WarehouseId = dto.YinYang == 1 ? (int)WarehouseEnum.FJ1 : (int)WarehouseEnum.ZJ1,
-                StockStatus = (int)StockStatusEmun.鍏ュ簱纭,
-                Creater = StockConstants.AGV_USER,
-                CreateDate = DateTime.Now,
-                Remark = $"AGV鍏ュ簱浠诲姟鍒涘缓锛屼换鍔″彿锛歿dto.TaskId}",
-                Details = new List<Dt_StockInfoDetail> { details }
-            };
-
-            task.TaskType = (int)TaskInboundTypeEnum.Inbound;
-            task.TaskStatus = (int)TaskInStatusEnum.InNew;
-            task.CurrentAddress = task.SourceAddress;
-
-            _unitOfWorkManage.BeginTran();
-            try
-            {
-                // 鍏堝垱寤轰换鍔�
-                var taskResult = await BaseDal.AddDataAsync(task) > 0;
-                if (!taskResult)
-                {
-                    _unitOfWorkManage.RollbackTran();
-                    return response.Error("鍏ュ簱浠诲姟鍒涘缓澶辫触");
+using Mapster;
+using System.Text.Json;
+using WIDESEA_Common.Constants;
+using WIDESEA_Common.LocationEnum;
+using WIDESEA_Common.StockEnum;
+using WIDESEA_Common.TaskEnum;
+using WIDESEA_Common.WareHouseEnum;
+using WIDESEA_Core;
+using WIDESEA_Core.Enums;
+using WIDESEA_Core.Helper;
+using WIDESEA_DTO.Task;
+using WIDESEA_IStockService;
+using WIDESEA_Model.Models;
+
+namespace WIDESEA_TaskInfoService
+{
+    public partial class TaskService
+    {
+
+        public string AGV_OutTaskComplete = WIDESEA_Core.Helper.AppSettings.Configuration["AGV_OutTaskComplete"];
+        public string WCS_ReceiveTask = WIDESEA_Core.Helper.AppSettings.Configuration["WCS_ReceiveTask"];
+
+        /// <summary>
+        /// 鏋佸嵎搴撳嚭鍏ュ簱鐢宠
+        /// </summary>
+        public async Task<AGVResponse> ApplyInOutAsync(ApplyInOutDto applyInOutDto)
+        {
+            AGVResponse response = new AGVResponse();
+
+            try
+            {
+                var validationMessage = ValidateApplyInOutRequest(applyInOutDto);
+                if (validationMessage != null)
+                    return response.Error(validationMessage);
+
+                var existingTask = await BaseDal.QueryFirstAsync(x => x.PalletCode == applyInOutDto.TrayNumber || x.OrderNo == applyInOutDto.TaskId);
+                if (existingTask != null)
+                    return response.Error($"WMS宸叉湁褰撳墠浠诲姟锛屼笉鍙噸澶嶄笅鍙戯紝浠诲姟鍙凤細{applyInOutDto.TaskId}");
+
+                var task = BuildAgvTask(applyInOutDto);
+
+                if (applyInOutDto.InOut == 1)
+                {
+                    var inboundResult = await CreateAgvInboundTaskAsync(task, applyInOutDto);
+                    if (inboundResult != null)
+                        return inboundResult;
+                }
+                else
+                {
+                    var outboundResult = await CreateAgvOutboundTaskAsync(task, applyInOutDto);
+                    if (outboundResult != null)
+                        return outboundResult;
+                }
+
+                return response.OK(BuildAgvDataDto(task, applyInOutDto));
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                return response.Error($"WMS浠诲姟鍒涘缓鎺ュ彛閿欒: {ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 鎵嬪姩鍑哄簱瀹屾垚鍙嶉缁橝GV
+        /// </summary>
+        public async Task<WebResponseContent> OutTaskComplete(OutTaskCompleteDto outTaskCompleteDto)
+        {
+            WebResponseContent response = new WebResponseContent();
+
+            try
+            {
+                var validationMessage = ValidateOutTaskCompleteRequest(outTaskCompleteDto);
+                if (validationMessage != null)
+                    return response.Error(validationMessage);
+
+                var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == outTaskCompleteDto.TaskId);
+                if (task == null)
+                    return response.Error("鏈壘鍒颁换鍔′俊鎭�");
+
+                outTaskCompleteDto.ReqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
+                var httpResponse = _httpClientHelper.Post<AGVResponse>(AGV_OutTaskComplete, outTaskCompleteDto.ToJson()).Data;
+                if (httpResponse == null || httpResponse.Data == null)
+                    return response.Error(httpResponse?.Msg ?? "AGV鎺ュ彛璋冪敤寮傚父");
+
+                if (!httpResponse.Code)
+                        return response.Error(string.IsNullOrWhiteSpace(httpResponse.Msg) ? "AGV鎺ュ彛璋冪敤澶辫触" : httpResponse.Msg);
+
+                var syncResult = await CompleteLocalOutboundAfterAgvAckAsync(task);
+                return syncResult.Status ? response.OK(httpResponse.Msg) : syncResult;
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                return response.Error($"WMS浠诲姟瀹屾垚鎺ュ彛閿欒锛歿ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 杈撻�佺嚎鐢宠杩涘叆
+        /// </summary>
+        public async Task<AGVResponse> ApplyEnterAsync(ApplyEnterDto applyEnterDto)
+        {
+            AGVResponse response = new AGVResponse();
+
+            try
+            {
+                var validationMessage = ValidateApplyEnterRequest(applyEnterDto);
+                if (validationMessage != null)
+                    return response.Error(validationMessage);
+
+                var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == applyEnterDto.TaskId);
+                if (task == null)
+                    return response.Error($"鏈壘鍒颁换鍔′俊鎭紝浠诲姟鍙凤細{applyEnterDto.TaskId}");
+
+                if (CanApplyEnter(task, applyEnterDto))
+                    return response.OK();
+
+                return response.Error($"杈撻�佺嚎{applyEnterDto.DevId}褰撳墠绻佸繖锛岃绋嶅悗閲嶈瘯");
+            }
+            catch (Exception ex)
+            {
+                return response.Error($"WMS杈撻�佺嚎鐢宠鎺ュ彛閿欒锛歿ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 鍙栨斁璐у畬鎴�
+        /// </summary>
+        public async Task<AGVResponse> TaskCompleteAsync(TaskCompleteDto taskCompleteDto)
+        {
+            AGVResponse response = new AGVResponse();
+
+            try
+            {
+                var validationMessage = ValidateTaskCompleteRequest(taskCompleteDto);
+                if (validationMessage != null)
+                    return response.Error(validationMessage);
+
+                var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == taskCompleteDto.TaskId);
+                if (task == null)
+                    return response.Error($"鏈壘鍒颁换鍔′俊鎭紝浠诲姟鍙凤細{taskCompleteDto.TaskId}");
+
+                return taskCompleteDto.InOut == 2
+                    ? await CompleteAgvOutboundTaskAsync(task)
+                    : await CompleteAgvInboundTaskAsync(task);
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                return response.Error($"WMS鍙栨斁璐у畬鎴愭帴鍙i敊璇細{ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 浠诲姟鍙栨秷
+        /// </summary>
+        public async Task<AGVResponse> TaskCancelAsync(TaskCancelDto taskCancelDto)
+        {
+            AGVResponse response = new AGVResponse();
+
+            try
+            {
+                var validationMessage = ValidateTaskCancelRequest(taskCancelDto);
+                if (validationMessage != null)
+                    return response.Error(validationMessage);
+
+                var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == taskCancelDto.TaskId);
+                if (task == null)
+                    return response.OK();
+
+                if (task.TaskStatus == (int)TaskInStatusEnum.InNew)
+                    return await CancelAgvInboundTask(task);
+
+                if (task.TaskStatus == (int)TaskOutStatusEnum.OutNew)
+                    return await CancelAgvOutboundTaskAsync(task);
+
+                return response.Error("浠诲姟宸茬粡鍦ㄦ墽琛屼腑锛屼笉鍙彇娑�");
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                return response.Error($"WMS浠诲姟鍙栨秷鎺ュ彛閿欒锛歿ex.Message}");
+            }
+        }
+
+        #region 鍙傛暟楠岃瘉
+        private static string? ValidateApplyInOutRequest(ApplyInOutDto dto)
+        {
+            if (dto == null) return "璇锋眰鍙傛暟涓嶈兘涓虹┖";
+            if (string.IsNullOrWhiteSpace(dto.TrayNumber)) return "鎵樼洏鍙蜂笉鑳戒负绌�";
+            if (string.IsNullOrWhiteSpace(dto.TaskId)) return "浠诲姟鍙蜂笉鑳戒负绌�";
+            if (string.IsNullOrWhiteSpace(dto.MaterialType)) return "鐗╂枡绫诲瀷涓嶈兘涓虹┖";
+            if (string.IsNullOrWhiteSpace(dto.MaterialName)) return "鐗╂枡鎻忚堪涓嶈兘涓虹┖";
+            if (string.IsNullOrWhiteSpace(dto.ReqTime)) return "璇锋眰鏃堕棿涓嶈兘涓虹┖";
+            if (dto.Floor != 1 && dto.Floor != 2) return $"妤煎眰娈甸敊璇紝蹇呴』涓�1(妯″垏娈�)鎴�2(鍗风粫娈�)锛屽綋鍓嶅�硷細{dto.Floor}";
+            if (dto.YinYang != 1 && dto.YinYang != 2) return $"闃撮槼鏋侀敊璇紝蹇呴』涓�1(闃存瀬)鎴�2(闃虫瀬)锛屽綋鍓嶅�硷細{dto.YinYang}";
+            if (dto.InOut != 1 && dto.InOut != 2) return $"鍑哄叆搴撶被鍨嬮敊璇紝蹇呴』涓�1(鍏ュ簱)鎴�2(鍑哄簱)锛屽綋鍓嶅�硷細{dto.InOut}";
+            if (dto.InOut == 1 && (dto.Width == null || dto.Width <= 0)) return "鍏ュ簱鏃跺搴︿笉鑳戒负绌轰笖蹇呴』澶т簬0";
+            if (dto.InOut == 1 && string.IsNullOrWhiteSpace(dto.Group)) return "鍏ュ簱鏃舵暣鎵樼粍鍒笉鑳戒负绌�";
+            return null;
+        }
+
+        private static string? ValidateOutTaskCompleteRequest(OutTaskCompleteDto dto)
+        {
+            if (dto == null) return "璇锋眰鍙傛暟涓嶈兘涓虹┖";
+            if (string.IsNullOrWhiteSpace(dto.TaskId)) return "浠诲姟鍙蜂笉鑳戒负绌�";
+            if (string.IsNullOrWhiteSpace(dto.DevId)) return "鍑哄簱鍙g紪鍙蜂笉鑳戒负绌�";
+            return null;
+        }
+
+        private static string? ValidateApplyEnterRequest(ApplyEnterDto dto)
+        {
+            if (dto == null) return "璇锋眰鍙傛暟涓嶈兘涓虹┖";
+            if (string.IsNullOrWhiteSpace(dto.DevId)) return "璁惧缂栧彿涓嶈兘涓虹┖";
+            if (string.IsNullOrWhiteSpace(dto.TaskId)) return "浠诲姟鍙蜂笉鑳戒负绌�";
+            if (dto.InOut != 1 && dto.InOut != 2) return $"鍑哄叆搴撶被鍨嬮敊璇紝蹇呴』涓�1(鍏ュ簱)鎴�2(鍑哄簱)锛屽綋鍓嶅�硷細{dto.InOut}";
+            return null;
+        }
+
+        private static string? ValidateTaskCompleteRequest(TaskCompleteDto dto)
+        {
+            if (dto == null) return "璇锋眰鍙傛暟涓嶈兘涓虹┖";
+            if (string.IsNullOrWhiteSpace(dto.TaskId)) return "浠诲姟鍙蜂笉鑳戒负绌�";
+            if (string.IsNullOrWhiteSpace(dto.DevId)) return "璁惧缂栧彿涓嶈兘涓虹┖";
+            if (dto.InOut != 1 && dto.InOut != 2) return $"鍑哄叆搴撶被鍨嬮敊璇紝蹇呴』涓�1(鍏ュ簱)鎴�2(鍑哄簱)锛屽綋鍓嶅�硷細{dto.InOut}";
+            return null;
+        }
+
+        private static string? ValidateTaskCancelRequest(TaskCancelDto dto)
+        {
+            if (dto == null) return "璇锋眰鍙傛暟涓嶈兘涓虹┖";
+            if (string.IsNullOrWhiteSpace(dto.TaskId)) return "浠诲姟鍙蜂笉鑳戒负绌�";
+            return null;
+        }
+        #endregion 鍙傛暟楠岃瘉
+
+        #region 鍏蜂綋瀹炵幇
+        // 鍑哄叆搴撳叡鐢ㄥ垱寤轰换鍔�
+        private Dt_Task BuildAgvTask(ApplyInOutDto dto)
+        {
+            var task = new Dt_Task
+            {
+                OrderNo = dto.TaskId,
+                PalletCode = dto.TrayNumber,
+                PalletType = dto.Floor,
+                Grade = 1,
+                Creater = "AGV",
+                CreateDate = DateTime.Now,
+                Remark = $"鐗╂枡绫诲瀷锛歿dto.MaterialType}锛岀墿鏂欐弿杩帮細{dto.MaterialName}"
+            };
+
+            if (dto.YinYang == 1)
+            {
+                task.Roadway = WarehouseEnum.FJ1.ToString();
+                task.WarehouseId = (int)WarehouseEnum.FJ1;
+                task.SourceAddress = dto.InOut == 1 ? "D10010" : "D10020";
+                task.NextAddress = "D10080";
+                task.TargetAddress = "闃存瀬鍗峰簱";
+            }
+            else
+            {
+                task.Roadway = WarehouseEnum.ZJ1.ToString();
+                task.WarehouseId = (int)WarehouseEnum.ZJ1;
+                task.SourceAddress = dto.InOut == 1 ? "D10100" : "D10090";
+                task.NextAddress = "D10160";
+                task.TargetAddress = "姝f瀬鍗峰簱";
+            }
+
+            return task;
+        }
+
+        // 鏋勫缓杩斿洖AGV鍑哄叆搴撹姹備綋
+        private AGVDataDto BuildAgvDataDto(Dt_Task task, ApplyInOutDto dto)
+        {
+            return new AGVDataDto
+            {
+                DevId = dto.InOut == 1 ? task.SourceAddress : task.TargetAddress,
+                TrayNumber = task.PalletCode,
+                Group = dto.Group,
+                Width = dto.Width ?? 0,
+                LabelNumber = dto.LabelNumber,
+                ProductNo = dto.ProductNo,
+                ProductName = dto.ProductName,
+                Quantity = dto.Quantity,
+                UomCode = dto.UomCode,
+                ProductType = dto.ProductType,
+                Equipment = dto.Equipment,
+                ProductionDate = dto.ProductionDate,
+                LowerLimitTime = dto.LowerLimitTime,
+                WarningTime = dto.WarningTime,
+                OverdueTime = dto.OverdueTime
+            };
+        }
+
+        // 鍏ュ簱鍒涘缓
+        private async Task<AGVResponse?> CreateAgvInboundTaskAsync(Dt_Task task, ApplyInOutDto dto)
+        {
+            AGVResponse response = new AGVResponse();
+            var stockInfo = await _stockInfoService.GetStockInfoAsync(dto.TrayNumber);
+            if (stockInfo != null)
+                return response.Error($"褰撳墠鎵樼洏{dto.TrayNumber}宸茬粡鍏ュ簱浜�");
+
+            // 鍒涘缓搴撳瓨鏄庣粏
+            var details = new Dt_StockInfoDetail
+            {
+                MaterielCode = dto.ProductNo,
+                MaterielName = dto.ProductName,
+                StockQuantity = int.TryParse(dto.Quantity, out int quantity) ? quantity : 0,
+                Unit = dto.UomCode,
+                OrderNo = dto.ProductNo,
+                ProductionDate =dto.ProductionDate,
+                EffectiveDate = dto.LowerLimitTime,
+                SerialNumber = dto.TrayNumber,
+                Status = (int)StockStatusEmun.鍏ュ簱纭,
+                InboundOrderRowNo = 1,
+                Creater = StockConstants.AGV_USER,
+                CreateDate = DateTime.Now,
+                Remark = $"AGV鍏ュ簱浠诲姟鍒涘缓锛屼换鍔″彿锛歿dto.TaskId}"
+            };
+
+            // 鍒涘缓搴撳瓨涓昏褰�
+            var stock = new Dt_StockInfo
+            {
+                PalletCode = dto.TrayNumber,
+                PalletType = dto.Floor,
+                WarehouseId = dto.YinYang == 1 ? (int)WarehouseEnum.FJ1 : (int)WarehouseEnum.ZJ1,
+                StockStatus = (int)StockStatusEmun.鍏ュ簱纭,
+                Creater = StockConstants.AGV_USER,
+                CreateDate = DateTime.Now,
+                Remark = $"AGV鍏ュ簱浠诲姟鍒涘缓锛屼换鍔″彿锛歿dto.TaskId}",
+                Details = new List<Dt_StockInfoDetail> { details }
+            };
+
+            task.TaskType = (int)TaskInboundTypeEnum.Inbound;
+            task.TaskStatus = (int)TaskInStatusEnum.InNew;
+            task.CurrentAddress = task.SourceAddress;
+
+            _unitOfWorkManage.BeginTran();
+            try
+            {
+                // 鍏堝垱寤轰换鍔�
+                var taskResult = await BaseDal.AddDataAsync(task) > 0;
+                if (!taskResult)
+                {
+                    _unitOfWorkManage.RollbackTran();
+                    return response.Error("鍏ュ簱浠诲姟鍒涘缓澶辫触");
                 }
                 var result = _stockInfoService.Repository.AddData(stock, x => x.Details);
                 if (result)
-                {
-                    _unitOfWorkManage.CommitTran();
-                    return null;
+                {
+                    _unitOfWorkManage.CommitTran();
+                    return null;
                 }
-                else
-                {
-                    _unitOfWorkManage.RollbackTran();
-                    return response.Error("搴撳瓨淇℃伅鍒涘缓澶辫触");
+                else
+                {
+                    _unitOfWorkManage.RollbackTran();
+                    return response.Error("搴撳瓨淇℃伅鍒涘缓澶辫触");
                 }
-                // 浣跨敤搴撳瓨鏈嶅姟娣诲姞搴撳瓨涓昏褰曞拰鏄庣粏
-                //var stockResult = await _stockInfoService.AddStockWithDetailsUsingTransactionAsync(stock);
-
-            }
-            catch (Exception ex)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return response.Error($"鍏ュ簱浠诲姟鍒涘缓寮傚父锛歿ex.Message}");
-            }
-        }
-
-        // 鍑哄簱鍒涘缓
-        private async Task<AGVResponse?> CreateAgvOutboundTaskAsync(Dt_Task task, ApplyInOutDto dto)
-        {
-            AGVResponse response = new AGVResponse();
-            
-            // 妫�鏌ュ簱瀛樻槸鍚﹀瓨鍦�
-            var stockInfo = await _stockInfoService.GetStockInfoAsync(dto.TrayNumber);
-            if (stockInfo == null)
-                return response.Error($"鏈壘鍒版墭鐩榹dto.TrayNumber}鐨勫簱瀛樹俊鎭�");
-
-            // 妫�鏌ュ簱瀛樻槸鍚︽湁鏄庣粏锛堝嵆鏄惁鐪熺殑鏈夊簱瀛橈級
-            if (stockInfo.Details == null || !stockInfo.Details.Any())
-                return response.Error($"鎵樼洏{dto.TrayNumber}娌℃湁搴撳瓨鏄庣粏锛屾棤娉曞嚭搴�");
-
-            // 妫�鏌ュ簱瀛樻�绘暟閲忔槸鍚﹀ぇ浜�0
-            var totalQuantity = stockInfo.Details.Sum(d => d.StockQuantity);
-            if (totalQuantity <= 0)
-                return response.Error($"鎵樼洏{dto.TrayNumber}搴撳瓨鏁伴噺涓嶈冻锛屾棤娉曞嚭搴�");
-
-            // 鏍规嵁dto鍙傛暟杩涗竴姝ラ獙璇佸簱瀛樹俊鎭�
-            if (!string.IsNullOrEmpty(dto.ProductNo))
-            {
-                // 妫�鏌ュ簱瀛樻槑缁嗕腑鏄惁鍖呭惈鎸囧畾鐨勭墿鏂欑紪鐮�
-                var hasMatchingMaterial = stockInfo.Details.Any(d => d.MaterielCode == dto.ProductNo);
-                if (!hasMatchingMaterial)
-                    return response.Error($"鎵樼洏{dto.TrayNumber}涓病鏈夌墿鏂欑紪鐮佷负{dto.ProductNo}鐨勫簱瀛橈紝鏃犳硶鍑哄簱");
-            }
-
-            // 妫�鏌ュ簱瀛樼姸鎬佹槸鍚﹀厑璁稿嚭搴�
-            if (stockInfo.StockStatus != (int)StockStatusEmun.鍏ュ簱瀹屾垚)
-                return response.Error($"鎵樼洏{dto.TrayNumber}姝e湪绉诲姩涓紝璇风◢鍚庯紒");
-
-            // 妫�鏌ヨ揣浣嶄俊鎭�
-            var locationInfo = await _locationInfoService.GetLocationInfo(stockInfo.LocationCode);
-            if (locationInfo == null)
-                return response.Error($"鏈壘鍒版墭鐩榹stockInfo.LocationCode}鐨勮揣浣嶄俊鎭�");
-
-            // 妫�鏌ヨ揣浣嶇姸鎬佹槸鍚﹀厑璁稿嚭搴�
-            if (locationInfo.LocationStatus != (int)LocationStatusEnum.InStock)
-                return response.Error($"褰撳墠璐т綅{locationInfo.LocationStatus}鐘舵�佷俊鎭敊璇�");
-
-            // 楠岃瘉浠撳簱ID鏄惁鍖归厤锛堟牴鎹甦to鐨勯槾闃虫瀬鍙傛暟锛�
-            var expectedWarehouseId = dto.YinYang == 1 ? (int)WarehouseEnum.FJ1 : (int)WarehouseEnum.ZJ1;
-            if (stockInfo.WarehouseId != expectedWarehouseId)
-                return response.Error($"鎵樼洏{dto.TrayNumber}涓嶅湪棰勬湡鐨勪粨搴撲腑锛屾棤娉曞嚭搴�");
-
-            task.TaskType = (int)TaskOutboundTypeEnum.Outbound;
-            task.TaskStatus = (int)TaskOutStatusEnum.OutNew;
-            task.SourceAddress = stockInfo.LocationCode;
-            task.CurrentAddress = stockInfo.LocationCode;
-            task.TargetAddress = dto.YinYang == 1 ? "D10020" : "D10090";
-
-            var wmsTaskDto = _mapper.Map<WMSTaskDTO>(task);
-            var taskList = new List<WMSTaskDTO> { wmsTaskDto };
-            var requestBody = JsonSerializer.Serialize(taskList);
-
-            var httpResponse = _httpClientHelper.Post<WebResponseContent>(WCS_ReceiveTask, requestBody);
-            if (httpResponse == null || httpResponse.Data == null || !httpResponse.Data.Status)
-                return response.Error(httpResponse?.Data?.Message ?? "涓嬪彂WCS澶辫触");
-
-            stockInfo.StockStatus = (int)StockStatusEmun.鍑哄簱閿佸畾;
-            locationInfo.LocationStatus = (int)LocationStatusEnum.InStockLock;
-
-            _unitOfWorkManage.BeginTran();
-            var addTaskResult = await BaseDal.AddDataAsync(task) > 0;
-            var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo);
-            var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
-            if (!addTaskResult || !updateLocationResult || !updateStockResult)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return response.Error("鍑哄簱浠诲姟鍒涘缓澶辫触");
-            }
-            _unitOfWorkManage.CommitTran();
-
-
-            return null;
-        }
-
-        private async Task<WebResponseContent> CompleteLocalOutboundAfterAgvAckAsync(Dt_Task task)
-        {
-            task.TaskStatus = (int)TaskOutStatusEnum.Line_OutFinish;
-
-            _unitOfWorkManage.BeginTran();
-            var updateResult = BaseDal.UpdateData(task);
-            if (!updateResult)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return WebResponseContent.Instance.Error("AGV瀹屾垚鍥炰紶鍚庯紝浠诲姟鏇存柊澶辫触");
-            }
-
-            _unitOfWorkManage.CommitTran();
-            return WebResponseContent.Instance.OK();
-        }
-
-        private bool CanApplyEnter(Dt_Task task, ApplyEnterDto dto)
-        {
-            if (dto.InOut == 1)
-            {
-                var hasExecutingOutTask = BaseDal.QueryFirst(x => x.TaskType == (int)TaskOutboundTypeEnum.Outbound
-                    && x.TargetAddress == task.SourceAddress
-                    && (x.TaskStatus == (int)TaskOutStatusEnum.SC_OutExecuting
-                        || x.TaskStatus == (int)TaskOutStatusEnum.Line_OutExecuting));
-
-                // 濡傛灉娌℃湁姝e湪鎵ц鐨勫嚭搴撲换鍔★紝鍒欏厑璁稿叆搴�
-                return hasExecutingOutTask == null;
-            }
-            else
-            {
-                return task.TaskType == (int)TaskOutboundTypeEnum.Outbound
-                    && task.TaskStatus == (int)TaskStatusEnum.Line_Finish;
-            }
-        }
-
-        // WCS鍏ュ簱瀹屾垚
-        private async Task<WebResponseContent> CompleteAgvInboundTaskAsync(CreateTaskDto taskDto)
-        {
-            WebResponseContent response = new WebResponseContent();
-            var task = await BaseDal.QueryFirstAsync(x => x.PalletType == taskDto.PalletType);
-            if (task == null)
-                return response.Error($"娌℃湁褰撳墠鎵樼洏{taskDto.PalletType}鍏ュ簱浠诲姟");
-
-            var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
-            if (stockInfo == null)
-                return response.Error($"鏈壘鍒版墭鐩榹task.PalletCode}鐨勫簱瀛樹俊鎭�");
-
-            var locationInfo = await _locationInfoService.GetLocationInfoAsync(task.TargetAddress);
-            if (locationInfo == null)
-                return response.Error($"鏈壘鍒拌揣浣峽task.TargetAddress}鐨勪俊鎭�");
-
-            if (locationInfo.LocationStatus == (int)LocationStatusEnum.InStock)
-                return response.Error($"褰撳墠璐т綅{locationInfo.LocationStatus}鐘舵�佷笉鏄┖闂茬姸鎬侊紝鏃犳硶鍏ュ簱");
-
-            // 鏇存柊璐т綅鐘舵�佷负鍗犵敤
-            locationInfo.LocationStatus = (int)LocationStatusEnum.InStock;
-            task.TaskStatus = (int)TaskInStatusEnum.InFinish;
-            stockInfo.StockStatus = (int)StockStatusEmun.鍏ュ簱瀹屾垚;
-            _unitOfWorkManage.BeginTran();
-            var addStockResult = _stockInfoService.UpdateData(stockInfo);
-            var updateLocationResult = _locationInfoService.UpdateData(locationInfo);
-            BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.鑷姩瀹屾垚 : OperateTypeEnum.浜哄伐瀹屾垚);
-
-            if (!addStockResult.Status || !updateLocationResult.Status)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return response.Error("鍏ュ簱瀹屾垚鍚庯紝娣诲姞搴撳瓨鎴栬揣浣嶆洿鏂板け璐�");
-            }
-
-            _unitOfWorkManage.CommitTran();
-            return response.OK();
-        }
-
-        // AGV鍑哄簱瀹屾垚
-        private async Task<AGVResponse> CompleteAgvOutboundTaskAsync(Dt_Task task)
-        {
-            AGVResponse response = new AGVResponse();
-            var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
-            if (stockInfo == null)
-                return response.Error($"鏈壘鍒版墭鐩榹task.PalletCode}鐨勫簱瀛樹俊鎭�");
-
-            var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode);
-            if (locationInfo == null)
-                return response.Error($"鏈壘鍒版墭鐩榹stockInfo.LocationCode}鐨勮揣浣嶄俊鎭�");
-
-            if (stockInfo.StockStatus != (int)StockStatusEmun.鍑哄簱閿佸畾 || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock)
-                return response.Error($"褰撳墠搴撳瓨{stockInfo.StockStatus}鎴栬�呰揣浣峽locationInfo.LocationStatus}鐘舵�佷俊鎭敊璇�");
-
-            locationInfo.LocationStatus = (int)LocationStatusEnum.Free;
-            task.TaskStatus = (int)TaskOutStatusEnum.OutFinish;
-
-            _unitOfWorkManage.BeginTran();
-            //var deleteStockResult = _stockInfoService.DeleteData(stockInfo)
-            var deleteStockResult = await _stockInfoService.DeleteStockWithDetailsAsync(stockInfo.Id);
-            var updateLocationResult = _locationInfoService.UpdateData(locationInfo);
-            BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.鑷姩瀹屾垚 : OperateTypeEnum.浜哄伐瀹屾垚);
-            if (!deleteStockResult.Status || !updateLocationResult.Status)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return response.Error("鍑哄簱瀹屾垚鍚庯紝鏈湴搴撳瓨鎴栬揣浣嶆洿鏂板け璐�");
-            }
-
-            _unitOfWorkManage.CommitTran();
-            return response.OK();
-        }
-
-        // AGV宸叉斁璐э紝鍑嗗杈撻�佺嚎鍏ュ簱
-        private async Task<AGVResponse> CompleteAgvInboundTaskAsync(Dt_Task task)
-        {
-            AGVResponse response = new AGVResponse();
-            var availableLocation = await _locationInfoService.GetLocationInfo(task.Roadway);
-            if (availableLocation == null)
-                return response.Error("鏃犲彲鐢ㄧ殑鍏ュ簱璐т綅");
-
-            task.TargetAddress = availableLocation.LocationCode;
-
-            var wmsTaskDto = _mapper.Map<WMSTaskDTO>(task);
-            var taskList = new List<WMSTaskDTO> { wmsTaskDto };
-            var requestBody = JsonSerializer.Serialize(taskList);
-
-            var httpResponse = _httpClientHelper.Post<WebResponseContent>(WCS_ReceiveTask, requestBody);
-            if (httpResponse == null || httpResponse.Data == null || !httpResponse.Data.Status)
-                return response.Error(httpResponse?.Data?.Message ?? "涓嬪彂WCS澶辫触");
-
-            task.TaskStatus = (int)TaskInStatusEnum.Line_InExecuting;
-            task.Dispatchertime = DateTime.Now;
-
-            var locationInfo = await _locationInfoService.GetLocationInfoAsync(task.TargetAddress);
-            if (locationInfo == null)
-                return response.Error($"鏈壘鍒版墭鐩榹task.TargetAddress}鐨勮揣浣嶄俊鎭�");
-
-            if (locationInfo.LocationStatus != (int)LocationStatusEnum.Free)
-                return response.Error($"褰撳墠璐т綅{locationInfo.LocationStatus}鐘舵�佷俊鎭敊璇�");
-
-            var existingStock = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
-            if (existingStock != null)
-                return response.Error($"鎵樼洏{task.PalletCode}鐨勫簱瀛樹俊鎭凡瀛樺湪锛岃鍕块噸澶嶅叆搴�");
-
-            //Dt_StockInfo stockInfo = new Dt_StockInfo
-            //{
-            //    PalletCode = task.PalletCode,
-            //    StockStatus = (int)StockStatusEmun.鍏ュ簱纭,
-            //    LocationCode = locationInfo.LocationCode,
-            //    WarehouseId = task.WarehouseId,
-            //    Creater = "AGV",
-            //    CreateDate = DateTime.Now
-            //};
-
-            locationInfo.LocationStatus = (int)LocationStatusEnum.FreeLock;
-
-            _unitOfWorkManage.BeginTran();
-            var updateTaskResult = BaseDal.UpdateData(task);
-            var updateLocationResult = _locationInfoService.UpdateData(locationInfo);
-            //var addStockResult = _stockInfoService.AddData(stockInfo);
-            if (!updateTaskResult || !updateLocationResult.Status /*|| !addStockResult.Status*/)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return response.Error("鍏ュ簱瀹屾垚鍚庯紝鏈湴浠诲姟銆佸簱瀛樻垨璐т綅鏇存柊澶辫触");
-            }
-
-            _unitOfWorkManage.CommitTran();
-            return response.OK();
-        }
-
-        // AGV鍏ュ簱鍙栨秷
-        private async Task<AGVResponse> CancelAgvInboundTask(Dt_Task task)
-        {
-            AGVResponse response = new AGVResponse();
-            task.TaskStatus = (int)TaskInStatusEnum.InCancel;
-            
-            _unitOfWorkManage.BeginTran();
-            try
-            {
-                var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
-                if (stockInfo != null)
-                {
-                    var deleteResult = await _stockInfoService.DeleteStockWithDetailsAsync(stockInfo.Id);
-                    if (!deleteResult.Status)
-                    {
-                        _unitOfWorkManage.RollbackTran();
-                        return response.Error($"鍒犻櫎搴撳瓨澶辫触: {deleteResult.Message}");
-                    }
-                }
-
-                BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.鑷姩瀹屾垚 : OperateTypeEnum.浜哄伐瀹屾垚);
-
-                _unitOfWorkManage.CommitTran();
-                return response.OK();
-            }
-            catch (Exception ex)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return response.Error($"鍙栨秷鍏ュ簱浠诲姟鏃跺彂鐢熷紓甯�: {ex.Message}");
-            }
-        }
-
-
-        // AGV鍑哄簱鍙栨秷
-        private async Task<AGVResponse> CancelAgvOutboundTaskAsync(Dt_Task task)
-        {
-            AGVResponse response = new AGVResponse();
-            var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
-            if (stockInfo == null)
-                return response.Error($"鏈壘鍒版墭鐩榹task.PalletCode}鐨勫簱瀛樹俊鎭�");
-
-            var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode);
-            if (locationInfo == null)
-                return response.Error($"鏈壘鍒版墭鐩榹stockInfo.LocationCode}鐨勮揣浣嶄俊鎭�");
-
-            if (stockInfo.StockStatus != (int)StockStatusEmun.鍑哄簱閿佸畾 || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock)
-                return response.Error($"褰撳墠搴撳瓨{stockInfo.StockStatus}鎴栬�呰揣浣峽locationInfo.LocationStatus}鐘舵�佷俊鎭敊璇�");
-
-            stockInfo.StockStatus = (int)StockStatusEmun.鍏ュ簱瀹屾垚;
-            locationInfo.LocationStatus = (int)LocationStatusEnum.InStock;
-            task.TaskStatus = (int)TaskOutStatusEnum.OutCancel;
-
-            _unitOfWorkManage.BeginTran();
-            var updateLocationResult = _locationInfoService.UpdateData(locationInfo);
-            var updateStockResult = _stockInfoService.UpdateData(stockInfo);
-            BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.鑷姩瀹屾垚 : OperateTypeEnum.浜哄伐瀹屾垚);
-            if (!updateLocationResult.Status || !updateStockResult.Status)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return response.Error("鍑哄簱浠诲姟鍙栨秷澶辫触");
-            }
-
-            _unitOfWorkManage.CommitTran();
-            return response.OK();
-        }
-
-        #endregion 鍏蜂綋瀹炵幇
-    }
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                return response.Error($"鍏ュ簱浠诲姟鍒涘缓寮傚父锛歿ex.Message}");
+            }
+        }
+
+        // 鍑哄簱鍒涘缓
+        private async Task<AGVResponse?> CreateAgvOutboundTaskAsync(Dt_Task task, ApplyInOutDto dto)
+        {
+            AGVResponse response = new AGVResponse();
+            
+            // 妫�鏌ュ簱瀛樻槸鍚﹀瓨鍦�
+            var stockInfo = await _stockInfoService.GetStockInfoAsync(dto.TrayNumber);
+            if (stockInfo == null)
+                return response.Error($"鏈壘鍒版墭鐩榹dto.TrayNumber}鐨勫簱瀛樹俊鎭�");
+
+            // 妫�鏌ュ簱瀛樻槸鍚︽湁鏄庣粏锛堝嵆鏄惁鐪熺殑鏈夊簱瀛橈級
+            if (stockInfo.Details == null || !stockInfo.Details.Any())
+                return response.Error($"鎵樼洏{dto.TrayNumber}娌℃湁搴撳瓨鏄庣粏锛屾棤娉曞嚭搴�");
+
+            // 妫�鏌ュ簱瀛樻�绘暟閲忔槸鍚﹀ぇ浜�0
+            var totalQuantity = stockInfo.Details.Sum(d => d.StockQuantity);
+            if (totalQuantity <= 0)
+                return response.Error($"鎵樼洏{dto.TrayNumber}搴撳瓨鏁伴噺涓嶈冻锛屾棤娉曞嚭搴�");
+
+            // 鏍规嵁dto鍙傛暟杩涗竴姝ラ獙璇佸簱瀛樹俊鎭�
+            if (!string.IsNullOrEmpty(dto.ProductNo))
+            {
+                // 妫�鏌ュ簱瀛樻槑缁嗕腑鏄惁鍖呭惈鎸囧畾鐨勭墿鏂欑紪鐮�
+                var hasMatchingMaterial = stockInfo.Details.Any(d => d.MaterielCode == dto.ProductNo);
+                if (!hasMatchingMaterial)
+                    return response.Error($"鎵樼洏{dto.TrayNumber}涓病鏈夌墿鏂欑紪鐮佷负{dto.ProductNo}鐨勫簱瀛橈紝鏃犳硶鍑哄簱");
+            }
+
+            // 妫�鏌ュ簱瀛樼姸鎬佹槸鍚﹀厑璁稿嚭搴�
+            if (stockInfo.StockStatus != (int)StockStatusEmun.鍏ュ簱瀹屾垚)
+                return response.Error($"鎵樼洏{dto.TrayNumber}姝e湪绉诲姩涓紝璇风◢鍚庯紒");
+
+            // 妫�鏌ヨ揣浣嶄俊鎭�
+            var locationInfo = await _locationInfoService.GetLocationInfo(stockInfo.LocationCode);
+            if (locationInfo == null)
+                return response.Error($"鏈壘鍒版墭鐩榹stockInfo.LocationCode}鐨勮揣浣嶄俊鎭�");
+
+            // 妫�鏌ヨ揣浣嶇姸鎬佹槸鍚﹀厑璁稿嚭搴�
+            if (locationInfo.LocationStatus != (int)LocationStatusEnum.InStock)
+                return response.Error($"褰撳墠璐т綅{locationInfo.LocationStatus}鐘舵�佷俊鎭敊璇�");
+
+            // 楠岃瘉浠撳簱ID鏄惁鍖归厤锛堟牴鎹甦to鐨勯槾闃虫瀬鍙傛暟锛�
+            var expectedWarehouseId = dto.YinYang == 1 ? (int)WarehouseEnum.FJ1 : (int)WarehouseEnum.ZJ1;
+            if (stockInfo.WarehouseId != expectedWarehouseId)
+                return response.Error($"鎵樼洏{dto.TrayNumber}涓嶅湪棰勬湡鐨勪粨搴撲腑锛屾棤娉曞嚭搴�");
+
+            task.TaskType = (int)TaskOutboundTypeEnum.Outbound;
+            task.TaskStatus = (int)TaskOutStatusEnum.OutNew;
+            task.SourceAddress = stockInfo.LocationCode;
+            task.CurrentAddress = stockInfo.LocationCode;
+            task.TargetAddress = dto.YinYang == 1 ? "D10020" : "D10090";
+
+            var wmsTaskDto = _mapper.Map<WMSTaskDTO>(task);
+            var taskList = new List<WMSTaskDTO> { wmsTaskDto };
+            var requestBody = JsonSerializer.Serialize(taskList);
+
+            var httpResponse = _httpClientHelper.Post<WebResponseContent>(WCS_ReceiveTask, requestBody);
+            if (httpResponse == null || httpResponse.Data == null || !httpResponse.Data.Status)
+                return response.Error(httpResponse?.Data?.Message ?? "涓嬪彂WCS澶辫触");
+
+            stockInfo.StockStatus = (int)StockStatusEmun.鍑哄簱閿佸畾;
+            locationInfo.LocationStatus = (int)LocationStatusEnum.InStockLock;
+
+            _unitOfWorkManage.BeginTran();
+            var addTaskResult = await BaseDal.AddDataAsync(task) > 0;
+            var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo);
+            var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
+            if (!addTaskResult || !updateLocationResult || !updateStockResult)
+            {
+                _unitOfWorkManage.RollbackTran();
+                return response.Error("鍑哄簱浠诲姟鍒涘缓澶辫触");
+            }
+            _unitOfWorkManage.CommitTran();
+
+
+            return null;
+        }
+
+        private async Task<WebResponseContent> CompleteLocalOutboundAfterAgvAckAsync(Dt_Task task)
+        {
+            task.TaskStatus = (int)TaskOutStatusEnum.Line_OutFinish;
+
+            _unitOfWorkManage.BeginTran();
+            var updateResult = BaseDal.UpdateData(task);
+            if (!updateResult)
+            {
+                _unitOfWorkManage.RollbackTran();
+                return WebResponseContent.Instance.Error("AGV瀹屾垚鍥炰紶鍚庯紝浠诲姟鏇存柊澶辫触");
+            }
+
+            _unitOfWorkManage.CommitTran();
+            return WebResponseContent.Instance.OK();
+        }
+
+        private bool CanApplyEnter(Dt_Task task, ApplyEnterDto dto)
+        {
+            if (dto.InOut == 1)
+            {
+                var hasExecutingOutTask = BaseDal.QueryFirst(x => x.TaskType == (int)TaskOutboundTypeEnum.Outbound
+                    && x.TargetAddress == task.SourceAddress
+                    && (x.TaskStatus == (int)TaskOutStatusEnum.SC_OutExecuting
+                        || x.TaskStatus == (int)TaskOutStatusEnum.Line_OutExecuting));
+
+                // 濡傛灉娌℃湁姝e湪鎵ц鐨勫嚭搴撲换鍔★紝鍒欏厑璁稿叆搴�
+                return hasExecutingOutTask == null;
+            }
+            else
+            {
+                return task.TaskType == (int)TaskOutboundTypeEnum.Outbound
+                    && task.TaskStatus == (int)TaskStatusEnum.Line_Finish;
+            }
+        }
+
+        // WCS鍏ュ簱瀹屾垚
+        private async Task<WebResponseContent> CompleteAgvInboundTaskAsync(CreateTaskDto taskDto)
+        {
+            WebResponseContent response = new WebResponseContent();
+            var task = await BaseDal.QueryFirstAsync(x => x.PalletType == taskDto.PalletType);
+            if (task == null)
+                return response.Error($"娌℃湁褰撳墠鎵樼洏{taskDto.PalletType}鍏ュ簱浠诲姟");
+
+            var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
+            if (stockInfo == null)
+                return response.Error($"鏈壘鍒版墭鐩榹task.PalletCode}鐨勫簱瀛樹俊鎭�");
+
+            var locationInfo = await _locationInfoService.GetLocationInfoAsync(task.TargetAddress);
+            if (locationInfo == null)
+                return response.Error($"鏈壘鍒拌揣浣峽task.TargetAddress}鐨勪俊鎭�");
+
+            if (locationInfo.LocationStatus == (int)LocationStatusEnum.InStock)
+                return response.Error($"褰撳墠璐т綅{locationInfo.LocationStatus}鐘舵�佷笉鏄┖闂茬姸鎬侊紝鏃犳硶鍏ュ簱");
+
+            // 鏇存柊璐т綅鐘舵�佷负鍗犵敤
+            locationInfo.LocationStatus = (int)LocationStatusEnum.InStock;
+            task.TaskStatus = (int)TaskInStatusEnum.InFinish;
+            stockInfo.StockStatus = (int)StockStatusEmun.鍏ュ簱瀹屾垚;
+            _unitOfWorkManage.BeginTran();
+            var addStockResult = _stockInfoService.UpdateData(stockInfo);
+            var updateLocationResult = _locationInfoService.UpdateData(locationInfo);
+            BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.鑷姩瀹屾垚 : OperateTypeEnum.浜哄伐瀹屾垚);
+
+            if (!addStockResult.Status || !updateLocationResult.Status)
+            {
+                _unitOfWorkManage.RollbackTran();
+                return response.Error("鍏ュ簱瀹屾垚鍚庯紝娣诲姞搴撳瓨鎴栬揣浣嶆洿鏂板け璐�");
+            }
+
+            _unitOfWorkManage.CommitTran();
+            return response.OK();
+        }
+
+        // AGV鍑哄簱瀹屾垚
+        private async Task<AGVResponse> CompleteAgvOutboundTaskAsync(Dt_Task task)
+        {
+            AGVResponse response = new AGVResponse();
+            var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
+            if (stockInfo == null)
+                return response.Error($"鏈壘鍒版墭鐩榹task.PalletCode}鐨勫簱瀛樹俊鎭�");
+
+            var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode);
+            if (locationInfo == null)
+                return response.Error($"鏈壘鍒版墭鐩榹stockInfo.LocationCode}鐨勮揣浣嶄俊鎭�");
+
+            if (stockInfo.StockStatus != (int)StockStatusEmun.鍑哄簱閿佸畾 || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock)
+                return response.Error($"褰撳墠搴撳瓨{stockInfo.StockStatus}鎴栬�呰揣浣峽locationInfo.LocationStatus}鐘舵�佷俊鎭敊璇�");
+
+            locationInfo.LocationStatus = (int)LocationStatusEnum.Free;
+            task.TaskStatus = (int)TaskOutStatusEnum.OutFinish;
+
+            _unitOfWorkManage.BeginTran();
+            //var deleteStockResult = _stockInfoService.DeleteData(stockInfo)
+            var deleteStockResult = await _stockInfoService.DeleteStockWithDetailsAsync(stockInfo.Id);
+            var updateLocationResult = _locationInfoService.UpdateData(locationInfo);
+            BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.鑷姩瀹屾垚 : OperateTypeEnum.浜哄伐瀹屾垚);
+            if (!deleteStockResult.Status || !updateLocationResult.Status)
+            {
+                _unitOfWorkManage.RollbackTran();
+                return response.Error("鍑哄簱瀹屾垚鍚庯紝鏈湴搴撳瓨鎴栬揣浣嶆洿鏂板け璐�");
+            }
+
+            _unitOfWorkManage.CommitTran();
+            return response.OK();
+        }
+
+        // AGV宸叉斁璐э紝鍑嗗杈撻�佺嚎鍏ュ簱
+        private async Task<AGVResponse> CompleteAgvInboundTaskAsync(Dt_Task task)
+        {
+            AGVResponse response = new AGVResponse();
+            var availableLocation = await _locationInfoService.GetLocationInfo(task.Roadway);
+            if (availableLocation == null)
+                return response.Error("鏃犲彲鐢ㄧ殑鍏ュ簱璐т綅");
+
+            task.TargetAddress = availableLocation.LocationCode;
+
+            var wmsTaskDto = _mapper.Map<WMSTaskDTO>(task);
+            var taskList = new List<WMSTaskDTO> { wmsTaskDto };
+            var requestBody = JsonSerializer.Serialize(taskList);
+
+            var httpResponse = _httpClientHelper.Post<WebResponseContent>(WCS_ReceiveTask, requestBody);
+            if (httpResponse == null || httpResponse.Data == null || !httpResponse.Data.Status)
+                return response.Error(httpResponse?.Data?.Message ?? "涓嬪彂WCS澶辫触");
+
+            task.TaskStatus = (int)TaskInStatusEnum.Line_InExecuting;
+            task.Dispatchertime = DateTime.Now;
+
+            var locationInfo = await _locationInfoService.GetLocationInfoAsync(task.TargetAddress);
+            if (locationInfo == null)
+                return response.Error($"鏈壘鍒版墭鐩榹task.TargetAddress}鐨勮揣浣嶄俊鎭�");
+
+            if (locationInfo.LocationStatus != (int)LocationStatusEnum.Free)
+                return response.Error($"褰撳墠璐т綅{locationInfo.LocationStatus}鐘舵�佷俊鎭敊璇�");
+
+            var existingStock = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
+            if (existingStock != null)
+                return response.Error($"鎵樼洏{task.PalletCode}鐨勫簱瀛樹俊鎭凡瀛樺湪锛岃鍕块噸澶嶅叆搴�");
+
+            //Dt_StockInfo stockInfo = new Dt_StockInfo
+            //{
+            //    PalletCode = task.PalletCode,
+            //    StockStatus = (int)StockStatusEmun.鍏ュ簱纭,
+            //    LocationCode = locationInfo.LocationCode,
+            //    WarehouseId = task.WarehouseId,
+            //    Creater = "AGV",
+            //    CreateDate = DateTime.Now
+            //};
+
+            locationInfo.LocationStatus = (int)LocationStatusEnum.FreeLock;
+
+            _unitOfWorkManage.BeginTran();
+            var updateTaskResult = BaseDal.UpdateData(task);
+            var updateLocationResult = _locationInfoService.UpdateData(locationInfo);
+            //var addStockResult = _stockInfoService.AddData(stockInfo);
+            if (!updateTaskResult || !updateLocationResult.Status /*|| !addStockResult.Status*/)
+            {
+                _unitOfWorkManage.RollbackTran();
+                return response.Error("鍏ュ簱瀹屾垚鍚庯紝鏈湴浠诲姟銆佸簱瀛樻垨璐т綅鏇存柊澶辫触");
+            }
+
+            _unitOfWorkManage.CommitTran();
+            return response.OK();
+        }
+
+        // AGV鍏ュ簱鍙栨秷
+        private async Task<AGVResponse> CancelAgvInboundTask(Dt_Task task)
+        {
+            AGVResponse response = new AGVResponse();
+            task.TaskStatus = (int)TaskInStatusEnum.InCancel;
+            
+            _unitOfWorkManage.BeginTran();
+            try
+            {
+                var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
+                if (stockInfo != null)
+                {
+                    var deleteResult = await _stockInfoService.DeleteStockWithDetailsAsync(stockInfo.Id);
+                    if (!deleteResult.Status)
+                    {
+                        _unitOfWorkManage.RollbackTran();
+                        return response.Error($"鍒犻櫎搴撳瓨澶辫触: {deleteResult.Message}");
+                    }
+                }
+
+                BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.鑷姩瀹屾垚 : OperateTypeEnum.浜哄伐瀹屾垚);
+
+                _unitOfWorkManage.CommitTran();
+                return response.OK();
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                return response.Error($"鍙栨秷鍏ュ簱浠诲姟鏃跺彂鐢熷紓甯�: {ex.Message}");
+            }
+        }
+
+
+        // AGV鍑哄簱鍙栨秷
+        private async Task<AGVResponse> CancelAgvOutboundTaskAsync(Dt_Task task)
+        {
+            AGVResponse response = new AGVResponse();
+            var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
+            if (stockInfo == null)
+                return response.Error($"鏈壘鍒版墭鐩榹task.PalletCode}鐨勫簱瀛樹俊鎭�");
+
+            var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode);
+            if (locationInfo == null)
+                return response.Error($"鏈壘鍒版墭鐩榹stockInfo.LocationCode}鐨勮揣浣嶄俊鎭�");
+
+            if (stockInfo.StockStatus != (int)StockStatusEmun.鍑哄簱閿佸畾 || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock)
+                return response.Error($"褰撳墠搴撳瓨{stockInfo.StockStatus}鎴栬�呰揣浣峽locationInfo.LocationStatus}鐘舵�佷俊鎭敊璇�");
+
+            stockInfo.StockStatus = (int)StockStatusEmun.鍏ュ簱瀹屾垚;
+            locationInfo.LocationStatus = (int)LocationStatusEnum.InStock;
+            task.TaskStatus = (int)TaskOutStatusEnum.OutCancel;
+
+            _unitOfWorkManage.BeginTran();
+            var updateLocationResult = _locationInfoService.UpdateData(locationInfo);
+            var updateStockResult = _stockInfoService.UpdateData(stockInfo);
+            BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.鑷姩瀹屾垚 : OperateTypeEnum.浜哄伐瀹屾垚);
+            if (!updateLocationResult.Status || !updateStockResult.Status)
+            {
+                _unitOfWorkManage.RollbackTran();
+                return response.Error("鍑哄簱浠诲姟鍙栨秷澶辫触");
+            }
+
+            _unitOfWorkManage.CommitTran();
+            return response.OK();
+        }
+
+        #endregion 鍏蜂綋瀹炵幇
+    }
 }
\ No newline at end of file
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Dashboard/DashboardController.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Dashboard/DashboardController.cs
index cd8bcce..b80970b 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Dashboard/DashboardController.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Dashboard/DashboardController.cs
@@ -1,272 +1,373 @@
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-using SqlSugar;
-using WIDESEA_Core;
-using WIDESEA_Model.Models;
-
-namespace WIDESEA_WMSServer.Controllers.Dashboard
-{
-    /// <summary>
-    /// 浠〃鐩�
-    /// </summary>
-    [Route("api/Dashboard")]
-    [ApiController]
-    public class DashboardController : ControllerBase
-    {
-        private readonly ISqlSugarClient _db;
-
-        public DashboardController(ISqlSugarClient db)
-        {
-            _db = db;
-        }
-
-        /// <summary>
-        /// 鎬昏鏁版嵁
-        /// </summary>
-        [HttpGet("Overview"), AllowAnonymous]
-        public async Task<WebResponseContent> Overview()
-        {
-            try
-            {
-                var today = DateTime.Today;
-                var firstDayOfMonth = new DateTime(today.Year, today.Month, 1);
-
-                // 浠婃棩鍏ュ簱鏁�
-                var todayInbound = await _db.Queryable<Dt_Task_Hty>()
-                    .Where(t => t.InsertTime >= today && t.TaskType >= 500 && t.TaskType < 600)
-                    .CountAsync();
-
-                // 浠婃棩鍑哄簱鏁�
-                var todayOutbound = await _db.Queryable<Dt_Task_Hty>()
-                    .Where(t => t.InsertTime >= today && t.TaskType >= 100 && t.TaskType < 200)
-                    .CountAsync();
-
-                // 鏈湀鍏ュ簱鏁�
-                var monthInbound = await _db.Queryable<Dt_Task_Hty>()
-                    .Where(t => t.InsertTime >= firstDayOfMonth && t.TaskType >= 500 && t.TaskType < 600)
-                    .CountAsync();
-
-                // 鏈湀鍑哄簱鏁�
-                var monthOutbound = await _db.Queryable<Dt_Task_Hty>()
-                    .Where(t => t.InsertTime >= firstDayOfMonth && t.TaskType >= 100 && t.TaskType < 200)
-                    .CountAsync();
-
-                // 褰撳墠鎬诲簱瀛�
-                var totalStock = await _db.Queryable<Dt_StockInfo>().CountAsync();
-
-                return WebResponseContent.Instance.OK(null, new
-                {
-                    TodayInbound = todayInbound,
-                    TodayOutbound = todayOutbound,
-                    MonthInbound = monthInbound,
-                    MonthOutbound = monthOutbound,
-                    TotalStock = totalStock
-                });
-            }
-            catch (Exception ex)
-            {
-                return WebResponseContent.Instance.Error($"鎬昏鏁版嵁鑾峰彇澶辫触: {ex.Message}");
-            }
-        }
-
-        /// <summary>
-        /// 姣忔棩缁熻
-        /// </summary>
-        /// <remarks>
-        /// 娉ㄦ剰锛氭暟鎹湪 SQL 灞傝繃婊ゅ悗锛屽湪搴旂敤灞傛寜鏃ユ湡鍒嗙粍銆�
-        /// SqlSugar 鐨� GroupBy 涓嶆敮鎸佸 .Date 杩欐牱鐨勮绠楀垪鐩存帴鐢熸垚 SQL GROUP BY锛�
-        /// 鍥犳閲囩敤姝ゆ柟寮忎互纭繚璺ㄦ暟鎹簱鍏煎鎬с��
-        /// </remarks>
-        [HttpGet("DailyStats"), AllowAnonymous]
-        public async Task<WebResponseContent> DailyStats([FromQuery] int days = 30)
-        {
-            try
-            {
-                if (days <= 0) days = 30;
-                if (days > 365) days = 365;
-
-                var startDate = DateTime.Today.AddDays(-days + 1);
-
-                var query = await _db.Queryable<Dt_Task_Hty>()
-                    .Where(t => t.InsertTime >= startDate)
-                    .Select(t => new { t.InsertTime, t.TaskType })
-                    .ToListAsync();
-
-                var result = query
-                    .GroupBy(t => t.InsertTime.Date)
-                    .Select(g => new
-                    {
-                        Date = g.Key.ToString("yyyy-MM-dd"),
-                        Inbound = g.Count(t => t.TaskType >= 500 && t.TaskType < 600),
-                        Outbound = g.Count(t => t.TaskType >= 100 && t.TaskType < 200)
-                    })
-                    .OrderBy(x => x.Date)
-                    .ToList();
-
-                return WebResponseContent.Instance.OK(null, result);
-            }
-            catch (Exception ex)
-            {
-                return WebResponseContent.Instance.Error($"姣忔棩缁熻鑾峰彇澶辫触: {ex.Message}");
-            }
-        }
-
-        /// <summary>
-        /// 姣忓懆缁熻
-        /// </summary>
-        /// <remarks>
-        /// 娉ㄦ剰锛氭暟鎹湪 SQL 灞傝繃婊ゅ悗锛屽湪搴旂敤灞傛寜 ISO 8601 鍛ㄩ敭鍒嗙粍銆�
-        /// 鍛ㄩ敭涓� "YYYY-Www" 鏍煎紡锛屾棤娉曠洿鎺ュ湪 SQL 灞傜敤 GROUP BY 瀹炵幇銆�
-        /// </remarks>
-        [HttpGet("WeeklyStats"), AllowAnonymous]
-        public async Task<WebResponseContent> WeeklyStats([FromQuery] int weeks = 12)
-        {
-            try
-            {
-                if (weeks <= 0) weeks = 12;
-
-                var startDate = DateTime.Today.AddDays(-weeks * 7);
-
-                var query = await _db.Queryable<Dt_Task_Hty>()
-                    .Where(t => t.InsertTime >= startDate)
-                    .Select(t => new { t.InsertTime, t.TaskType })
-                    .ToListAsync();
-
-                var result = query
-                    .GroupBy(t => GetWeekKey(t.InsertTime))
-                    .Select(g => new
-                    {
-                        Week = g.Key,
-                        Inbound = g.Count(t => t.TaskType >= 500 && t.TaskType < 600),
-                        Outbound = g.Count(t => t.TaskType >= 100 && t.TaskType < 200)
-                    })
-                    .OrderBy(x => x.Week)
-                    .ToList();
-
-                return WebResponseContent.Instance.OK(null, result);
-            }
-            catch (Exception ex)
-            {
-                return WebResponseContent.Instance.Error($"姣忓懆缁熻鑾峰彇澶辫触: {ex.Message}");
-            }
-        }
-
-        private string GetWeekKey(DateTime date)
-        {
-            // 鑾峰彇鍛ㄤ竴寮�濮嬬殑鍛� (ISO 8601)
-            var diff = (7 + (date.DayOfWeek - DayOfWeek.Monday)) % 7;
-            var monday = date.AddDays(-diff);
-            var weekNum = System.Globalization.CultureInfo.InvariantCulture
-                .Calendar.GetWeekOfYear(monday, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
-            return $"{monday.Year}-W{weekNum:D2}";
-        }
-
-        /// <summary>
-        /// 姣忔湀缁熻
-        /// </summary>
-        /// <remarks>
-        /// 娉ㄦ剰锛氭暟鎹湪 SQL 灞傝繃婊ゅ悗锛屽湪搴旂敤灞傛寜骞存湀鍒嗙粍銆�
-        /// SqlSugar 鐨� GroupBy 涓嶆敮鎸佸尶鍚嶅璞� (Year, Month) 鐩存帴鏄犲皠鍒� SQL GROUP BY锛�
-        /// 鍥犳閲囩敤姝ゆ柟寮忎互纭繚璺ㄦ暟鎹簱鍏煎鎬с��
-        /// </remarks>
-        [HttpGet("MonthlyStats"), AllowAnonymous]
-        public async Task<WebResponseContent> MonthlyStats([FromQuery] int months = 12)
-        {
-            try
-            {
-                if (months <= 0) months = 12;
-
-                var startDate = DateTime.Today.AddMonths(-months + 1);
-                startDate = new DateTime(startDate.Year, startDate.Month, 1);
-
-                var query = await _db.Queryable<Dt_Task_Hty>()
-                    .Where(t => t.InsertTime >= startDate)
-                    .Select(t => new { t.InsertTime, t.TaskType })
-                    .ToListAsync();
-
-                var result = query
-                    .GroupBy(t => new { t.InsertTime.Year, t.InsertTime.Month })
-                    .Select(g => new
-                    {
-                        Month = $"{g.Key.Year}-{g.Key.Month:D2}",
-                        Inbound = g.Count(t => t.TaskType >= 500 && t.TaskType < 600),
-                        Outbound = g.Count(t => t.TaskType >= 100 && t.TaskType < 200)
-                    })
-                    .OrderBy(x => x.Month)
-                    .ToList();
-
-                return WebResponseContent.Instance.OK(null, result);
-            }
-            catch (Exception ex)
-            {
-                return WebResponseContent.Instance.Error($"姣忔湀缁熻鑾峰彇澶辫触: {ex.Message}");
-            }
-        }
-
-        /// <summary>
-        /// 搴撳瓨搴撻緞鍒嗗竷
-        /// </summary>
-        [HttpGet("StockAgeDistribution"), AllowAnonymous]
-        public async Task<WebResponseContent> StockAgeDistribution()
-        {
-            try
-            {
-                var today = DateTime.Today;
-
-                // 浣跨敤 SQL 鐩存帴鍒嗙粍缁熻锛岄伩鍏嶅姞杞芥墍鏈夋暟鎹埌鍐呭瓨
-                var result = new[]
-                {
-                    new { Range = "7澶╁唴", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) <= 7).CountAsync() },
-                    new { Range = "7-30澶�", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) > 7 && SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) <= 30).CountAsync() },
-                    new { Range = "30-90澶�", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) > 30 && SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) <= 90).CountAsync() },
-                    new { Range = "90澶╀互涓�", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) > 90).CountAsync() }
-                };
-
-                return WebResponseContent.Instance.OK(null, result);
-            }
-            catch (Exception ex)
-            {
-                return WebResponseContent.Instance.Error($"搴撳瓨搴撻緞鍒嗗竷鑾峰彇澶辫触: {ex.Message}");
-            }
-        }
-
-        /// <summary>
-        /// 鍚勪粨搴撳簱瀛樺垎甯�
-        /// </summary>
-        /// <remarks>
-        /// 浣跨敤 SQL GROUP BY 鍦ㄦ暟鎹簱灞傞潰鑱氬悎锛岄伩鍏嶅姞杞藉叏閮ㄥ簱瀛樿褰曞埌鍐呭瓨銆�
-        /// </remarks>
-        [HttpGet("StockByWarehouse"), AllowAnonymous]
-        public async Task<WebResponseContent> StockByWarehouse()
-        {
-            try
-            {
-                // 鏌ヨ浠撳簱鍚嶇О
-                var warehouses = await _db.Queryable<Dt_Warehouse>()
-                    .Select(w => new { w.WarehouseId, w.WarehouseName })
-                    .ToListAsync();
-                var warehouseDict = warehouses.ToDictionary(w => w.WarehouseId, w => w.WarehouseName);
-
-                // 浣跨敤 SQL GROUP BY 鍦ㄦ暟鎹簱灞傞潰鑱氬悎锛屼粎杩斿洖鑱氬悎缁撴灉
-                var stockGroups = await _db.Queryable<Dt_StockInfo>()
-                    .GroupBy(s => s.WarehouseId)
-                    .Select(s => new { s.WarehouseId, Count = SqlFunc.AggregateCount(s.Id) })
-                    .ToListAsync();
-
-                var result = stockGroups
-                    .Select(g => new
-                    {
-                        Warehouse = warehouseDict.TryGetValue(g.WarehouseId, out var name) ? name : $"浠撳簱{g.WarehouseId}",
-                        Count = g.Count
-                    })
-                    .ToList();
-
-                return WebResponseContent.Instance.OK(null, result);
-            }
-            catch (Exception ex)
-            {
-                return WebResponseContent.Instance.Error($"鍚勪粨搴撳簱瀛樺垎甯冭幏鍙栧け璐�: {ex.Message}");
-            }
-        }
-    }
-}
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
+using WIDESEA_Common.LocationEnum;
+using WIDESEA_Core;
+using WIDESEA_Model.Models;
+
+namespace WIDESEA_WMSServer.Controllers.Dashboard
+{
+    /// <summary>
+    /// 浠〃鐩�
+    /// </summary>
+    [Route("api/Dashboard")]
+    [ApiController]
+    public class DashboardController : ControllerBase
+    {
+        private readonly ISqlSugarClient _db;
+
+        public DashboardController(ISqlSugarClient db)
+        {
+            _db = db;
+        }
+
+        /// <summary>
+        /// 鎬昏鏁版嵁
+        /// </summary>
+        [HttpGet("Overview"), AllowAnonymous]
+        public async Task<WebResponseContent> Overview()
+        {
+            try
+            {
+                var today = DateTime.Today;
+                var firstDayOfMonth = new DateTime(today.Year, today.Month, 1);
+
+                // 浠婃棩鍏ュ簱鏁�
+                var todayInbound = await _db.Queryable<Dt_Task_Hty>()
+                    .Where(t => t.InsertTime >= today && t.TaskType >= 500 && t.TaskType < 600)
+                    .CountAsync();
+
+                // 浠婃棩鍑哄簱鏁�
+                var todayOutbound = await _db.Queryable<Dt_Task_Hty>()
+                    .Where(t => t.InsertTime >= today && t.TaskType >= 100 && t.TaskType < 200)
+                    .CountAsync();
+
+                // 鏈湀鍏ュ簱鏁�
+                var monthInbound = await _db.Queryable<Dt_Task_Hty>()
+                    .Where(t => t.InsertTime >= firstDayOfMonth && t.TaskType >= 500 && t.TaskType < 600)
+                    .CountAsync();
+
+                // 鏈湀鍑哄簱鏁�
+                var monthOutbound = await _db.Queryable<Dt_Task_Hty>()
+                    .Where(t => t.InsertTime >= firstDayOfMonth && t.TaskType >= 100 && t.TaskType < 200)
+                    .CountAsync();
+
+                // 褰撳墠鎬诲簱瀛�
+                var totalStock = await _db.Queryable<Dt_StockInfo>().CountAsync();
+
+                return WebResponseContent.Instance.OK(null, new
+                {
+                    TodayInbound = todayInbound,
+                    TodayOutbound = todayOutbound,
+                    MonthInbound = monthInbound,
+                    MonthOutbound = monthOutbound,
+                    TotalStock = totalStock
+                });
+            }
+            catch (Exception ex)
+            {
+                return WebResponseContent.Instance.Error($"鎬昏鏁版嵁鑾峰彇澶辫触: {ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 姣忔棩缁熻
+        /// </summary>
+        [HttpGet("DailyStats"), AllowAnonymous]
+        public async Task<WebResponseContent> DailyStats([FromQuery] int days = 30)
+        {
+            try
+            {
+                if (days <= 0) days = 30;
+                if (days > 365) days = 365;
+
+                var startDate = DateTime.Today.AddDays(-days + 1);
+                var endDate = DateTime.Today; // 鍖呭惈浠婂ぉ
+
+                var query = await _db.Queryable<Dt_Task_Hty>()
+                    .Where(t => t.InsertTime >= startDate && t.InsertTime <= endDate)
+                    .Select(t => new { t.InsertTime, t.TaskType })
+                    .ToListAsync();
+
+                // 鐢熸垚鏃ユ湡鑼冨洿
+                var allDates = new List<DateTime>();
+                for (var date = startDate; date <= endDate; date = date.AddDays(1))
+                {
+                    allDates.Add(date);
+                }
+
+                // 鎸夋棩鏈熷垎缁勭粺璁�
+                var groupedData = query
+                    .GroupBy(t => t.InsertTime.Date)
+                    .Select(g => new
+                    {
+                        Date = g.Key,
+                        Inbound = g.Count(t => t.TaskType >= 200 && t.TaskType < 300),
+                        Outbound = g.Count(t => t.TaskType >= 100 && t.TaskType < 200)
+                    })
+                    .ToDictionary(x => x.Date, x => x);
+
+                // 琛ュ叏缂哄け鏃ユ湡
+                var result = allDates.Select(date =>
+                {
+                    if (groupedData.TryGetValue(date, out var data))
+                    {
+                        return new
+                        {
+                            Date = date.ToString("MM-dd"),
+                            Inbound = data.Inbound,
+                            Outbound = data.Outbound
+                        };
+                    }
+                    else
+                    {
+                        return new
+                        {
+                            Date = date.ToString("MM-dd"),
+                            Inbound = 0,
+                            Outbound = 0
+                        };
+                    }
+                })
+                .OrderBy(x => x.Date)
+                .ToList();
+
+                return WebResponseContent.Instance.OK(null, result);
+            }
+            catch (Exception ex)
+            {
+                return WebResponseContent.Instance.Error($"姣忔棩缁熻鑾峰彇澶辫触: {ex.Message}");
+            }
+        }
+        /// <summary>
+        /// 姣忓懆缁熻
+        /// </summary>
+        /// <remarks>
+        /// 娉ㄦ剰锛氭暟鎹湪 SQL 灞傝繃婊ゅ悗锛屽湪搴旂敤灞傛寜 ISO 8601 鍛ㄩ敭鍒嗙粍銆�
+        /// 鍛ㄩ敭涓� "YYYY-Www" 鏍煎紡锛屾棤娉曠洿鎺ュ湪 SQL 灞傜敤 GROUP BY 瀹炵幇銆�
+        /// </remarks>
+        [HttpGet("WeeklyStats"), AllowAnonymous]
+        public async Task<WebResponseContent> WeeklyStats([FromQuery] int weeks = 12)
+        {
+            try
+            {
+                if (weeks <= 0) weeks = 12;
+
+                var startDate = DateTime.Today.AddDays(-weeks * 7);
+
+                var query = await _db.Queryable<Dt_Task_Hty>()
+                    .Where(t => t.InsertTime >= startDate)
+                    .Select(t => new { t.InsertTime, t.TaskType })
+                    .ToListAsync();
+
+                var result = query
+                    .GroupBy(t => GetWeekKey(t.InsertTime))
+                    .Select(g => new
+                    {
+                        Week = g.Key,
+                        Inbound = g.Count(t => t.TaskType >= 200 && t.TaskType < 300),
+                        Outbound = g.Count(t => t.TaskType >= 100 && t.TaskType < 200)
+                    })
+                    .OrderBy(x => x.Week)
+                    .ToList();
+
+                return WebResponseContent.Instance.OK(null, result);
+            }
+            catch (Exception ex)
+            {
+                return WebResponseContent.Instance.Error($"姣忓懆缁熻鑾峰彇澶辫触: {ex.Message}");
+            }
+        }
+
+        private string GetWeekKey(DateTime date)
+        {
+            // 鑾峰彇鍛ㄤ竴寮�濮嬬殑鍛� (ISO 8601)
+            var diff = (7 + (date.DayOfWeek - DayOfWeek.Monday)) % 7;
+            var monday = date.AddDays(-diff);
+            var weekNum = System.Globalization.CultureInfo.InvariantCulture
+                .Calendar.GetWeekOfYear(monday, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
+            return $"{monday.Year}-W{weekNum:D2}";
+        }
+
+        /// <summary>
+        /// 姣忔湀缁熻
+        /// </summary>
+        /// <remarks>
+        /// 鎸夊勾鏈堢粺璁″叆绔欏拰鍑虹珯浠诲姟鏁伴噺
+        /// </remarks>
+        [HttpGet("MonthlyStats"), AllowAnonymous]
+        public async Task<WebResponseContent> MonthlyStats([FromQuery] int months = 12)
+        {
+            try
+            {
+                if (months <= 0) months = 12;
+
+                var startDate = DateTime.Today.AddMonths(-months + 1);
+                startDate = new DateTime(startDate.Year, startDate.Month, 1);
+
+                var monthlyStats = await _db.Queryable<Dt_Task_Hty>()
+                    .Where(t => t.InsertTime >= startDate)
+                    .GroupBy(t => new { t.InsertTime.Year, t.InsertTime.Month })
+                    .Select(t => new
+                    {
+                        Year = t.InsertTime.Year,
+                        Month = t.InsertTime.Month,
+                        Inbound = SqlFunc.AggregateSum(
+                            SqlFunc.IIF(t.TaskType >= 200 && t.TaskType < 300, 1, 0)
+                        ),
+                        Outbound = SqlFunc.AggregateSum(
+                            SqlFunc.IIF(t.TaskType >= 100 && t.TaskType < 200, 1, 0)
+                        )
+                    })
+                    .OrderBy(t => t.Year)
+                    .OrderBy(t => t.Month)
+                    .ToListAsync();
+
+                // 鐢熸垚鎵�鏈夐渶瑕佺粺璁$殑鏈堜唤鍒楄〃
+                var allMonths = new List<DateTime>();
+                var currentMonth = startDate;
+                var endMonth = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
+
+                while (currentMonth <= endMonth)
+                {
+                    allMonths.Add(currentMonth);
+                    currentMonth = currentMonth.AddMonths(1);
+                }
+
+                // 灏嗘煡璇㈢粨鏋滆浆鎹负瀛楀吀锛屾柟渚挎煡鎵�
+                var statsDict = monthlyStats.ToDictionary(
+                    s => $"{s.Year}-{s.Month:D2}",
+                    s => new { s.Inbound, s.Outbound }
+                );
+
+                // 鏋勫缓瀹屾暣鐨勭粨鏋滃垪琛紝鍖呭惈鎵�鏈夋湀浠�
+                var result = new List<object>();
+                foreach (var month in allMonths)
+                {
+                    var monthKey = $"{month.Year}-{month.Month:D2}";
+
+                    if (statsDict.TryGetValue(monthKey, out var stat))
+                    {
+                        result.Add(new
+                        {
+                            Month = monthKey,
+                            Inbound = stat.Inbound,
+                            Outbound = stat.Outbound
+                        });
+                    }
+                    else
+                    {
+                        result.Add(new
+                        {
+                            Month = monthKey,
+                            Inbound = 0,
+                            Outbound = 0
+                        });
+                    }
+                }
+
+                return WebResponseContent.Instance.OK(null, result);
+            }
+            catch (Exception ex)
+            {
+                // 璁板綍寮傚父鏃ュ織锛堝疄闄呴」鐩腑寤鸿浣跨敤鏃ュ織妗嗘灦锛�
+                // _logger.LogError(ex, "姣忔湀缁熻鑾峰彇澶辫触");
+
+                return WebResponseContent.Instance.Error($"姣忔湀缁熻鑾峰彇澶辫触: {ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 搴撳瓨搴撻緞鍒嗗竷
+        /// </summary>
+        [HttpGet("StockAgeDistribution"), AllowAnonymous]
+        public async Task<WebResponseContent> StockAgeDistribution()
+        {
+            try
+            {
+                var today = DateTime.Today;
+
+                // 浣跨敤 SQL 鐩存帴鍒嗙粍缁熻锛岄伩鍏嶅姞杞芥墍鏈夋暟鎹埌鍐呭瓨
+                var result = new[]
+                {
+                    new { Range = "7澶╁唴", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) <= 7).CountAsync() },
+                    new { Range = "7-30澶�", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) > 7 && SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) <= 30).CountAsync() },
+                    new { Range = "30-90澶�", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) > 30 && SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) <= 90).CountAsync() },
+                    new { Range = "90澶╀互涓�", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) > 90).CountAsync() }
+                };
+
+                return WebResponseContent.Instance.OK(null, result);
+            }
+            catch (Exception ex)
+            {
+                return WebResponseContent.Instance.Error($"搴撳瓨搴撻緞鍒嗗竷鑾峰彇澶辫触: {ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 鍚勪粨搴撳簱瀛樺垎甯�
+        /// </summary>
+        /// <remarks>
+        /// 浣跨敤 SQL GROUP BY 鍦ㄦ暟鎹簱灞傞潰鑱氬悎锛岄伩鍏嶅姞杞藉叏閮ㄥ簱瀛樿褰曞埌鍐呭瓨銆�
+        /// </remarks>
+        [HttpGet("StockByWarehouse"), AllowAnonymous]
+        public async Task<WebResponseContent> StockByWarehouse()
+        {
+            try
+            {
+                // 鏌ヨ鎵�鏈変粨搴撲俊鎭�
+                var warehouses = await _db.Queryable<Dt_Warehouse>()
+                    .Select(w => new { w.WarehouseId, w.WarehouseName })
+                    .ToListAsync();
+
+                // 鏌ヨ鎵�鏈夎揣浣嶄俊鎭紝鎸変粨搴撳垎缁勭粺璁℃�绘暟
+                var locationGroups = await _db.Queryable<Dt_LocationInfo>()
+                    .GroupBy(l => l.WarehouseId)
+                    .Select(l => new
+                    {
+                        WarehouseId = l.WarehouseId,
+                        TotalLocations = SqlFunc.AggregateCount(l.Id)
+                    })
+                    .ToListAsync();
+
+                // 鏌ヨ鐘舵�佷笉涓篎ree鐨勮揣浣嶄俊鎭紙鏈夎揣璐т綅锛夛紝鎸変粨搴撳垎缁勭粺璁�
+                var occupiedLocationGroups = await _db.Queryable<Dt_LocationInfo>()
+                    .Where(l => l.LocationStatus != (int)LocationStatusEnum.Free)
+                    .GroupBy(l => l.WarehouseId)
+                    .Select(l => new
+                    {
+                        WarehouseId = l.WarehouseId,
+                        OccupiedLocations = SqlFunc.AggregateCount(l.Id)
+                    })
+                    .ToListAsync();
+
+                // 灏嗕粨搴撲俊鎭笌璐т綅缁熻淇℃伅鍚堝苟
+                var result = warehouses.Select(w =>
+                {
+                    var totalLocations = locationGroups.FirstOrDefault(lg => lg.WarehouseId == w.WarehouseId)?.TotalLocations ?? 0;
+                    var occupiedLocations = occupiedLocationGroups.FirstOrDefault(og => og.WarehouseId == w.WarehouseId)?.OccupiedLocations ?? 0;
+                    var emptyLocations = totalLocations - occupiedLocations;
+
+                    var occupiedPercentage = totalLocations > 0 ? Math.Round((double)occupiedLocations / totalLocations * 100, 2) : 0.0;
+                    var emptyPercentage = totalLocations > 0 ? Math.Round((double)emptyLocations / totalLocations * 100, 2) : 0.0;
+
+                    return new
+                    {
+                        Warehouse = w.WarehouseName,
+                        Total = totalLocations,
+                        HasStock = occupiedLocations,
+                        NoStock = emptyLocations,
+                        HasStockPercentage = $"{occupiedPercentage}%",
+                        NoStockPercentage = $"{emptyPercentage}%"
+                    };
+                }).ToList();
+
+                return WebResponseContent.Instance.OK(null, result);
+            }
+            catch (Exception ex)
+            {
+                return WebResponseContent.Instance.Error($"鍚勪粨搴撳簱瀛樺垎甯冭幏鍙栧け璐�: {ex.Message}");
+            }
+        }
+    }
+}

--
Gitblit v1.9.3