From 2df3b287a5c868f987b99ff00dc1d2339747b8f1 Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期一, 09 三月 2026 09:48:13 +0800
Subject: [PATCH] Merge branch 'feature/multi-outbound-address-roundrobin' - 实现多出库口轮询功能
---
Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/Core/AutoOutboundTaskOptions.cs | 8 +-
Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/Core/RoundRobinService.cs | 42 ++++++++++
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs | 37 +++++++--
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Program.cs | 1
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json | 80 ++++++++++----------
Code/WMS/WIDESEA_WMSServer/docs/plans/2026-03-09-multi-outbound-address-roundrobin-design.md | 20 +++--
6 files changed, 128 insertions(+), 60 deletions(-)
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/Core/AutoOutboundTaskOptions.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/Core/AutoOutboundTaskOptions.cs
index 3822f2e..a619a6a 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/Core/AutoOutboundTaskOptions.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/Core/AutoOutboundTaskOptions.cs
@@ -18,13 +18,13 @@
public int CheckIntervalSeconds { get; set; } = 300;
/// <summary>
- /// 鎸夊贩閬撳墠缂�閰嶇疆鐩爣鍦板潃
+ /// 鎸夊贩閬撳墠缂�閰嶇疆鐩爣鍦板潃锛堟敮鎸佸鍑哄簱鍙o級
/// </summary>
- public Dictionary<string, string> TargetAddresses { get; set; }
+ public Dictionary<string, List<string>> TargetAddresses { get; set; }
= new()
{
- { "GW", "10081" },
- { "CW", "10080" }
+ { "GW", new List<string> { "10081" } },
+ { "CW", new List<string> { "10080" } }
};
}
}
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/Core/RoundRobinService.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/Core/RoundRobinService.cs
new file mode 100644
index 0000000..24d8c58
--- /dev/null
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/Core/RoundRobinService.cs
@@ -0,0 +1,42 @@
+using System.Collections.Concurrent;
+
+namespace WIDESEA_Core.Core
+{
+ /// <summary>
+ /// 杞鏈嶅姟 - 绾跨▼瀹夊叏鐨勫湴鍧�杞閫夋嫨
+ /// </summary>
+ public class RoundRobinService
+ {
+ /// <summary>
+ /// 杞璁℃暟鍣� - key: 宸烽亾鍓嶇紑, value: 褰撳墠绱㈠紩
+ /// </summary>
+ private readonly ConcurrentDictionary<string, int> _counters = new();
+
+ /// <summary>
+ /// 鑾峰彇涓嬩竴涓湴鍧�锛堣疆璇級
+ /// </summary>
+ /// <param name="key">宸烽亾鍓嶇紑鏍囪瘑</param>
+ /// <param name="addresses">鍊欓�夊湴鍧�鍒楄〃</param>
+ /// <returns>閫変腑鐨勭洰鏍囧湴鍧�</returns>
+ public string GetNextAddress(string key, List<string> addresses)
+ {
+ // 绌哄垪琛ㄦ鏌�
+ if (addresses == null || addresses.Count == 0)
+ return "10080";
+
+ // 鍗曚釜鍦板潃锛岀洿鎺ヨ繑鍥�
+ if (addresses.Count == 1)
+ return addresses[0];
+
+ // 澶氫釜鍦板潃锛屼娇鐢ㄨ疆璇㈤�夋嫨
+ // AddOrUpdate 鏄師瀛愭搷浣滐紝绾跨▼瀹夊叏
+ int index = _counters.AddOrUpdate(
+ key,
+ 0, // 棣栨浣跨敤锛屼粠 0 寮�濮�
+ (k, oldValue) => (oldValue + 1) % addresses.Count // 杞锛氶�掑鍚庡彇妯�
+ );
+
+ return addresses[index];
+ }
+ }
+}
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
index 4b23b23..d49b8e8 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -8,6 +8,7 @@
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
+using WIDESEA_Core.Core;
using WIDESEA_DTO;
using WIDESEA_DTO.Task;
using WIDESEA_IBasicService;
@@ -24,6 +25,7 @@
private readonly ILocationInfoService _locationInfoService;
private readonly HttpClientHelper _httpClientHelper;
private readonly IConfiguration _configuration;
+ private readonly RoundRobinService _roundRobinService;
public IRepository<Dt_Task> Repository => BaseDal;
@@ -42,13 +44,15 @@
IStockInfoService stockInfoService,
ILocationInfoService locationInfoService,
HttpClientHelper httpClientHelper,
- IConfiguration configuration) : base(BaseDal)
+ IConfiguration configuration,
+ RoundRobinService roundRobinService) : base(BaseDal)
{
_mapper = mapper;
_stockInfoService = stockInfoService;
_locationInfoService = locationInfoService;
_httpClientHelper = httpClientHelper;
_configuration = configuration;
+ _roundRobinService = roundRobinService;
}
#region WCS閫昏緫澶勭悊
@@ -381,20 +385,37 @@
}
/// <summary>
- /// 鏍规嵁宸烽亾纭畾鐩爣鍦板潃
+ /// 鏍规嵁宸烽亾纭畾鐩爣鍦板潃锛堟敮鎸佸鍑哄簱鍙h疆璇級
/// </summary>
- private string DetermineTargetAddress(string roadway, Dictionary<string, string> addressMap)
+ private string DetermineTargetAddress(string roadway, Dictionary<string, List<string>> addressMap)
{
if (string.IsNullOrWhiteSpace(roadway))
- return "10080"; // 榛樿鍦板潃
+ return "10080";
+ // 鏌ユ壘鍖归厤鐨勫贩閬撳墠缂�
+ string matchedPrefix = null;
foreach (var kvp in addressMap)
{
if (roadway.Contains(kvp.Key))
- return kvp.Value;
+ {
+ matchedPrefix = kvp.Key;
+ break;
+ }
}
- return "10080"; // 榛樿鍦板潃
+ if (matchedPrefix == null)
+ return "10080";
+
+ var addresses = addressMap[matchedPrefix];
+ if (addresses == null || addresses.Count == 0)
+ return "10080";
+
+ // 鍗曚釜鍦板潃锛岀洿鎺ヨ繑鍥�
+ if (addresses.Count == 1)
+ return addresses[0];
+
+ // 澶氫釜鍦板潃锛屼娇鐢ㄨ疆璇㈡湇鍔�
+ return _roundRobinService.GetNextAddress(matchedPrefix, addresses);
}
/// <summary>
@@ -473,8 +494,8 @@
// 4. 鑾峰彇閰嶇疆鐨勭洰鏍囧湴鍧�鏄犲皠
var targetAddressMap = _configuration.GetSection("AutoOutboundTask:TargetAddresses")
- .Get<Dictionary<string, string>>()
- ?? new Dictionary<string, string>();
+ .Get<Dictionary<string, List<string>>>()
+ ?? new Dictionary<string, List<string>>();
// 5. 鎵归噺鍒涘缓浠诲姟
var taskList = new List<Dt_Task>();
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Program.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Program.cs
index 32e4349..815fd7b 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Program.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Program.cs
@@ -42,6 +42,7 @@
// 2锟斤拷锟斤拷锟矫凤拷锟斤拷
builder.Services.AddSingleton(new AppSettings(builder.Configuration));//注锟斤拷
builder.Services.AddAllOptionRegister();//锟斤拷取锟斤拷锟斤拷锟侥硷拷
+builder.Services.AddSingleton<RoundRobinService>();
builder.Services.Configure<AutoOutboundTaskOptions>(
builder.Configuration.GetSection("AutoOutboundTask"));
builder.Services.AddMemoryCacheSetup();//锟斤拷锟斤拷
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json b/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json
index db224ba..e334059 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json
@@ -1,42 +1,42 @@
{
- "urls": "http://*:9291", //web鏈嶅姟绔彛锛屽鏋滅敤IIS閮ㄧ讲锛屾妸杩欎釜鍘绘帀
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft.AspNetCore": "Warning"
+ "urls": "http://*:9291", //web鏈嶅姟绔彛锛屽鏋滅敤IIS閮ㄧ讲锛屾妸杩欎釜鍘绘帀
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "dics": "inOrderType,outOrderType,inboundState,createType,enableEnum,enableStatusEnum,locationStatusEnum,locationTypeEnum,taskTypeEnum,taskStatusEnum,outboundStatusEnum,orderDetailStatusEnum,stockStatusEmun,stockChangeType,outStockStatus,receiveOrderTypeEnum,authorityScope,authorityScopes,locationChangeType,warehouses,suppliers,taskType,receiveStatus,purchaseType,purchaseOrderStatus,printStatus",
+ "AllowedHosts": "*",
+ "ConnectionStringsEncryption": false,
+ "MainDB": "DB_WIDESEA", //褰撳墠椤圭洰鐨勪富搴擄紝鎵�瀵瑰簲鐨勮繛鎺ュ瓧绗︿覆鐨凟nabled蹇呴』涓簍rue
+ //杩炴帴瀛楃涓�
+ //"ConnectionString": "HTI6FB1H05Krd07mNm9yBCNhofW6edA5zLs9TY~MNthRYW3kn0qKbMIsGp~3yyPDF1YZUCPBQx8U0Jfk4PH~ajNFXVIwlH85M3F~v_qKYQ3CeAz3q1mLVDn8O5uWt1~3Ut2V3KRkEwYHvW2oMDN~QIDXPxDgXN0R2oTIhc9dNu7QNaLEknblqmHhjaNSSpERdDVZIgHnMKejU_SL49tralBkZmDNi0hmkbL~837j1NWe37u9fJKmv91QPb~16JsuI9uu0EvNZ06g6PuZfOSAeFH9GMMIZiketdcJG3tHelo=",
+ "ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
+ //"ConnectionString": "Data Source=10.30.4.92;Initial Catalog=WMS_TC;User ID=sa;Password=duo123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
+ //鏃MS鏁版嵁搴撹繛鎺�
+ //"TeConnectionString": "Data Source=10.30.4.92;Initial Catalog=TeChuang;User ID=sa;Password=duo123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
+ //璺ㄥ煙
+ "Cors": {
+ "PolicyName": "CorsIpAccess", //绛栫暐鍚嶇О
+ "EnableAllIPs": true, //褰撲负true鏃讹紝寮�鏀炬墍鏈塈P鍧囧彲璁块棶銆�
+ // 鏀寔澶氫釜鍩熷悕绔彛锛屾敞鎰忕鍙e彿鍚庝笉瑕佸甫/鏂滄潌锛氭瘮濡俵ocalhost:8000/锛屾槸閿欑殑
+ // 娉ㄦ剰锛宧ttp://127.0.0.1:1818 鍜� http://localhost:1818 鏄笉涓�鏍风殑
+ "IPs": "http://127.0.0.1:8080,http://localhost:8080,http://127.0.0.1:8081,http://localhost:8081"
+ },
+ "LogAopEnable": false,
+ "PrintSql": false, //鎵撳嵃SQL璇彞
+ "ApiName": "WIDESEA",
+ "ExpMinutes": 120,
+ "DBSeedEnable": false,
+ "PDAVersion": "4",
+ "WebSocketPort": 9296,
+ "AutoOutboundTask": {
+ "Enable": true, /// 鏄惁鍚敤鑷姩鍑哄簱浠诲姟
+ "CheckIntervalSeconds": 300, /// 妫�鏌ラ棿闅旓紙绉掞級
+ "TargetAddresses": { /// 鎸夊贩閬撳墠缂�閰嶇疆鐩爣鍦板潃锛堟敮鎸佸鍑哄簱鍙o級
+ "GW": ["10081"],
+ "CW": ["10080"]
+ }
}
- },
- "dics": "inOrderType,outOrderType,inboundState,createType,enableEnum,enableStatusEnum,locationStatusEnum,locationTypeEnum,taskTypeEnum,taskStatusEnum,outboundStatusEnum,orderDetailStatusEnum,stockStatusEmun,stockChangeType,outStockStatus,receiveOrderTypeEnum,authorityScope,authorityScopes,locationChangeType,warehouses,suppliers,taskType,receiveStatus,purchaseType,purchaseOrderStatus,printStatus",
- "AllowedHosts": "*",
- "ConnectionStringsEncryption": false,
- "MainDB": "DB_WIDESEA", //褰撳墠椤圭洰鐨勪富搴擄紝鎵�瀵瑰簲鐨勮繛鎺ュ瓧绗︿覆鐨凟nabled蹇呴』涓簍rue
- //杩炴帴瀛楃涓�
- //"ConnectionString": "HTI6FB1H05Krd07mNm9yBCNhofW6edA5zLs9TY~MNthRYW3kn0qKbMIsGp~3yyPDF1YZUCPBQx8U0Jfk4PH~ajNFXVIwlH85M3F~v_qKYQ3CeAz3q1mLVDn8O5uWt1~3Ut2V3KRkEwYHvW2oMDN~QIDXPxDgXN0R2oTIhc9dNu7QNaLEknblqmHhjaNSSpERdDVZIgHnMKejU_SL49tralBkZmDNi0hmkbL~837j1NWe37u9fJKmv91QPb~16JsuI9uu0EvNZ06g6PuZfOSAeFH9GMMIZiketdcJG3tHelo=",
- "ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
- //"ConnectionString": "Data Source=10.30.4.92;Initial Catalog=WMS_TC;User ID=sa;Password=duo123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
- //鏃MS鏁版嵁搴撹繛鎺�
- //"TeConnectionString": "Data Source=10.30.4.92;Initial Catalog=TeChuang;User ID=sa;Password=duo123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
- //璺ㄥ煙
- "Cors": {
- "PolicyName": "CorsIpAccess", //绛栫暐鍚嶇О
- "EnableAllIPs": true, //褰撲负true鏃讹紝寮�鏀炬墍鏈塈P鍧囧彲璁块棶銆�
- // 鏀寔澶氫釜鍩熷悕绔彛锛屾敞鎰忕鍙e彿鍚庝笉瑕佸甫/鏂滄潌锛氭瘮濡俵ocalhost:8000/锛屾槸閿欑殑
- // 娉ㄦ剰锛宧ttp://127.0.0.1:1818 鍜� http://localhost:1818 鏄笉涓�鏍风殑
- "IPs": "http://127.0.0.1:8080,http://localhost:8080,http://127.0.0.1:8081,http://localhost:8081"
- },
- "LogAopEnable": false,
- "PrintSql": false, //鎵撳嵃SQL璇彞
- "ApiName": "WIDESEA",
- "ExpMinutes": 120,
- "DBSeedEnable": false,
- "PDAVersion": "4",
- "WebSocketPort": 9296,
- "AutoOutboundTask": {
- "Enable": true, /// 鏄惁鍚敤鑷姩鍑哄簱浠诲姟
- "CheckIntervalSeconds": 300, /// 妫�鏌ラ棿闅旓紙绉掞級
- "TargetAddresses": { /// 鎸夊贩閬撳墠缂�閰嶇疆鐩爣鍦板潃
- "GW": "10081",
- "CW": "10080"
- }
- }
-}
\ No newline at end of file
+}
diff --git a/Code/WMS/WIDESEA_WMSServer/docs/plans/2026-03-09-multi-outbound-address-roundrobin-design.md b/Code/WMS/WIDESEA_WMSServer/docs/plans/2026-03-09-multi-outbound-address-roundrobin-design.md
index d0dfc6c..0e6e2af 100644
--- a/Code/WMS/WIDESEA_WMSServer/docs/plans/2026-03-09-multi-outbound-address-roundrobin-design.md
+++ b/Code/WMS/WIDESEA_WMSServer/docs/plans/2026-03-09-multi-outbound-address-roundrobin-design.md
@@ -313,11 +313,15 @@
## 瀹炴柦娓呭崟
-- [ ] 淇敼 `AutoOutboundTaskOptions.TargetAddresses` 绫诲瀷
-- [ ] 鍒涘缓 `RoundRobinService` 绫�
-- [ ] 淇敼 `TaskService.DetermineTargetAddress` 鏂规硶
-- [ ] 鍦� `Program.cs` 娉ㄥ唽 `RoundRobinService`
-- [ ] 鏇存柊 `appsettings.json` 閰嶇疆绀轰緥
-- [ ] 缂栬瘧楠岃瘉
-- [ ] 鎵嬪姩娴嬭瘯
-- [ ] 鏇存柊璁捐鏂囨。
+- [x] 淇敼 `AutoOutboundTaskOptions.TargetAddresses` 绫诲瀷
+- [x] 鍒涘缓 `RoundRobinService` 绫�
+- [x] 淇敼 `TaskService.DetermineTargetAddress` 鏂规硶
+- [x] 鍦� `Program.cs` 娉ㄥ唽 `RoundRobinService`
+- [x] 鏇存柊 `appsettings.json` 閰嶇疆绀轰緥
+- [x] 缂栬瘧楠岃瘉
+- [ ] 鎵嬪姩娴嬭瘯锛堥渶瑕佽繍琛岀幆澧冨拰鏁版嵁搴擄級
+- [x] 鏇存柊璁捐鏂囨。
+
+**瀹炴柦鏃ユ湡**: 2026-03-09
+**瀹炴柦浜�**: Claude Code
+**鐘舵��**: 浠g爜瀹炵幇瀹屾垚锛屽緟鎵嬪姩娴嬭瘯
--
Gitblit v1.9.3