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