From 4c1f6449a2dd28bdfb76dae2bac127c2081f9f54 Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期一, 09 三月 2026 09:22:28 +0800
Subject: [PATCH] 添加多出库口轮询功能设计文档
---
Code/WMS/WIDESEA_WMSServer/docs/plans/2026-03-09-multi-outbound-address-roundrobin-design.md | 323 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 323 insertions(+), 0 deletions(-)
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
new file mode 100644
index 0000000..d0dfc6c
--- /dev/null
+++ b/Code/WMS/WIDESEA_WMSServer/docs/plans/2026-03-09-multi-outbound-address-roundrobin-design.md
@@ -0,0 +1,323 @@
+# 澶氬嚭搴撳彛杞鍔熻兘璁捐鏂囨。
+
+**鏃ユ湡**: 2026-03-09
+**浣滆��**: Claude Code
+**鐘舵��**: 寰呭疄鏂�
+
+## 姒傝堪
+
+鏈璁℃棬鍦ㄦ敼杩涜嚜鍔ㄥ嚭搴撲换鍔$殑鐩爣鍦板潃閰嶇疆鍔熻兘锛屾敮鎸佷竴涓贩閬撻厤缃涓嚭搴撳彛锛屽苟閫氳繃杞绠楁硶瀹炵幇璐熻浇鍧囪 銆�
+
+## 闇�姹傝儗鏅�
+
+褰撳墠绯荤粺涓紝`TargetAddresses` 閰嶇疆閲囩敤涓�瀵逛竴鏄犲皠锛堝贩閬撳墠缂� 鈫� 鍑哄簱鍙e湴鍧�锛夈�備絾瀹為檯涓氬姟涓紝涓�涓贩閬撳彲鑳芥湁澶氫釜鍑哄簱鍙o紝闇�瑕佹敮鎸侊細
+
+1. **涓�瀵瑰鍏崇郴**锛氫竴涓贩閬撳彲浠ラ厤缃涓嚭搴撳彛
+2. **璐熻浇鍧囪 **锛氶�氳繃杞绠楁硶閫夋嫨鍑哄簱鍙o紝閬垮厤鍗曠偣鍘嬪姏
+3. **鍚戝悗鍏煎**锛氫繚鎸佸鍗曞嚭鍙i厤缃殑鏀寔
+
+## 鎶�鏈柟妗�
+
+### 鏋舵瀯閫夋嫨
+
+閲囩敤 **鍐呭瓨杞璁℃暟鍣� + 鐙珛鏈嶅姟绫�** 鐨勬ā寮忥細
+
+1. **RoundRobinService**锛氱嫭绔嬬殑杞鏈嶅姟绫伙紝绠$悊杞璁℃暟鍣�
+2. **閰嶇疆妯″瀷鍙樻洿**锛歚Dictionary<string, string>` 鈫� `Dictionary<string, List<string>>`
+3. **绾跨▼瀹夊叏**锛氫娇鐢� `ConcurrentDictionary` 淇濊瘉澶氱嚎绋嬪畨鍏�
+
+### 鏍稿績璁捐
+
+#### 1. 閰嶇疆鏍煎紡鍙樻洿
+
+**appsettings.json:**
+```json
+{
+ "AutoOutboundTask": {
+ "TargetAddresses": {
+ "GW": ["10081", "10082", "10083"],
+ "CW": ["10080"]
+ }
+ }
+}
+```
+
+**璇存槑锛�**
+- 鍊肩被鍨嬩粠 `string` 鏀逛负 `string[]`锛圝SON 鏁扮粍锛�
+- 鏀寔涓�涓贩閬撻厤缃涓嚭搴撳彛
+- 鍗曚釜鍑哄簱鍙d篃鍙敤鏁扮粍鏍煎紡锛堝彧鏈変竴涓厓绱狅級
+
+#### 2. 閰嶇疆妯″瀷绫�
+
+**AutoOutboundTaskOptions.cs:**
+```csharp
+public class AutoOutboundTaskOptions
+{
+ public bool Enable { get; set; } = true;
+ public int CheckIntervalSeconds { get; set; } = 300;
+
+ public Dictionary<string, List<string>> TargetAddresses { get; set; }
+ = new()
+ {
+ { "GW", new List<string> { "10081" } },
+ { "CW", new List<string> { "10080" } }
+ };
+}
+```
+
+#### 3. 杞鏈嶅姟绫�
+
+**RoundRobinService.cs** (鏂板缓):
+```csharp
+using System.Collections.Concurrent;
+
+namespace WIDESEA_Core.Core
+{
+ /// <summary>
+ /// 杞鏈嶅姟 - 绾跨▼瀹夊叏鐨勫湴鍧�杞閫夋嫨
+ /// </summary>
+ public class RoundRobinService
+ {
+ 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, old) => (old + 1) % addresses.Count // 杞锛氶�掑鍚庡彇妯�
+ );
+
+ return addresses[index];
+ }
+ }
+}
+```
+
+**鍏抽敭鐗规�э細**
+- 浣跨敤 `ConcurrentDictionary<string, int>` 瀛樺偍姣忎釜宸烽亾鐨勫綋鍓嶇储寮�
+- `AddOrUpdate` 鏂规硶淇濊瘉鍘熷瓙鎬э紝鏃犻渶棰濆閿�
+- 妯¤繍绠楀疄鐜板惊鐜疆璇�
+- 绾跨▼瀹夊叏锛屾敮鎸佸悗鍙版湇鍔$殑骞跺彂璋冪敤
+
+#### 4. TaskService 鏂规硶淇敼
+
+**DetermineTargetAddress 鏂规硶:**
+```csharp
+private string DetermineTargetAddress(
+ string roadway,
+ Dictionary<string, List<string>> addressMap)
+{
+ if (string.IsNullOrWhiteSpace(roadway))
+ return "10080";
+
+ // 鏌ユ壘鍖归厤鐨勫贩閬撳墠缂�
+ string matchedPrefix = null;
+ foreach (var kvp in addressMap)
+ {
+ if (roadway.Contains(kvp.Key))
+ {
+ matchedPrefix = kvp.Key;
+ break;
+ }
+ }
+
+ 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);
+}
+```
+
+**渚濊禆娉ㄥ叆:**
+```csharp
+public class TaskService
+{
+ private readonly RoundRobinService _roundRobinService;
+
+ public TaskService(
+ // ... 鍏朵粬渚濊禆
+ RoundRobinService roundRobinService)
+ {
+ // ... 鍏朵粬璧嬪��
+ _roundRobinService = roundRobinService;
+ }
+}
+```
+
+#### 5. 鏈嶅姟娉ㄥ唽
+
+**Program.cs:**
+```csharp
+// 娉ㄥ唽涓哄崟渚嬶紝淇濊瘉鍏ㄥ眬鍏变韩璁℃暟鍣�
+builder.Services.AddSingleton<RoundRobinService>();
+```
+
+## 鏁版嵁娴佺▼
+
+```mermaid
+graph TD
+ A[鍒涘缓鍑哄簱浠诲姟] --> B[鑾峰彇搴撳瓨宸烽亾淇℃伅]
+ B --> C[鏌ユ壘鍖归厤鐨勫贩閬撳墠缂�]
+ C --> D{鍦板潃鍒楄〃鏁伴噺}
+ D -->|0涓獆 E[杩斿洖榛樿鍦板潃 10080]
+ D -->|1涓獆 F[鐩存帴杩斿洖璇ュ湴鍧�]
+ D -->|澶氫釜| G[璋冪敤 RoundRobinService]
+ G --> H[鏌ヨ/鏇存柊璁℃暟鍣╙
+ H --> I[杩斿洖 addresses counter % count]
+ I --> J[鍒涘缓浠诲姟]
+ F --> J
+ E --> J
+```
+
+## 杞绀轰緥
+
+**閰嶇疆:**
+```json
+{
+ "TargetAddresses": {
+ "GW": ["10081", "10082", "10083"]
+ }
+}
+```
+
+**璋冪敤搴忓垪:**
+| 娆℃暟 | 璁℃暟鍣ㄥ�� | 杩斿洖鍦板潃 |
+|------|---------|---------|
+| 1 | 0 | 10081 |
+| 2 | 1 | 10082 |
+| 3 | 2 | 10083 |
+| 4 | 0 | 10081 |
+| 5 | 1 | 10082 |
+| ... | ... | ... |
+
+## 閿欒澶勭悊
+
+1. **閰嶇疆閿欒**锛�
+ - 鍦板潃鍒楄〃涓虹┖ 鈫� 杩斿洖榛樿鍦板潃 "10080"
+ - 宸烽亾涓嶅尮閰嶄换浣曞墠缂� 鈫� 杩斿洖榛樿鍦板潃 "10080"
+
+2. **骞跺彂瀹夊叏**锛�
+ - 浣跨敤 `ConcurrentDictionary` 淇濊瘉绾跨▼瀹夊叏
+ - `AddOrUpdate` 鏄師瀛愭搷浣�
+
+3. **搴旂敤閲嶅惎**锛�
+ - 杞浣嶇疆閲嶇疆涓� 0
+ - 鍙帴鍙楃殑鏉冭 锛堢畝鍖栧疄鐜帮級
+
+## 鍚戝悗鍏煎鎬�
+
+### 鏃ч厤缃牸寮�
+```json
+{
+ "TargetAddresses": {
+ "GW": "10081",
+ "CW": "10080"
+ }
+}
+```
+
+### 鏂伴厤缃牸寮�
+```json
+{
+ "TargetAddresses": {
+ "GW": ["10081"],
+ "CW": ["10080"]
+ }
+}
+```
+
+**鍏煎鎬у鐞嗭細**
+- JSON 閰嶇疆缁戝畾浼氳嚜鍔ㄥ鐞嗕袱绉嶆牸寮�
+- 鍗曚釜瀛楃涓蹭細琚В鏋愪负鍗曞厓绱犳暟缁�
+- 鐜版湁閰嶇疆鏃犻渶淇敼鍗冲彲宸ヤ綔
+
+## 鎬ц兘褰卞搷
+
+1. **鍐呭瓨寮�閿�**锛氭瘡涓贩閬撳墠缂�涓�涓暣鏁拌鏁板櫒锛堢害 50 瀛楄妭锛�
+2. **CPU 寮�閿�**锛氭ā杩愮畻鍜屽瓧鍏告煡鎵撅紝O(1) 澶嶆潅搴�
+3. **绾跨▼瀹夊叏**锛氭棤閿佽璁★紝`ConcurrentDictionary` 浣跨敤浼樺寲鐨勫悓姝ユ満鍒�
+
+## 娴嬭瘯璁″垝
+
+### 鍗曞厓娴嬭瘯
+1. `RoundRobinService.GetNextAddress` 杞閫昏緫
+2. 鍗曚釜鍦板潃鐩存帴杩斿洖
+3. 澶氫釜鍦板潃杞杩斿洖
+4. 骞跺彂璋冪敤娴嬭瘯
+
+### 闆嗘垚娴嬭瘯
+1. 淇敼 appsettings.json 涓哄鍑哄彛閰嶇疆
+2. 鍒涘缓澶氫釜鍑哄簱浠诲姟
+3. 楠岃瘉鐩爣鍦板潃杞鍒嗛厤
+4. 楠岃瘉鏃ュ織璁板綍
+
+### 鎵嬪姩娴嬭瘯
+```sql
+-- 鍑嗗娴嬭瘯鏁版嵁
+UPDATE Dt_StockInfo
+SET OutboundDate = DATEADD(MINUTE, -5, GETDATE())
+WHERE PalletCode IN ('TEST001', 'TEST002', 'TEST003')
+ AND StockStatus = 1;
+```
+
+鍚姩搴旂敤锛岃瀵熸棩蹇楋細
+```
+info: 鍒涘缓浠诲姟 TEST001锛岀洰鏍囧湴鍧�: 10081
+info: 鍒涘缓浠诲姟 TEST002锛岀洰鏍囧湴鍧�: 10082
+info: 鍒涘缓浠诲姟 TEST003锛岀洰鏍囧湴鍧�: 10083
+```
+
+## 閮ㄧ讲娉ㄦ剰浜嬮」
+
+1. **閰嶇疆鏇存柊**锛�
+ - 灏� `TargetAddresses` 鐨勫�间粠瀛楃涓叉敼涓烘暟缁勬牸寮�
+ - 纭繚姣忎釜鏁扮粍鑷冲皯鏈変竴涓厓绱�
+
+2. **渚濊禆娉ㄥ叆**锛�
+ - 纭繚 `RoundRobinService` 宸叉敞鍐屼负鍗曚緥
+ - `TaskService` 鏋勯�犲嚱鏁伴渶瑕佹敞鍏ヨ鏈嶅姟
+
+3. **鍥炴粴鏂规**锛�
+ - 淇濈暀 `appsettings.json` 澶囦唤
+ - 濡傞亣闂鍙仮澶嶄负鍗曞嚭鍙i厤缃�
+
+## 鏈潵鏀硅繘
+
+1. **鏉冮噸杞**锛氭敮鎸佷负姣忎釜鍦板潃閰嶇疆鏉冮噸
+2. **鍋ュ悍妫�鏌�**锛氭帓闄や笉鍙敤鐨勫嚭搴撳彛
+3. **鎸佷箙鍖�**锛氬皢杞浣嶇疆淇濆瓨鍒� Redis/鏁版嵁搴�
+4. **鐩戞帶缁熻**锛氳褰曟瘡涓湴鍧�鐨勪换鍔″垎閰嶆暟閲�
+
+## 瀹炴柦娓呭崟
+
+- [ ] 淇敼 `AutoOutboundTaskOptions.TargetAddresses` 绫诲瀷
+- [ ] 鍒涘缓 `RoundRobinService` 绫�
+- [ ] 淇敼 `TaskService.DetermineTargetAddress` 鏂规硶
+- [ ] 鍦� `Program.cs` 娉ㄥ唽 `RoundRobinService`
+- [ ] 鏇存柊 `appsettings.json` 閰嶇疆绀轰緥
+- [ ] 缂栬瘧楠岃瘉
+- [ ] 鎵嬪姩娴嬭瘯
+- [ ] 鏇存柊璁捐鏂囨。
--
Gitblit v1.9.3