From fcdbb4d6cc8eb3629b871a4945ff2da599d64107 Mon Sep 17 00:00:00 2001
From: pan <antony1029@163.com>
Date: 星期六, 29 十一月 2025 17:51:43 +0800
Subject: [PATCH] 提交

---
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutboundBatchPickingService.cs                 |   12 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/OutboundBatchPickingController.cs |  198 +++++
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_Outbound.cs                          |   19 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/OutLockStockStatusEnum.cs                       |    5 
 项目代码/WIDESEA_WMSClient/src/extension/outbound/extend/outOrderDetail.vue                                 |    8 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/OutboundOrderGetDTO.cs                              |   45 +
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs                 |   12 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/BatchOutBoundDto.cs                                 |  169 ++++
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundBatchPickingService.cs                   |  777 +++++++++++++++++++-
 项目代码/WIDESEA_WMSClient/src/views/outbound/BatchPickingConfirm.vue                                       |  958 +++++++++++++++---------
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Common/CommonEnum/PalletTypeEnum.cs                              |   14 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_PickingRecord.cs                        |   24 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/Task/WMSTaskDTO.cs                                           |   11 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Common/OrderEnum/OutboundOrderEnum.cs                            |    2 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs                                 |    2 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs                                   |    3 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/StockStatusEmun.cs                              |    8 
 17 files changed, 1,825 insertions(+), 442 deletions(-)

diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/extension/outbound/extend/outOrderDetail.vue" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/extension/outbound/extend/outOrderDetail.vue"
index 07bb89d..d796938 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/extension/outbound/extend/outOrderDetail.vue"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/extension/outbound/extend/outOrderDetail.vue"
@@ -642,18 +642,18 @@
             } catch (err) {
               return;
             }
-
+console.log(this.selection);
             // 4. 鏋勯�犺姹傚弬鏁帮紙鏂板灏忔暟瀛楁锛�
             const keys = this.selection.map((item) => item.id);
             const requestParams = {
-              taskIds: keys,
+              orderDetailId: keys[0], // 鍒嗘壒鍑哄簱浠呮敮鎸佸崟鏉℃槑缁�
               outboundPlatform: formData.selectedPlatform, // 鍑哄簱绔欏彴
-              outboundDecimal: formData.outboundDecimal // 鏂板锛氬皬鏁板瓧娈典紶缁欏悗绔�
+              batchQuantity: formData.outboundDecimal // 鏂板锛氬皬鏁板瓧娈典紶缁欏悗绔�
             };
 
             // 5. 璋冪敤鍑哄簱鎺ュ彛
             this.http
-              .post("api/Task/ ", requestParams, "鏁版嵁澶勭悊涓�")
+              .post("api/Task/GenerateOutboundBatchTasks", requestParams, "鏁版嵁澶勭悊涓�")
               .then((x) => {
                 if (!x.status) return ElMessage.error(x.message);
                 
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/outbound/BatchPickingConfirm.vue" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/outbound/BatchPickingConfirm.vue"
index 243b5dc..4487276 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/outbound/BatchPickingConfirm.vue"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/outbound/BatchPickingConfirm.vue"
@@ -4,29 +4,8 @@
       <el-page-header @back="goBack">
         <template #content>
           <span class="title">鍑哄簱鎷i�夌‘璁� - {{ this.$route.query.orderNo }}</span>
-          <el-tag v-if="currentBatchNo" type="success" style="margin-left: 10px;">
-            褰撳墠鎵规: {{ currentBatchNo }}
-          </el-tag>
         </template>
       </el-page-header>
-    </div>
-
-    <!-- 鎵规鎿嶄綔鍖哄煙 -->
-    <div class="batch-operations">
-      <el-card>
-        <div class="batch-actions">
-          <el-button type="primary" @click="openBatchAllocateDialog">鍒嗘壒鍒嗛厤</el-button>
-          <el-select v-model="selectedBatchNo" placeholder="閫夋嫨鎵规" @change="onBatchChange" style="width: 200px; margin-left: 10px;">
-            <el-option
-              v-for="batch in batchList"
-              :key="batch.batchNo"
-              :label="`${batch.batchNo} (${batch.batchStatusText})`"
-              :value="batch.batchNo">
-            </el-option>
-          </el-select>
-          <el-button type="info" @click="refreshBatchList">鍒锋柊鎵规</el-button>
-        </div>
-      </el-card>
     </div>
 
     <!-- 鎵爜鍖哄煙 -->
@@ -52,21 +31,6 @@
           <el-button type="info" @click="openRevertSplitDialog">鎾ら攢鎷嗗寘</el-button>
           <el-button type="info" @click="handleEmptyPallet">鍙栫┖绠�</el-button>
           <el-button type="primary" @click="openBatchReturnDialog">鍥炲簱</el-button>
-        </div>
-      </el-card>
-    </div>
-
-    <!-- 鎵规姹囨�讳俊鎭� -->
-    <div class="batch-summary-area" v-if="currentBatchNo">
-      <el-card>
-        <div class="batch-summary-info">
-          <el-tag type="info">鎵规鍙�: {{ batchSummary.batchNo }}</el-tag>
-          <el-tag :type="getBatchStatusType(batchSummary.batchStatus)">
-            {{ batchSummary.batchStatusText }}
-          </el-tag>
-          <el-tag type="warning">鍒嗛厤鏁伴噺: {{ batchSummary.batchQuantity }}</el-tag>
-          <el-tag type="success">瀹屾垚鏁伴噺: {{ batchSummary.completedQuantity }}</el-tag>
-          <el-tag type="danger">鍓╀綑鏁伴噺: {{ batchSummary.remainingQuantity }}</el-tag>
         </div>
       </el-card>
     </div>
@@ -127,52 +91,6 @@
       </el-row>
     </div>
 
-    <!-- 鍒嗘壒鍒嗛厤寮圭獥 -->
-    <div v-if="showBatchAllocateDialog" class="custom-dialog-overlay">
-      <div class="custom-dialog-wrapper">
-        <div class="custom-dialog">
-          <div class="custom-dialog-header">
-            <h3>鍒嗘壒鍒嗛厤搴撳瓨</h3>
-            <el-button type="text" @click="closeBatchAllocateDialog" class="close-button">脳</el-button>
-          </div>
-          <div class="custom-dialog-body">
-            <el-form :model="batchAllocateForm" :rules="batchAllocateFormRules" ref="batchAllocateFormRef" label-width="100px">
-              <el-form-item label="璁㈠崟缂栧彿">
-                <el-input v-model="batchAllocateForm.orderNo" disabled></el-input>
-              </el-form-item>
-              <el-form-item label="鐗╂枡鏄庣粏" prop="orderDetailId">
-                <el-select v-model="batchAllocateForm.orderDetailId" placeholder="閫夋嫨鐗╂枡鏄庣粏" style="width: 100%">
-                  <el-option
-                    v-for="detail in allocatableDetails"
-                    :key="detail.id"
-                    :label="`${detail.materielCode} - 闇�姹�:${detail.needOutQuantity} 宸插垎閰�:${detail.allocatedQuantity} 鍙垎閰�:${detail.availableQuantity}`"
-                    :value="detail.id">
-                  </el-option>
-                </el-select>
-              </el-form-item>
-              <el-form-item label="鍒嗛厤鏁伴噺" prop="batchQuantity">
-                <el-input-number 
-                  v-model="batchAllocateForm.batchQuantity" 
-                  :min="0.01" 
-                  :precision="2"
-                  :step="1"
-                  style="width: 100%"
-                  placeholder="杈撳叆鍒嗛厤鏁伴噺">
-                </el-input-number>
-              </el-form-item>
-              <el-form-item label="鍙垎閰嶆暟閲�">
-                <el-input :value="getAvailableQuantity()" disabled></el-input>
-              </el-form-item>
-            </el-form>
-          </div>
-          <div class="custom-dialog-footer">
-            <el-button @click="closeBatchAllocateDialog">鍙栨秷</el-button>
-            <el-button type="primary" @click="handleBatchAllocate" :loading="batchAllocateLoading">纭鍒嗛厤</el-button>
-          </div>
-        </div>
-      </div>
-    </div>
-
     <!-- 鎷嗗寘寮圭獥 -->
     <div v-if="showCustomSplitDialog" class="custom-dialog-overlay">
       <div class="custom-dialog-wrapper">
@@ -186,20 +104,28 @@
               <el-form-item label="璁㈠崟缂栧彿">
                 <el-input v-model="splitForm.orderNo" disabled></el-input>
               </el-form-item>
-              <el-form-item label="鎵规缂栧彿">
-                <el-input v-model="splitForm.batchNo" disabled></el-input>
-              </el-form-item>
               <el-form-item label="鎵樼洏缂栧彿">
                 <el-input v-model="splitForm.palletCode" disabled></el-input>
               </el-form-item>
               <el-form-item label="鍘熸潯鐮�" prop="originalBarcode">
-                <el-input 
-                  v-model="splitForm.originalBarcode" 
-                  placeholder="鎵弿鍘熸潯鐮�"
-                  @keyup.enter.native="onSplitBarcodeScan"
-                  @change="onSplitBarcodeScan"
-                  clearable>
-                </el-input>
+                <div style="display: flex; align-items: center; gap: 10px;">
+                  <el-input 
+                    v-model="splitForm.originalBarcode" 
+                    placeholder="鎵弿鍘熸潯鐮�"
+                    @keyup.enter.native="onSplitBarcodeScan"
+                    @change="onSplitBarcodeScan"
+                    clearable
+                    style="flex: 1;">
+                  </el-input>
+                  <!-- 鏂板锛氭煡鐪嬫媶鍖呴摼鎸夐挳 -->
+                  <el-button 
+  type="primary" 
+  @click="viewSplitChainFromSplit(splitForm.originalBarcode)" 
+  :disabled="!splitForm.originalBarcode"
+  :loading="splitChainLoading">
+  鏌ョ湅鎷嗗寘閾�
+</el-button>
+                </div>
               </el-form-item>
               <el-form-item label="鐗╂枡缂栫爜">
                 <el-input v-model="splitForm.materielCode" disabled></el-input>
@@ -238,15 +164,46 @@
           <div class="custom-dialog-body">
             <el-form :model="revertSplitForm" :rules="revertSplitFormRules" ref="revertSplitFormRef" label-width="100px">
               <el-form-item label="鏂版潯鐮�" prop="newBarcode">
-                <el-input 
-                  v-model="revertSplitForm.newBarcode" 
-                  placeholder="鎵弿鏂版潯鐮�"
-                  @keyup.enter.native="onRevertSplitBarcodeScan"
-                  @change="onRevertSplitBarcodeScan"
-                  clearable>
-                </el-input>
+                <div style="display: flex; align-items: center; gap: 10px;">
+                  <el-input 
+                    v-model="revertSplitForm.newBarcode" 
+                    placeholder="鎵弿鏂版潯鐮�"
+                    @keyup.enter.native="onRevertSplitBarcodeScan"
+                    @change="onRevertSplitBarcodeScan"
+                    clearable
+                    style="flex: 1;">
+                  </el-input>
+                  <!-- 鏂板锛氭煡鐪嬫媶鍖呴摼鎸夐挳 -->
+                  <el-button 
+                    type="primary" 
+                    @click="viewSplitChain(revertSplitForm.newBarcode)" 
+                    :disabled="!revertSplitForm.newBarcode">
+                    鏌ョ湅鎷嗗寘閾�
+                  </el-button>
+                </div>
               </el-form-item>
             </el-form>
+            
+            <!-- 鏂板锛氭媶鍖呴摼绠�瑕佷俊鎭樉绀� -->
+            <div v-if="splitChainInfo.splitChain && splitChainInfo.splitChain.length > 0" 
+                 style="margin-top: 15px; padding: 10px; background: #f0f9ff; border-radius: 4px;">
+              <div style="font-size: 14px; color: #606266;">
+                <div>鎷嗗寘閾句俊鎭�: 鍏� {{ splitChainInfo.totalSplitTimes }} 娆℃媶鍖�</div>
+                <div style="margin-top: 5px;">
+                  <el-tag 
+                    v-for="item in splitChainInfo.splitChain.slice(0, 3)" 
+                    :key="item.newBarcode"
+                    :type="item.isReverted ? 'success' : 'primary'"
+                    size="small"
+                    style="margin-right: 5px;">
+                    {{ item.newBarcode }} ({{ item.splitQuantity }})
+                  </el-tag>
+                  <span v-if="splitChainInfo.splitChain.length > 3" style="color: #909399;">
+                    绛� {{ splitChainInfo.splitChain.length }} 涓潯鐮�
+                  </span>
+                </div>
+              </div>
+            </div>
           </div>
           <div class="custom-dialog-footer">
             <el-button @click="closeRevertSplitDialog">鍙栨秷</el-button>
@@ -256,12 +213,136 @@
       </div>
     </div>
 
+    <!-- 鎷嗗寘閾句俊鎭脊绐� -->
+<div v-if="showSplitChainDialog" class="custom-dialog-overlay">
+  <div class="custom-dialog-wrapper">
+    <div class="custom-dialog" style="width: 750px;">
+      <div class="custom-dialog-header">
+        <h3>鎷嗗寘閾句俊鎭�</h3>
+        <el-button type="text" @click="closeSplitChainDialog" class="close-button">脳</el-button>
+      </div>
+      <div class="custom-dialog-body">
+        <!-- 鏂板锛氭媶鍖呴摼璇存槑 -->
+        <div style="margin-bottom: 15px; padding: 10px; background: #f0f9ff; border-radius: 4px;">
+          <div style="display: flex; justify-content: space-between; align-items: center;">
+            <div>
+              <div style="font-weight: bold; color: #303133;">鎷嗗寘閾捐鏄�</div>
+              <div style="font-size: 12px; color: #606266; margin-top: 5px;">
+                褰撳墠鏄剧ず鐨勬槸浠� <el-tag type="primary" size="small">{{ splitChainInfo.originalBarcode }}</el-tag> 寮�濮嬬殑鎷嗗寘閾�
+                <br>鍏� {{ splitChainInfo.totalSplitTimes }} 娆℃媶鍖呮搷浣滐紝娑夊強 {{ splitChainInfo.splitChain.length }} 涓潯鐮�
+              </div>
+            </div>
+            <el-button 
+              type="primary" 
+              size="small" 
+              @click="findRootChain(splitChainInfo.originalBarcode)"
+              v-if="splitChainInfo.chainType !== 'root'">
+              鏌ユ壘瀹屾暣鎷嗗寘閾�
+            </el-button>
+          </div>
+        </div>
+        
+        <div style="margin-bottom: 15px;">
+          <el-tag type="info">鎬绘媶鍖呮鏁�: {{ splitChainInfo.totalSplitTimes }}</el-tag>
+          <el-tag type="warning" style="margin-left: 10px;">
+            鍘熷鏉$爜: {{ splitChainInfo.originalBarcode }}
+          </el-tag>
+          <el-tag :type="splitChainInfo.chainType === 'root' ? 'success' : 'warning'" style="margin-left: 10px;">
+            {{ splitChainInfo.chainType === 'root' ? '瀹屾暣閾�' : '鍒嗘敮閾�' }}
+          </el-tag>
+        </div>
+        
+        <el-table :data="splitChainInfo.splitChain" border height="300">
+          <el-table-column type="index" label="搴忓彿" width="60" align="center"></el-table-column>
+          <el-table-column prop="splitTime" label="鎷嗗寘鏃堕棿" width="160">
+            <template #default="scope">
+              {{ formatDateTime(scope.row.splitTime) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="originalBarcode" label="鍘熸潯鐮�" width="140">
+            <template #default="scope">
+              <el-tag 
+                :type="scope.row.originalBarcode === splitChainInfo.rootBarcode ? 'success' : 'primary'" 
+                size="small">
+                {{ scope.row.originalBarcode }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column prop="newBarcode" label="鏂版潯鐮�" width="140">
+            <template #default="scope">
+              <el-tag 
+                :type="scope.row.isReverted ? 'info' : 'warning'" 
+                size="small">
+                {{ scope.row.newBarcode }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column prop="splitQuantity" label="鎷嗗寘鏁伴噺" width="100" align="right">
+            <template #default="scope">
+              {{ scope.row.splitQuantity.toFixed(2) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="operator" label="鎿嶄綔鍛�" width="100"></el-table-column>
+          <el-table-column prop="isReverted" label="鐘舵��" width="80" align="center">
+            <template #default="scope">
+              <el-tag 
+                :type="scope.row.isReverted ? 'success' : 'danger'" 
+                size="small">
+                {{ scope.row.isReverted ? '宸叉挙閿�' : '鏈夋晥' }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="鎿嶄綔" width="120" align="center">
+            <template #default="scope">
+              <el-button 
+                v-if="!scope.row.isReverted"
+                type="danger" 
+                size="mini" 
+                @click="cancelSingleSplit(scope.row.newBarcode)"
+                :disabled="hasPicked(scope.row.newBarcode)">
+                鍙栨秷
+              </el-button>
+              <span v-else style="color: #909399;">宸叉挙閿�</span>
+            </template>
+          </el-table-column>
+        </el-table>
+        
+        <!-- 鎵归噺鎿嶄綔鍖哄煙 -->
+        <div style="margin-top: 15px; padding: 10px; background: #f5f7fa; border-radius: 4px;">
+          <div style="display: flex; justify-content: space-between; align-items: center;">
+            <div>
+              <span style="font-size: 14px; color: #606266;">
+                鎵归噺鎿嶄綔: 鍙互鍙栨秷鏁翠釜鎷嗗寘閾炬垨閫夋嫨鍗曚釜鎷嗗寘璁板綍鍙栨秷
+              </span>
+              <div style="font-size: 12px; color: #909399; margin-top: 5px;">
+                瀹屾暣鎷嗗寘閾惧寘鍚粠鏈�鍘熷鏉$爜寮�濮嬬殑鎵�鏈夋媶鍖呮搷浣�
+              </div>
+            </div>
+            <div>
+              <el-button 
+                type="danger" 
+                @click="cancelWholeSplitChain"
+                :disabled="!canCancelWholeChain"
+                :loading="revertSplitLoading">
+                鍙栨秷鏁翠釜鎷嗗寘閾�
+              </el-button>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="custom-dialog-footer">
+        <el-button @click="closeSplitChainDialog">鍏抽棴</el-button>
+      </div>
+    </div>
+  </div>
+</div>
+
     <!-- 鎵归噺鍥炲簱寮圭獥 -->
     <div v-if="showBatchReturnDialog" class="custom-dialog-overlay">
       <div class="custom-dialog-wrapper">
         <div class="custom-dialog">
           <div class="custom-dialog-header">
-            <h3>鎵规鍥炲簱</h3>
+            <h3>鎵樼洏鍥炲簱</h3>
             <el-button type="text" @click="closeBatchReturnDialog" class="close-button">脳</el-button>
           </div>
           <div class="custom-dialog-body">
@@ -269,8 +350,8 @@
               <el-form-item label="璁㈠崟缂栧彿">
                 <el-input v-model="batchReturnForm.orderNo" disabled></el-input>
               </el-form-item>
-              <el-form-item label="鎵规缂栧彿">
-                <el-input v-model="batchReturnForm.batchNo" disabled></el-input>
+              <el-form-item label="鎵樼洏缂栧彿">
+                <el-input v-model="batchReturnForm.palletCode" disabled></el-input>
               </el-form-item>
               <el-form-item label="鏈嫞閫夋暟閲�">
                 <el-input v-model="batchReturnForm.unpickedQuantity" disabled></el-input>
@@ -335,36 +416,12 @@
   name: 'BatchOutboundPicking',
   components: {printView},
   data() {
-    // 楠岃瘉瑙勫垯瀹氫箟...
-    const validateBatchQuantity = (rule, value, callback) => {
-      if (value === null || value === undefined || value === '') {
-        callback(new Error('璇疯緭鍏ュ垎閰嶆暟閲�'));
-      } else if (value <= 0) {
-        callback(new Error('鍒嗛厤鏁伴噺蹇呴』澶т簬0'));
-      } else {
-        callback();
-      }
-    };
-
-    const validateOrderDetailId = (rule, value, callback) => {
-      if (!value) {
-        callback(new Error('璇烽�夋嫨鐗╂枡鏄庣粏'));
-      } else {
-        callback();
-      }
-    };
-
     return {
       scanData: {
         orderNo: '',
         palletCode: '',
-        barcode: '',
-        batchNo: ''
+        barcode: ''
       },
-      currentBatchNo: '', // 褰撳墠鎵规鍙�
-      batchList: [], // 鎵规鍒楄〃
-      selectedBatchNo: '', // 閫変腑鐨勬壒娆″彿
-      batchSummary: {}, // 鎵规姹囨�讳俊鎭�
       unpickedList: [],
       pickedList: [],
       selectedPickedRows: [],
@@ -376,30 +433,22 @@
       palletStatus: '鏈煡',
       
       // 寮圭獥鐘舵��
-      showBatchAllocateDialog: false,
       showCustomSplitDialog: false,
       showRevertSplitDialog: false,
       showBatchReturnDialog: false,
       showEmptyPalletDialog: false,
+      showSplitChainDialog: false, // 鏂板锛氭媶鍖呴摼淇℃伅寮圭獥
       
       // 鍔犺浇鐘舵��
-      batchAllocateLoading: false,
       splitLoading: false,
       revertSplitLoading: false,
       batchReturnLoading: false,
       emptypalletOutLoading: false,
+      splitChainLoading: false, // 鏂板锛氭媶鍖呴摼鍔犺浇鐘舵��
       
       // 琛ㄥ崟鏁版嵁
-      batchAllocateForm: {
-        orderNo: '',
-        orderDetailId: '',
-        batchQuantity: 0
-      },
-      allocatableDetails: [], // 鍙垎閰嶇殑璁㈠崟鏄庣粏
-      
       splitForm: {
         orderNo: '',
-        batchNo: '',
         palletCode: '',
         originalBarcode: '',
         materielCode: '',
@@ -413,7 +462,7 @@
       
       batchReturnForm: {
         orderNo: '',
-        batchNo: '',
+        palletCode: '',
         unpickedCount: 0,
         unpickedQuantity: 0
       },
@@ -423,25 +472,52 @@
         palletCode: ''
       },
       
+      // 鏂板锛氭媶鍖呴摼鐩稿叧鏁版嵁
+      splitChainInfo: {
+        originalBarcode: '',
+        totalSplitTimes: 0,
+        splitChain: []
+      },
+      
       // 楠岃瘉瑙勫垯
-      batchAllocateFormRules: {
-        orderDetailId: [
-          { required: true, validator: validateOrderDetailId, trigger: 'change' }
+      splitFormRules: {
+        originalBarcode: [
+          { required: true, message: '璇疯緭鍏ュ師鏉$爜', trigger: 'blur' }
         ],
-        batchQuantity: [
-          { required: true, validator: validateBatchQuantity, trigger: 'blur' }
+        splitQuantity: [
+          { required: true, message: '璇疯緭鍏ユ媶鍖呮暟閲�', trigger: 'blur' },
+          { type: 'number', min: 0.01, message: '鎷嗗寘鏁伴噺蹇呴』澶т簬0', trigger: 'blur' }
         ]
       },
       
-      // 鍏朵粬楠岃瘉瑙勫垯...
+      revertSplitFormRules: {
+        newBarcode: [
+          { required: true, message: '璇疯緭鍏ユ柊鏉$爜', trigger: 'blur' }
+        ]
+      },
+      
+      emptypalletOutFormRules: {
+        palletCode: [
+          { required: true, message: '璇疯緭鍏ユ墭鐩樼爜', trigger: 'blur' }
+        ]
+      },
+      
       isProcessing: false
+    }
+  },
+  computed: {
+    // 鏄惁鍙互鍙栨秷鏁翠釜鎷嗗寘閾�
+    canCancelWholeChain() {
+      return this.splitChainInfo.splitChain && 
+             this.splitChainInfo.splitChain.some(item => !item.isReverted);
     }
   },
   mounted() {
     if (this.$route.query.orderNo) {
       this.scanData.orderNo = this.$route.query.orderNo;
-      this.batchAllocateForm.orderNo = this.$route.query.orderNo;
-      this.loadBatchList();
+      this.splitForm.orderNo = this.$route.query.orderNo;
+      this.batchReturnForm.orderNo = this.$route.query.orderNo;
+      this.emptypalletOutForm.orderNo = this.$route.query.orderNo;
     }
     this.$nextTick(() => {
       this.$refs.palletInput.focus();
@@ -450,150 +526,6 @@
   methods: {
     goBack(){
       this.$router.back()
-    },
-
-    // 鎵规鐩稿叧鏂规硶
-    async loadBatchList() {
-      try {
-        const res = await http.post('/api/BatchOutbound/order-batch-list', {
-          orderNo: this.scanData.orderNo
-        });
-        if (res.status) {
-          this.batchList = res.data || [];
-          if (this.batchList.length > 0) {
-            this.selectedBatchNo = this.batchList[0].batchNo;
-            this.currentBatchNo = this.selectedBatchNo;
-            this.scanData.batchNo = this.selectedBatchNo;
-            this.loadBatchData();
-          }
-        }
-      } catch (error) {
-        this.$message.error('鍔犺浇鎵规鍒楄〃澶辫触');
-      }
-    },
-
-    async refreshBatchList() {
-      await this.loadBatchList();
-      this.$message.success('鎵规鍒楄〃宸插埛鏂�');
-    },
-
-    onBatchChange(batchNo) {
-      this.currentBatchNo = batchNo;
-      this.scanData.batchNo = batchNo;
-      this.loadBatchData();
-    },
-
-    async loadBatchData() {
-      if (!this.currentBatchNo) return;
-      
-      await this.loadBatchSummary();
-      await this.loadUnpickedList();
-      await this.loadPickedList();
-    },
-
-    async loadBatchSummary() {
-      try {
-        const res = await http.post('/api/BatchOutbound/batch-summary', {
-          orderNo: this.scanData.orderNo,
-          batchNo: this.currentBatchNo
-        });
-        if (res.status) {
-          this.batchSummary = res.data || {};
-        }
-      } catch (error) {
-        this.$message.error('鍔犺浇鎵规姹囨�诲け璐�');
-      }
-    },
-
-    async loadUnpickedList() {
-      try {
-        const res = await http.post('/api/BatchOutbound/batch-unpicked-list', {
-          orderNo: this.scanData.orderNo,
-          batchNo: this.currentBatchNo
-        });
-        this.unpickedList = res.data || [];
-        this.summary.unpickedCount = this.unpickedList.length;
-        this.summary.unpickedQuantity = this.unpickedList.reduce((sum, item) => sum + (item.remainQuantity || 0), 0);
-      } catch (error) {
-        this.$message.error('鍔犺浇鏈嫞閫夊垪琛ㄥけ璐�');
-      }
-    },
-
-    async loadPickedList() {
-      try {
-        const res = await http.post('/api/BatchOutbound/batch-picked-list', {
-          orderNo: this.scanData.orderNo,
-          batchNo: this.currentBatchNo
-        });
-        this.pickedList = res.data || [];
-        this.summary.pickedCount = this.pickedList.length;
-      } catch (error) {
-        this.$message.error('鍔犺浇宸叉嫞閫夊垪琛ㄥけ璐�');
-      }
-    },
-
-    getBatchStatusType(status) {
-      const statusMap = {
-        0: 'info', // 鍒嗛厤涓�
-        1: 'warning', // 鎵ц涓�
-        2: 'success', // 宸插畬鎴�
-        3: 'danger' // 宸插洖搴�
-      };
-      return statusMap[status] || 'info';
-    },
-
-    // 鍒嗘壒鍒嗛厤鐩稿叧鏂规硶
-    async openBatchAllocateDialog() {
-      this.showBatchAllocateDialog = true;
-      await this.loadAllocatableDetails();
-      this.batchAllocateForm.orderDetailId = '';
-      this.batchAllocateForm.batchQuantity = 0;
-    },
-
-    async loadAllocatableDetails() {
-      try {
-        const res = await http.post('/api/BatchOutbound/allocatable-order-details', {
-          orderNo: this.scanData.orderNo
-        });
-        if (res.status) {
-          this.allocatableDetails = res.data || [];
-        }
-      } catch (error) {
-        this.$message.error('鍔犺浇鍙垎閰嶆槑缁嗗け璐�');
-      }
-    },
-
-    getAvailableQuantity() {
-      const detail = this.allocatableDetails.find(d => d.id === this.batchAllocateForm.orderDetailId);
-      return detail ? detail.availableQuantity : 0;
-    },
-
-    async handleBatchAllocate() {
-      if (this.$refs.batchAllocateFormRef) {
-        this.$refs.batchAllocateFormRef.validate(async (valid) => {
-          if (valid) {
-            this.batchAllocateLoading = true;
-            try {
-              const res = await http.post('/api/BatchOutbound/batch-allocate-stock', this.batchAllocateForm);
-              if (res.status) {
-                this.$message.success('鍒嗘壒鍒嗛厤鎴愬姛');
-                this.showBatchAllocateDialog = false;
-                await this.loadBatchList(); // 鍒锋柊鎵规鍒楄〃
-              } else {
-                this.$message.error(res.message || '鍒嗘壒鍒嗛厤澶辫触');
-              }
-            } catch (error) {
-              this.$message.error('鍒嗘壒鍒嗛厤澶辫触');
-            } finally {
-              this.batchAllocateLoading = false;
-            }
-          }
-        });
-      }
-    },
-
-    closeBatchAllocateDialog() {
-      this.showBatchAllocateDialog = false;
     },
 
     // 鍒嗘嫞鐩稿叧鏂规硶
@@ -606,19 +538,18 @@
         return;
       }
 
-      if (!this.currentBatchNo) {
-        this.$message.warning('璇峰厛閫夋嫨鎵规');
-        return;
-      }
-
       this.isProcessing = true;
       
       try {
-        const res = await http.post('/api/BatchOutbound/confirm-picking', this.scanData);
+        const res = await http.post('/api/OutboundBatchPicking/confirm-picking', {
+          orderNo: this.scanData.orderNo,
+          palletCode: this.scanData.palletCode,
+          barcode: this.scanData.barcode
+        });
         if (res.status) {
           this.$message.success('鎷i�夌‘璁ゆ垚鍔�');
           this.scanData.barcode = '';
-          await this.loadBatchData();
+          await this.loadPalletData();
           if(res.data && res.data.splitResults && res.data.splitResults.length>0){
             this.$refs.childs.open(res.data.splitResults);
           }
@@ -643,14 +574,9 @@
         this.$message.warning('璇峰厛鎵弿鎵樼洏鐮�');
         return;
       }
-      if (!this.currentBatchNo) {
-        this.$message.warning('璇峰厛閫夋嫨鎵规');
-        return;
-      }
       this.showCustomSplitDialog = true;
       this.resetSplitForm();
       this.splitForm.orderNo = this.scanData.orderNo;
-      this.splitForm.batchNo = this.currentBatchNo;
       this.splitForm.palletCode = this.scanData.palletCode;
     },
 
@@ -659,9 +585,9 @@
       this.splitForm.originalBarcode = this.splitForm.originalBarcode.replace(/\n/g, '').trim();
 
       try {
-        const res = await http.post('/api/BatchOutbound/split-package-info', {
+        const res = await http.post('/api/OutboundBatchPicking/split-package-info', {
           orderNo: this.splitForm.orderNo,
-          batchNo: this.splitForm.batchNo,
+          palletCode: this.splitForm.palletCode,
           barcode: this.splitForm.originalBarcode
         });
 
@@ -683,11 +609,16 @@
           if (valid) {
             this.splitLoading = true;
             try {
-              const res = await http.post('/api/BatchOutbound/manual-split-package', this.splitForm);
+              const res = await http.post('/api/OutboundBatchPicking/split-package', {
+                orderNo: this.splitForm.orderNo,
+                palletCode: this.splitForm.palletCode,
+                originalBarcode: this.splitForm.originalBarcode,
+                splitQuantity: this.splitForm.splitQuantity
+              });
               if (res.status) {
                 this.$message.success('鎷嗗寘鎴愬姛');
                 this.showCustomSplitDialog = false;
-                await this.loadBatchData();
+                await this.loadPalletData();
               } else {
                 this.$message.error(res.message || '鎷嗗寘澶辫触');
               }
@@ -700,11 +631,28 @@
         });
       }
     },
-
+// 鍦ㄦ媶鍖呭脊绐椾腑鏌ョ湅鎷嗗寘閾�
+async viewSplitChainFromSplit(barcode) {
+  if (!barcode) {
+    this.$message.warning('璇峰厛杈撳叆鏉$爜');
+    return;
+  }
+  
+  // 鍏堝叧闂媶鍖呭脊绐�
+  this.closeCustomSplitDialog();
+  
+  await this.$nextTick();
+  
+  // 鐒跺悗鎵撳紑鎷嗗寘閾句俊鎭脊绐�
+  await this.viewSplitChain(barcode);
+},
     // 鎾ら攢鎷嗗寘
     async onRevertSplitBarcodeScan() {
       if (!this.revertSplitForm.newBarcode) return;
       this.revertSplitForm.newBarcode = this.revertSplitForm.newBarcode.replace(/\n/g, '').trim();
+      
+      // 鏂板锛氭壂鎻忓悗鑷姩鏄剧ず鎷嗗寘閾句俊鎭�
+      await this.viewSplitChain(this.revertSplitForm.newBarcode);
     },
 
     async handleRevertSplit() {
@@ -713,15 +661,15 @@
           if (valid) {
             this.revertSplitLoading = true;
             try {
-              const res = await http.post('/api/BatchOutbound/cancel-split-package', {
+              const res = await http.post('/api/OutboundBatchPicking/cancel-split', {
                 orderNo: this.scanData.orderNo,
-                batchNo: this.currentBatchNo,
+                palletCode: this.scanData.palletCode,
                 newBarcode: this.revertSplitForm.newBarcode
               });
               if (res.status) {
                 this.$message.success('鎾ら攢鎷嗗寘鎴愬姛');
                 this.showRevertSplitDialog = false;
-                await this.loadBatchData();
+                await this.loadPalletData();
               } else {
                 this.$message.error(res.message || '鎾ら攢鎷嗗寘澶辫触');
               }
@@ -734,16 +682,238 @@
         });
       }
     },
+// 鏌ユ壘瀹屾暣鎷嗗寘閾撅紙浠庢牴鏉$爜寮�濮嬶級
+async findRootChain(currentBarcode) {
+  this.splitChainLoading = true;
+  try {
+    const res = await http.post('/api/OutboundBatchPicking/find-root-split-chain', {
+      orderNo: this.scanData.orderNo,
+      barcode: currentBarcode
+    });
+    
+    if (res.status) {
+      this.splitChainInfo = res.data;
+      this.$message.success('宸插姞杞藉畬鏁存媶鍖呴摼');
+    } else {
+      this.$message.error(res.message || '鏌ユ壘瀹屾暣鎷嗗寘閾惧け璐�');
+    }
+  } catch (error) {
+    this.$message.error('鏌ユ壘瀹屾暣鎷嗗寘閾惧け璐�');
+  } finally {
+    this.splitChainLoading = false;
+  }
+},
+    // 鎷嗗寘閾剧浉鍏虫柟娉�
+   // 鏌ョ湅鎷嗗寘閾句俊鎭�
+async viewSplitChain(barcode) {
+  if (!barcode) {
+    this.$message.warning('璇峰厛杈撳叆鏉$爜');
+    return;
+  }
+  
+  this.splitChainLoading = true;
+  try {
+    const res = await http.post('/api/OutboundBatchPicking/split-package-chain-info', {
+      orderNo: this.scanData.orderNo,
+      barcode: barcode
+    });
+    
+    if (res.status) {
+      this.splitChainInfo = res.data;
+      
+      // 鏄剧ず鎻愮ず淇℃伅锛屽憡璇夌敤鎴疯繖鏄粈涔堢被鍨嬬殑鎷嗗寘閾�
+      let chainType = "褰撳墠鏉$爜鐨勬媶鍖呴摼";
+      if (this.splitChainInfo.chainType === 'root') {
+        chainType = "瀹屾暣鎷嗗寘閾撅紙浠庡師濮嬫潯鐮佸紑濮嬶級";
+      } else if (this.splitChainInfo.chainType === 'branch') {
+        chainType = "鍒嗘敮鎷嗗寘閾�";
+      }
+      
+      this.$message.info(`宸插姞杞�${chainType}锛屽叡${this.splitChainInfo.totalSplitTimes}娆℃媶鍖卄);
+      this.showSplitChainDialog = true;
+    } else {
+      this.$message.error(res.message || '鑾峰彇鎷嗗寘閾句俊鎭け璐�');
+    }
+  } catch (error) {
+    this.$message.error('鑾峰彇鎷嗗寘閾句俊鎭け璐�');
+  } finally {
+    this.splitChainLoading = false;
+  }
+},
+
+    // 鍏抽棴鎷嗗寘閾句俊鎭脊绐�
+    closeSplitChainDialog() {
+      this.showSplitChainDialog = false;
+      
+    },
+    // 鍦ㄦ挙閿�鎷嗗寘寮圭獥涓煡鐪嬫媶鍖呴摼
+async viewSplitChainFromRevert(barcode) {
+  if (!barcode) {
+    this.$message.warning('璇峰厛杈撳叆鏉$爜');
+    return;
+  }
+  
+  // 鍏堝叧闂挙閿�鎷嗗寘寮圭獥
+  this.closeRevertSplitDialog();
+  
+  await this.$nextTick();
+  
+  // 鐒跺悗鎵撳紑鎷嗗寘閾句俊鎭脊绐�
+  await this.viewSplitChain(barcode);
+},
+// 蹇�熼噸鏂版墦寮�鎷嗗寘閾惧脊绐�
+async quickReopenSplitChainDialog(barcode) {
+  if (!barcode) return;
+  
+  this.showSplitChainDialog = true;
+  this.splitChainLoading = true;
+  
+  try {
+    const res = await http.post('/api/OutboundBatchPicking/split-package-chain-info', {
+      orderNo: this.scanData.orderNo,
+      barcode: barcode
+    });
+    
+    if (res.status) {
+      this.splitChainInfo = res.data;
+    }
+  } catch (error) {
+    console.error('閲嶆柊鍔犺浇鎷嗗寘閾句俊鎭け璐�:', error);
+  } finally {
+    this.splitChainLoading = false;
+  }
+},
+    // 鍙栨秷鍗曚釜鎷嗗寘璁板綍
+async cancelSingleSplit(newBarcode) {
+  // 鍏堣褰曞綋鍓嶄俊鎭紝鐒跺悗鍏抽棴寮圭獥
+  const originalBarcode = this.splitChainInfo.originalBarcode;
+  this.closeSplitChainDialog();
+  
+  await this.$nextTick();
+  
+  try {
+    await this.$confirm(
+      `纭畾瑕佸彇娑堟潯鐮� ${newBarcode} 鐨勬媶鍖呮搷浣滃悧锛焋, 
+      '鍙栨秷鍗曚釜鎷嗗寘', 
+      {
+        confirmButtonText: '纭畾鍙栨秷',
+        cancelButtonText: '鍐嶆兂鎯�',
+        type: 'warning'
+      }
+    );
+    
+    this.revertSplitLoading = true;
+    
+    const res = await http.post('/api/OutboundBatchPicking/cancel-split', {
+      orderNo: this.scanData.orderNo,
+      palletCode: this.scanData.palletCode,
+      newBarcode: newBarcode
+    });
+    
+    if (res.status) {
+      this.$message.success('鍙栨秷鎷嗗寘鎴愬姛');
+      await this.loadPalletData();
+      // 閲嶆柊鎵撳紑寮圭獥鏄剧ず鏇存柊鍚庣殑鐘舵��
+      await this.viewSplitChain(originalBarcode);
+    } else {
+      this.$message.error(res.message || '鍙栨秷鎷嗗寘澶辫触');
+      await this.viewSplitChain(originalBarcode);
+    }
+  } catch (error) {
+    if (error === 'cancel') {
+      // 鐢ㄦ埛鍙栨秷鍚庨噸鏂版墦寮�寮圭獥
+      await this.viewSplitChain(originalBarcode);
+    } else {
+      this.$message.error('鍙栨秷鎷嗗寘澶辫触');
+      await this.viewSplitChain(originalBarcode);
+    }
+  } finally {
+    this.revertSplitLoading = false;
+  }
+},
+
+// 鍙栨秷鏁翠釜鎷嗗寘閾�  
+async cancelWholeSplitChain() {
+  // 鍏堣褰曞綋鍓嶆媶鍖呴摼淇℃伅锛岀劧鍚庡叧闂脊绐�
+  const originalBarcode = this.splitChainInfo.originalBarcode;
+  this.closeSplitChainDialog();
+  
+  // 缁欎竴鐐规椂闂磋寮圭獥瀹屽叏鍏抽棴
+  await this.$nextTick();
+  
+  try {
+    // 鐜板湪鏄剧ず纭瀵硅瘽妗嗭紝纭繚瀹冨湪鏈�鍓嶉潰
+    await this.$confirm(
+      `纭畾瑕佸彇娑堟暣涓媶鍖呴摼鍚楋紵\n杩欏皢鍙栨秷浠庢潯鐮� ${originalBarcode} 寮�濮嬬殑鎵�鏈夋媶鍖呮搷浣溿�俙, 
+      '鍙栨秷鎷嗗寘閾剧‘璁�', 
+      {
+        confirmButtonText: '纭畾鍙栨秷',
+        cancelButtonText: '鍐嶆兂鎯�',
+        type: 'warning',
+        center: true,
+        closeOnClickModal: false
+      }
+    );
+    
+    // 鐢ㄦ埛纭鍚庢墽琛屽彇娑堟搷浣�
+    this.revertSplitLoading = true;
+    
+    const res = await http.post('/api/OutboundBatchPicking/cancel-split-chain', {
+      orderNo: this.scanData.orderNo,
+      palletCode: this.scanData.palletCode,
+      startBarcode: originalBarcode
+    });
+    
+    console.log('鍙栨秷鎷嗗寘閾惧搷搴�:', res);
+    
+    if (res.status) {
+      this.$message.success('鍙栨秷鎷嗗寘閾炬垚鍔�');
+      await this.loadPalletData();
+      // 鍙�夛細閲嶆柊鎵撳紑鎷嗗寘閾句俊鎭脊绐楁樉绀烘洿鏂板悗鐨勭姸鎬�
+      // await this.viewSplitChain(originalBarcode);
+    } else {
+      this.$message.error(res.message || '鍙栨秷鎷嗗寘閾惧け璐�');
+      // 澶辫触鍚庨噸鏂版墦寮�寮圭獥
+      await this.viewSplitChain(originalBarcode);
+    }
+  } catch (error) {
+    // 鐢ㄦ埛鍙栨秷鎿嶄綔
+    if (error === 'cancel') {
+      console.log('鐢ㄦ埛鍙栨秷浜嗘媶鍖呴摼鎿嶄綔');
+      // 鐢ㄦ埛鍙栨秷鍚庨噸鏂版墦寮�寮圭獥
+      await this.viewSplitChain(originalBarcode);
+    } else {
+      console.error('鍙栨秷鎷嗗寘閾鹃敊璇�:', error);
+      this.$message.error('鍙栨秷鎷嗗寘閾惧け璐�: ' + error.message);
+      // 鍑洪敊鍚庨噸鏂版墦寮�寮圭獥
+      await this.viewSplitChain(originalBarcode);
+    }
+  } finally {
+    this.revertSplitLoading = false;
+  }
+},
+
+    // 妫�鏌ユ潯鐮佹槸鍚﹀凡琚垎鎷�
+    hasPicked(barcode) {
+      return this.pickedList.some(item => item.currentBarcode === barcode);
+    },
+
+    // 鏍煎紡鍖栨棩鏈熸椂闂�
+    formatDateTime(dateTime) {
+      if (!dateTime) return '';
+      const date = new Date(dateTime);
+      return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}`;
+    },
 
     // 鍥炲簱鐩稿叧鏂规硶
     openBatchReturnDialog() {
-      if (!this.currentBatchNo) {
-        this.$message.warning('璇峰厛閫夋嫨鎵规');
+      if (!this.scanData.palletCode) {
+        this.$message.warning('璇峰厛鎵弿鎵樼洏鐮�');
         return;
       }
       this.showBatchReturnDialog = true;
       this.batchReturnForm.orderNo = this.scanData.orderNo;
-      this.batchReturnForm.batchNo = this.currentBatchNo;
+      this.batchReturnForm.palletCode = this.scanData.palletCode;
       this.batchReturnForm.unpickedCount = this.summary.unpickedCount;
       this.batchReturnForm.unpickedQuantity = this.summary.unpickedQuantity;
     },
@@ -751,33 +921,42 @@
     async handleBatchReturnConfirm() {
       this.batchReturnLoading = true;
       try {
-        const res = await http.post('/api/BatchOutbound/batch-return-stock', {
+        const res = await http.post('/api/OutboundBatchPicking/return-stock', {
           orderNo: this.scanData.orderNo,
-          batchNo: this.currentBatchNo
+          palletCode: this.scanData.palletCode
         });
         if (res.status) {
-          this.$message.success('鎵规鍥炲簱鎴愬姛');
+          this.$message.success('鍥炲簱鎴愬姛');
           this.showBatchReturnDialog = false;
-          await this.loadBatchData();
+          await this.loadPalletData();
         } else {
-          this.$message.error(res.message || '鎵规鍥炲簱澶辫触');
+          this.$message.error(res.message || '鍥炲簱澶辫触');
         }
       } catch (error) {
-        this.$message.error('鎵规鍥炲簱澶辫触');
+        this.$message.error('鍥炲簱澶辫触');
       } finally {
         this.batchReturnLoading = false;
       }
     },
 
     // 鍙栫┖绠辨柟娉�
+    handleEmptyPallet() {
+      this.showEmptyPalletDialog = true;
+      this.emptypalletOutForm.orderNo = this.scanData.orderNo;
+      this.emptypalletOutForm.palletCode = '';
+    },
+
     async handleEmptyPalletConfirm() {
       this.emptypalletOutLoading = true;
       try {
-        const res = await http.post('/api/BatchOutbound/remove-empty-pallet', this.emptypalletOutForm);
+        const res = await http.post('/api/OutboundBatchPicking/remove-empty-pallet', {
+          orderNo: this.emptypalletOutForm.orderNo,
+          palletCode: this.emptypalletOutForm.palletCode
+        });
         if (res.status) {
           this.$message.success('鍙栬蛋绌虹鎴愬姛');
           this.showEmptyPalletDialog = false;
-          await this.loadBatchData();
+          await this.loadPalletData();
         } else {
           this.$message.error(res.message || '鍙栬蛋绌虹澶辫触');
         }
@@ -788,32 +967,69 @@
       }
     },
 
-    // 鍏朵粬鍘熸湁鏂规硶...
+    // 鏁版嵁鍔犺浇鏂规硶
+    async loadPalletData() {
+      if (!this.scanData.orderNo || !this.scanData.palletCode) return;
+      
+      await this.loadUnpickedList();
+      await this.loadPickedList();
+      await this.loadPalletStatus();
+    },
+
+    async loadUnpickedList() {
+      try {
+        const res = await http.post('/api/OutboundBatchPicking/pallet-locks', {
+          orderNo: this.scanData.orderNo,
+          palletCode: this.scanData.palletCode
+        });
+        if (res.status) {
+          this.unpickedList = res.data || [];
+          this.summary.unpickedCount = this.unpickedList.length;
+          this.summary.unpickedQuantity = this.unpickedList.reduce((sum, item) => sum + (item.remainQuantity || 0), 0);
+        }
+      } catch (error) {
+        this.$message.error('鍔犺浇鏈嫞閫夊垪琛ㄥけ璐�');
+      }
+    },
+
+    async loadPickedList() {
+      try {
+        const res = await http.post('/api/OutboundBatchPicking/pallet-picked-list', {
+          orderNo: this.scanData.orderNo,
+          palletCode: this.scanData.palletCode
+        });
+        if (res.status) {
+          this.pickedList = res.data || [];
+          this.summary.pickedCount = this.pickedList.length;
+        }
+      } catch (error) {
+        this.$message.error('鍔犺浇宸叉嫞閫夊垪琛ㄥけ璐�');
+      }
+    },
+
+    async loadPalletStatus() {
+      try {
+        const res = await http.post('/api/OutboundBatchPicking/pallet-status', {
+          orderNo: this.scanData.orderNo,
+          palletCode: this.scanData.palletCode
+        });
+        if (res.status) {
+          this.palletStatus = res.data.statusText || '鏈煡';
+        }
+      } catch (error) {
+        this.palletStatus = '鏈煡';
+      }
+    },
+
+    // 鎵爜鐩稿叧鏂规硶
     onPalletScan() {
       this.scanData.palletCode = this.scanData.palletCode.replace(/\n/g, '').trim();
       if (!this.scanData.palletCode) return;
       
-      this.loadActiveBatch();
+      this.loadPalletData();
       this.$nextTick(() => {
         this.$refs.barcodeInput.focus();
       });
-    },
-
-    async loadActiveBatch() {
-      try {
-        const res = await http.post('/api/BatchOutbound/active-batch', {
-          orderNo: this.scanData.orderNo,
-          palletCode: this.scanData.palletCode
-        });
-        if (res.status && res.data) {
-          this.currentBatchNo = res.data.batchNo;
-          this.scanData.batchNo = res.data.batchNo;
-          this.selectedBatchNo = res.data.batchNo;
-          await this.loadBatchData();
-        }
-      } catch (error) {
-        console.log('鑾峰彇娲昏穬鎵规澶辫触锛屽彲鑳芥墭鐩樻病鏈夊叧鑱旀壒娆�');
-      }
     },
 
     onBarcodeScan() {
@@ -853,9 +1069,8 @@
         try {
           for (const row of this.selectedPickedRows) {
             try {
-              const res = await http.post('/api/BatchOutbound/cancel-picking', {
+              const res = await http.post('/api/OutboundBatchPicking/cancel-picking', {
                 orderNo: this.scanData.orderNo,
-                batchNo: this.currentBatchNo,
                 palletCode: this.scanData.palletCode,
                 barcode: row.currentBarcode
               });
@@ -867,7 +1082,7 @@
             }
           }        
           this.$message.success('鎵归噺鍙栨秷瀹屾垚');
-          await this.loadBatchData();
+          await this.loadPalletData();
           this.selectedPickedRows = [];
         } catch (error) {
           this.$message.error('鎵归噺鍙栨秷鎿嶄綔澶辫触');
@@ -902,10 +1117,9 @@
       this.showBatchReturnDialog = false;
     },
 
-    openEmptyPalletDialog() {
-      this.showEmptyPalletDialog = true;
-      this.emptypalletOutForm.orderNo = this.scanData.orderNo;
-      this.emptypalletOutForm.palletCode = '';
+    onEmptyPalletScan() {
+      if (!this.emptypalletOutForm.palletCode) return;
+      this.emptypalletOutForm.palletCode = this.emptypalletOutForm.palletCode.replace(/\n/g, '').trim();
     },
 
     closeEmptyPalletDialog() {
@@ -913,9 +1127,8 @@
       this.emptypalletOutForm.palletCode = '';
     },
 
-    onEmptyPalletScan() {
-      if (!this.emptypalletOutForm.palletCode) return;
-      this.emptypalletOutForm.palletCode = this.emptypalletOutForm.palletCode.replace(/\n/g, '').trim();
+    parentcall() {
+      // 鎵撳嵃鍥炶皟
     }
   }
 })
@@ -924,26 +1137,6 @@
 <style scoped>
 .OutboundPicking-container {
   padding: 20px;
-}
-
-.batch-operations {
-  margin-bottom: 15px;
-}
-
-.batch-actions {
-  display: flex;
-  align-items: center;
-  gap: 10px;
-}
-
-.batch-summary-area {
-  margin-bottom: 15px;
-}
-
-.batch-summary-info {
-  display: flex;
-  gap: 15px;
-  flex-wrap: wrap;
 }
 
 .scanner-form {
@@ -977,6 +1170,18 @@
 }
 
 /* 鑷畾涔夊脊绐楁牱寮� */
+:deep(.el-message-box) {
+  z-index: 10010 !important;
+}
+
+:deep(.el-overlay) {
+  z-index: 10009 !important;
+}
+
+:deep(.el-message) {
+  z-index: 10011 !important;
+}
+
 .custom-dialog-overlay {
   position: fixed;
   top: 0;
@@ -987,12 +1192,12 @@
   display: flex;
   align-items: center;
   justify-content: center;
-  z-index: 9999;
+  z-index: 2000; /* 淇濇寔涓�涓悎鐞嗙殑 z-index */
 }
 
 .custom-dialog-wrapper {
   position: relative;
-  z-index: 10000;
+  z-index: 2001;
 }
 
 .custom-dialog {
@@ -1058,7 +1263,14 @@
     flex-direction: column;
     align-items: stretch;
   }
-  
+  /* 纭繚纭瀵硅瘽妗嗗湪鏈�鍓嶉潰 */
+.el-message-box__wrapper {
+  z-index: 10001 !important;
+}
+
+.el-message {
+  z-index: 10002 !important;
+}
   .scanner-form .el-input {
     width: 100%;
   }
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/CommonEnum/PalletTypeEnum.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/CommonEnum/PalletTypeEnum.cs"
index f9a2413..a7d5abd 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/CommonEnum/PalletTypeEnum.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/CommonEnum/PalletTypeEnum.cs"
@@ -35,4 +35,18 @@
         /// </summary>
         LargestPallet = 4
     }
+
+
+ 
+
+    public enum PalletStatusEnum
+    {
+        鏈紑濮� = 0,
+        鎷i�変腑 = 1,
+        宸插畬鎴� = 2,
+        鏃犱换鍔� = 3
+    }
+
+
+ 
 }
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/OrderEnum/OutboundOrderEnum.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/OrderEnum/OutboundOrderEnum.cs"
index ad071e1..805fb4f 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/OrderEnum/OutboundOrderEnum.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/OrderEnum/OutboundOrderEnum.cs"
@@ -103,4 +103,6 @@
         [Description("鍏朵粬鍑哄簱鍗�")]
         Other = 235
     }
+
+
 }
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/OutLockStockStatusEnum.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/OutLockStockStatusEnum.cs"
index e106eab..dc7d6c1 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/OutLockStockStatusEnum.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/OutLockStockStatusEnum.cs"
@@ -35,6 +35,8 @@
         宸叉嫞閫� = 3,
         宸插洖搴� = 4,
     }
+    
+
     public enum OutLockStockStatusEnum
     {
         [Description("宸插垎閰�")]
@@ -67,6 +69,9 @@
         [Description("宸查噴鏀�")]
         宸查噴鏀� =9,
 
+        [Description("宸插彇璧�")]
+        宸插彇璧� =10,
+
         [Description("鎾ら攢")]
         鎾ら攢 = 99
     }
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/StockStatusEmun.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/StockStatusEmun.cs"
index d10b600..65e71f1 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/StockStatusEmun.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/StockStatusEmun.cs"
@@ -40,6 +40,9 @@
         Lock,
 
     }
+
+ 
+
     /// <summary>
     /// 搴撳瓨鐘舵�侊細 <br/>
     /// 1锛岀粍鐩樻殏瀛�<br/>
@@ -98,7 +101,10 @@
         [Description("鐩樼偣搴撳瓨瀹屾垚")]
         鐩樼偣搴撳瓨瀹屾垚 = 32,
 
-        [Description("缁勭洏鎾ら攢")]
+        [Description("宸叉竻鐞�")]
+        宸叉竻鐞� = 33,
+
+       [Description("缁勭洏鎾ら攢")]
         缁勭洏鎾ら攢 = 99,
 
         [Description("鍏ュ簱鎾ら攢")]
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/BatchOutBoundDto.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/BatchOutBoundDto.cs"
new file mode 100644
index 0000000..e889a73
--- /dev/null
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/BatchOutBoundDto.cs"
@@ -0,0 +1,169 @@
+锘縰sing SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace WIDESEA_DTO.Outbound
+{
+
+
+    public class PalletLockInfoDto
+    {
+        public int Id { get; set; }
+        public string OrderNo { get; set; }
+        public string BatchNo { get; set; }
+        public string MaterielCode { get; set; }
+        public string CurrentBarcode { get; set; }
+        public decimal AssignQuantity { get; set; }
+        public decimal PickedQty { get; set; }
+        public int Status { get; set; }
+        public string LocationCode { get; set; }
+        public string PalletCode { get; set; }
+        public bool CanSplit { get; set; }
+        public bool CanPick { get; set; }
+    }
+
+    #region 璇锋眰DTO
+
+    public class ConfirmPickingRequest
+    {
+        [Required(ErrorMessage = "璁㈠崟鍙蜂笉鑳戒负绌�")]
+        public string OrderNo { get; set; }
+
+        [Required(ErrorMessage = "鎵樼洏鍙蜂笉鑳戒负绌�")]
+        public string PalletCode { get; set; }
+
+        [Required(ErrorMessage = "鏉$爜涓嶈兘涓虹┖")]
+        public string Barcode { get; set; }
+    }
+
+    public class CancelPickingRequest
+    {
+        [Required(ErrorMessage = "璁㈠崟鍙蜂笉鑳戒负绌�")]
+        public string OrderNo { get; set; }
+
+        [Required(ErrorMessage = "鎵樼洏鍙蜂笉鑳戒负绌�")]
+        public string PalletCode { get; set; }
+
+        [Required(ErrorMessage = "鏉$爜涓嶈兘涓虹┖")]
+        public string Barcode { get; set; }
+
+        public int PickingHistoryId { get; set; }
+    }
+
+ 
+
+    public class CancelSplitRequest
+    {
+        [Required(ErrorMessage = "璁㈠崟鍙蜂笉鑳戒负绌�")]
+        public string OrderNo { get; set; }
+
+        [Required(ErrorMessage = "鎵樼洏鍙蜂笉鑳戒负绌�")]
+        public string PalletCode { get; set; }
+
+        [Required(ErrorMessage = "鏂版潯鐮佷笉鑳戒负绌�")]
+        public string NewBarcode { get; set; }
+    }
+
+    public class ReturnStockRequest
+    {
+        [Required(ErrorMessage = "璁㈠崟鍙蜂笉鑳戒负绌�")]
+        public string OrderNo { get; set; }
+
+        [Required(ErrorMessage = "鎵樼洏鍙蜂笉鑳戒负绌�")]
+        public string PalletCode { get; set; }
+    }
+    public class CancelSplitDto
+    {
+        [Required(ErrorMessage = "璁㈠崟鍙蜂笉鑳戒负绌�")]
+        public string OrderNo { get; set; }
+
+        [Required(ErrorMessage = "鎵樼洏鍙蜂笉鑳戒负绌�")]
+        public string PalletCode { get; set; }
+
+        [Required(ErrorMessage = "鏂版潯鐮佷笉鑳戒负绌�")]
+        public string NewBarcode { get; set; }
+    }
+
+    public class ReturnStockDto
+    {
+        [Required(ErrorMessage = "璁㈠崟鍙蜂笉鑳戒负绌�")]
+        public string OrderNo { get; set; }
+
+        [Required(ErrorMessage = "鎵樼洏鍙蜂笉鑳戒负绌�")]
+        public string PalletCode { get; set; }
+    }
+
+    public class PalletLocksDto
+    {
+        [Required(ErrorMessage = "璁㈠崟鍙蜂笉鑳戒负绌�")]
+        public string OrderNo { get; set; }
+
+        [Required(ErrorMessage = "鎵樼洏鍙蜂笉鑳戒负绌�")]
+        public string PalletCode { get; set; }
+    }
+
+    #endregion
+
+    #region DTO绫�
+
+    public class PalletPickedInfoDto
+    {
+        public int Id { get; set; }
+        public string OrderNo { get; set; }
+        public int OrderDetailId { get; set; }
+        public string PalletCode { get; set; }
+        public string Barcode { get; set; }
+        public string MaterielCode { get; set; }
+        public decimal PickedQty { get; set; }
+        public DateTime PickTime { get; set; }
+        public string Operator { get; set; }
+        public string LocationCode { get; set; }
+    }
+
+    public class PalletStatusDto
+    {
+        public string OrderNo { get; set; }
+        public string PalletCode { get; set; }
+        public int Status { get; set; }
+        public string StatusText { get; set; }
+        public int TotalItems { get; set; }
+        public int CompletedItems { get; set; }
+        public int PendingItems { get; set; }
+    }
+
+    public class SplitPackageInfoDto
+    {
+        public string OrderNo { get; set; }
+        public string PalletCode { get; set; }
+        public string Barcode { get; set; }
+        public string MaterielCode { get; set; }
+        public decimal RemainQuantity { get; set; }
+        public decimal AssignQuantity { get; set; }
+        public decimal PickedQty { get; set; }
+    }
+
+    public class EmptyPalletRemovalDto
+    {
+        public string OrderNo { get; set; }
+        public string PalletCode { get; set; }
+        public DateTime RemovalTime { get; set; }
+        public string Operator { get; set; }
+        public int CompletedItemsCount { get; set; }
+        public decimal TotalPickedQuantity { get; set; }
+    }
+
+    public class RemoveEmptyPalletDto
+    {
+        [Required(ErrorMessage = "璁㈠崟鍙蜂笉鑳戒负绌�")]
+        public string OrderNo { get; set; }
+
+        [Required(ErrorMessage = "鎵樼洏鍙蜂笉鑳戒负绌�")]
+        public string PalletCode { get; set; }
+    }
+    #endregion
+
+}
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/OutboundOrderGetDTO.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/OutboundOrderGetDTO.cs"
index 8381ea6..bbb4ca0 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/OutboundOrderGetDTO.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/OutboundOrderGetDTO.cs"
@@ -2,6 +2,7 @@
 using Newtonsoft.Json;
 using System;
 using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
@@ -37,8 +38,20 @@
     {
         public int OutStockLockInfoId { get; set; }
         public string MaterielCode { get; set; }
-        public decimal SplitQuantity { get; set; }
+    
         public string Operator { get; set; }
+
+        [Required(ErrorMessage = "璁㈠崟鍙蜂笉鑳戒负绌�")]
+        public string OrderNo { get; set; }
+
+        [Required(ErrorMessage = "鎵樼洏鍙蜂笉鑳戒负绌�")]
+        public string PalletCode { get; set; }
+
+        [Required(ErrorMessage = "鍘熸潯鐮佷笉鑳戒负绌�")]
+        public string OriginalBarcode { get; set; }
+
+        [Range(0.001, double.MaxValue, ErrorMessage = "鎷嗗寘鏁伴噺蹇呴』澶т簬0")]
+        public decimal SplitQuantity { get; set; }
     }
     public class ConfirmPickingDto
     {
@@ -77,10 +90,7 @@
         public string OrderNo { get; set; }
     }
 
-    public class CancelPickingRequest
-    {
-        public int PickingHistoryId { get; set; }
-    }
+ 
 
     public class BackToStockRequest
     {
@@ -261,6 +271,29 @@
         public string Barcode { get; set; }
     }
 
+ 
+
+    public class CancelSplitChainDto
+    {
+        [Required(ErrorMessage = "璁㈠崟鍙蜂笉鑳戒负绌�")]
+        public string OrderNo { get; set; }
+
+        [Required(ErrorMessage = "鎵樼洏鍙蜂笉鑳戒负绌�")]
+        public string PalletCode { get; set; }
+
+        [Required(ErrorMessage = "璧峰鏉$爜涓嶈兘涓虹┖")]
+        public string StartBarcode { get; set; }
+    }
+
+    public class SplitPackageChainInfoRequestDto
+    {
+        [Required(ErrorMessage = "璁㈠崟鍙蜂笉鑳戒负绌�")]
+        public string OrderNo { get; set; }
+
+        [Required(ErrorMessage = "鏉$爜涓嶈兘涓虹┖")]
+        public string Barcode { get; set; }
+    }
+
     public class SplitPackageDto
     {
         public string OrderNo { get; set; }
@@ -295,4 +328,6 @@
         //public decimal SplitQuantity { get; set; }
         //public decimal RemainQuantity { get; set; }
     }
+ 
+
 }
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_DTO/Task/WMSTaskDTO.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_DTO/Task/WMSTaskDTO.cs"
index 03e71c3..2adbcca 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_DTO/Task/WMSTaskDTO.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_DTO/Task/WMSTaskDTO.cs"
@@ -81,4 +81,15 @@
         public int[] taskIds { get; set; }
 
     }
+
+    public class GenerateOutboundBatchTasksDto 
+    {
+        public string orderNo { get; set; }
+
+        public int orderDetailId { get; set; }
+
+        public decimal batchQuantity { get; set; }
+
+        public string outboundPlatform { get; set; }
+    }
 }
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutboundBatchPickingService.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutboundBatchPickingService.cs"
index 15027f8..37d8a2f 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutboundBatchPickingService.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutboundBatchPickingService.cs"
@@ -1,5 +1,6 @@
 锘縰sing WIDESEA_Core;
 using WIDESEA_Core.BaseRepository;
+using WIDESEA_DTO.Outbound;
 using WIDESEA_Model.Models;
 
 namespace WIDESEA_IOutboundService
@@ -11,7 +12,18 @@
         Task<WebResponseContent> BatchReturnStock(string orderNo, string palletCode);
         Task<WebResponseContent> CancelPicking(string orderNo, string palletCode, string barcode);
         Task<WebResponseContent> CancelSplitPackage(string orderNo, string palletCode, string newBarcode);
+
+        Task<WebResponseContent> CancelSplitPackageChain(string orderNo, string palletCode, string startBarcode);
+
+        Task<List<Dt_SplitPackageRecord>> GetSplitPackageChain(string orderNo, string startBarcode);
+        Task<string> FindRootBarcode(string orderNo, string startBarcode);
+        Task<WebResponseContent> GetSplitPackageChainInfo(string orderNo, string barcode);
         Task<WebResponseContent> ConfirmBatchPicking(string orderNo, string palletCode, string barcode);
+        Task<List<PalletLockInfoDto>> GetPalletLockInfos(string orderNo, string palletCode);
+        Task<List<PalletPickedInfoDto>> GetPalletPickedList(string orderNo, string palletCode);
+        Task<PalletStatusDto> GetPalletStatus(string orderNo, string palletCode);
+        Task<SplitPackageInfoDto> GetSplitPackageInfo(string orderNo, string palletCode, string barcode);
         Task<WebResponseContent> ManualSplitPackage(string orderNo, string palletCode, string originalBarcode, decimal splitQuantity);
+        Task<WebResponseContent> RemoveEmptyPallet(string orderNo, string palletCode);
     }
 }
\ No newline at end of file
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs"
index 43c9e48..2b3b106 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs"
@@ -48,6 +48,8 @@
 
         WebResponseContent GenerateOutboundTask(int orderDetailId, List<StockSelectViewDTO> stockSelectViews);
 
+        Task<WebResponseContent> GenerateOutboundBatchTasksAsync(int orderDetailId, decimal batchQuantity, string outStation);
+
 
     }
 }
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_PickingRecord.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_PickingRecord.cs"
index 7344ede..2d6a2fa 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_PickingRecord.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_PickingRecord.cs"
@@ -122,6 +122,28 @@
        public decimal StockBeforeSplit { get; set; }
         public decimal AssignBeforeSplit { get; set; }
     }
- 
+
+
+    /// <summary>
+    /// 绌虹鍙栬蛋璁板綍琛�
+    /// </summary>
+    public class Dt_EmptyPalletRemoval
+    {
+        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
+        public int Id { get; set; }
+
+        public string OrderNo { get; set; }
+
+        public string PalletCode { get; set; }
+
+        public DateTime RemovalTime { get; set; }
+
+        public string Operator { get; set; }
+
+        public int CompletedItemsCount { get; set; }
+
+        public decimal TotalPickedQuantity { get; set; }
+    }
+
 
 }
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundBatchPickingService.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundBatchPickingService.cs"
index 2b85d56..bbd2251 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundBatchPickingService.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundBatchPickingService.cs"
@@ -6,11 +6,13 @@
 using System.Text;
 using System.Threading.Tasks;
 using WIDESEA_BasicService;
+using WIDESEA_Common.CommonEnum;
 using WIDESEA_Common.OrderEnum;
 using WIDESEA_Common.StockEnum;
 using WIDESEA_Core;
 using WIDESEA_Core.BaseRepository;
 using WIDESEA_Core.BaseServices;
+using WIDESEA_DTO.Outbound;
 using WIDESEA_IAllocateService;
 using WIDESEA_IBasicService;
 using WIDESEA_IOutboundService;
@@ -18,6 +20,7 @@
 using WIDESEA_Model.Models;
 using WIDESEA_Model.Models.Basic;
 using WIDESEA_Model.Models.Outbound;
+using static WIDESEA_OutboundService.OutboundBatchPickingService;
 
 namespace WIDESEA_OutboundService
 {
@@ -61,7 +64,7 @@
         public OutboundBatchPickingService(IRepository<Dt_PickingRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, IStockService stockService,
             IOutStockLockInfoService outStockLockInfoService, IStockInfoDetailService stockInfoDetailService, ILocationInfoService locationInfoService,
             IOutboundOrderDetailService outboundOrderDetailService, ISplitPackageService splitPackageService, IOutboundOrderService outboundOrderService,
-            IRepository<Dt_Task> taskRepository, IESSApiService eSSApiService, ILogger<OutboundPickingService> logger, IInvokeMESService invokeMESService, IDailySequenceService dailySequenceService, IAllocateService allocateService) : base(BaseDal)
+            IRepository<Dt_Task> taskRepository, IESSApiService eSSApiService, ILogger<OutboundPickingService> logger, IInvokeMESService invokeMESService, IDailySequenceService dailySequenceService, IAllocateService allocateService, IRepository<Dt_OutboundBatch> outboundBatchRepository) : base(BaseDal)
         {
             _unitOfWorkManage = unitOfWorkManage;
             _stockInfoService = stockInfoService;
@@ -78,9 +81,341 @@
             _invokeMESService = invokeMESService;
             _dailySequenceService = dailySequenceService;
             _allocateService = allocateService;
+            _outboundBatchRepository = outboundBatchRepository;
         }
 
+        // <summary>
+        /// 鑾峰彇鎵樼洏鐨勯攣瀹氫俊鎭�
+        /// </summary>
+        public async Task<List<PalletLockInfoDto>> GetPalletLockInfos(string orderNo, string palletCode)
+        {
+            var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                  .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode)
+                  .Select(x => new
+                  {
+                      x.Id,
+                      x.OrderNo,
+                      x.BatchNo,
+                      x.MaterielCode,
+                      x.CurrentBarcode,
+                      x.AssignQuantity,
+                      x.PickedQty,
+                      x.Status,
+                      x.LocationCode,
+                      x.PalletCode
+                  }).ToListAsync();
 
+            var lockInfoDtos = lockInfos.Select(x => new PalletLockInfoDto
+            {
+                Id = x.Id,
+                OrderNo = x.OrderNo,
+                BatchNo = x.BatchNo,
+                MaterielCode = x.MaterielCode,
+                CurrentBarcode = x.CurrentBarcode,
+                AssignQuantity = x.AssignQuantity,
+                PickedQty = x.PickedQty,
+                Status = x.Status,
+                LocationCode = x.LocationCode,
+                PalletCode = x.PalletCode,
+                CanSplit = (x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓� && x.AssignQuantity - x.PickedQty > 0),
+                CanPick = (x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓� && x.PickedQty < x.AssignQuantity)
+            }).ToList();
+
+            return lockInfoDtos;
+        }
+        #region 鏌ヨ鏂规硶
+
+        /// <summary>
+        /// 鑾峰彇鎵樼洏鐨勫凡鎷i�夊垪琛�
+        /// </summary>
+        public async Task<List<PalletPickedInfoDto>> GetPalletPickedList(string orderNo, string palletCode)
+        {
+            var pickedList = await Db.Queryable<Dt_PickingRecord>()
+                .Where(x => x.OrderNo == orderNo &&
+                           x.PalletCode == palletCode &&
+                           !x.IsCancelled)
+                .Select(x => new PalletPickedInfoDto
+                {
+                    Id = x.Id,
+                    OrderNo = x.OrderNo,
+                    OrderDetailId = x.OrderDetailId,
+                    PalletCode = x.PalletCode,
+                    Barcode = x.Barcode,
+                    MaterielCode = x.MaterielCode,
+                    PickedQty = x.PickQuantity,
+                    PickTime = x.PickTime,
+                    Operator = x.Operator,
+                    LocationCode = x.LocationCode
+                })
+                .ToListAsync();
+
+            return pickedList;
+        }
+
+        /// <summary>
+        /// 鑾峰彇鎵樼洏鐘舵��
+        /// </summary>
+        public async Task<PalletStatusDto> GetPalletStatus(string orderNo, string palletCode)
+        {
+            // 鑾峰彇鎵樼洏鐨勯攣瀹氫俊鎭�
+            var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode)
+                .ToListAsync();
+
+            if (!lockInfos.Any())
+            {
+                return new PalletStatusDto
+                {
+                    OrderNo = orderNo,
+                    PalletCode = palletCode,
+                    Status = (int)PalletStatusEnum.鏃犱换鍔�,
+                    StatusText = "鏃犱换鍔�",
+                    TotalItems = 0,
+                    CompletedItems = 0,
+                    PendingItems = 0
+                };
+            }
+
+            var totalItems = lockInfos.Count;
+            var completedItems = lockInfos.Count(x => x.Status == (int)OutLockStockStatusEnum.鎷i�夊畬鎴�);
+            var pendingItems = lockInfos.Count(x => x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�);
+
+            var status = PalletStatusEnum.鎷i�変腑;
+            if (pendingItems == 0 && completedItems > 0)
+            {
+                status = PalletStatusEnum.宸插畬鎴�;
+            }
+            else if (pendingItems > 0 && completedItems == 0)
+            {
+                status = PalletStatusEnum.鏈紑濮�;
+            }
+            else if (pendingItems > 0 && completedItems > 0)
+            {
+                status = PalletStatusEnum.鎷i�変腑;
+            }
+
+            return new PalletStatusDto
+            {
+                OrderNo = orderNo,
+                PalletCode = palletCode,
+                Status = (int)status,
+                StatusText = GetPalletStatusText(status),
+                TotalItems = totalItems,
+                CompletedItems = completedItems,
+                PendingItems = pendingItems
+            };
+        }
+
+        /// <summary>
+        /// 鑾峰彇鎷嗗寘淇℃伅
+        /// </summary>
+        public async Task<SplitPackageInfoDto> GetSplitPackageInfo(string orderNo, string palletCode, string barcode)
+        {
+            // 鏌ユ壘閿佸畾淇℃伅
+            var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(x => x.OrderNo == orderNo &&
+                           x.PalletCode == palletCode &&
+                           x.CurrentBarcode == barcode
+                        //&& x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�
+                          )
+                .FirstAsync();
+
+            if (lockInfo == null)
+                throw new Exception("鏈壘鍒版湁鏁堢殑閿佸畾淇℃伅");
+
+            // 璁$畻鍓╀綑鍙媶鏁伴噺
+            var remainQuantity = lockInfo.AssignQuantity - lockInfo.PickedQty;
+
+            return new SplitPackageInfoDto
+            {
+                OrderNo = orderNo,
+                PalletCode = palletCode,
+                Barcode = barcode,
+                MaterielCode = lockInfo.MaterielCode,
+                RemainQuantity = remainQuantity,
+                AssignQuantity = lockInfo.AssignQuantity,
+                PickedQty = lockInfo.PickedQty
+            };
+        }
+
+        #endregion
+
+        #region 鍙栬蛋绌虹閫昏緫
+
+        /// <summary>
+        /// 鍙栬蛋绌虹 - 娓呯悊宸插畬鎴愭嫞閫夌殑鎵樼洏鏁版嵁
+        /// </summary>
+        public async Task<WebResponseContent> RemoveEmptyPallet(string orderNo, string palletCode)
+        {
+            try
+            {
+                _unitOfWorkManage.BeginTran();
+
+                //  楠岃瘉鎵樼洏鏄惁鍙互鍙栬蛋锛堝繀椤诲叏閮ㄥ畬鎴愭嫞閫夛級
+                var validationResult = await ValidateEmptyPalletRemoval(orderNo, palletCode);
+                if (!validationResult.IsValid)
+                    return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
+
+                var completedLocks = validationResult.Data;
+
+                // 娓呯悊閿佸畾璁板綍锛堟爣璁颁负宸插畬鎴愶級
+                await CleanupCompletedLocks(completedLocks);
+
+                // 鏇存柊鐩稿叧璁㈠崟鐘舵��
+                await UpdateOrderStatusAfterPalletRemoval(orderNo);
+
+                //  璁板綍鎿嶄綔鍘嗗彶
+                // await RecordEmptyPalletRemoval(orderNo, palletCode, completedLocks);
+
+                _unitOfWorkManage.CommitTran();
+
+                return WebResponseContent.Instance.OK("鍙栬蛋绌虹鎴愬姛");
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                _logger.LogError($"鍙栬蛋绌虹澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error($"鍙栬蛋绌虹澶辫触锛歿ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 楠岃瘉绌虹鍙栬蛋鏉′欢
+        /// </summary>
+        private async Task<ValidationResult<List<Dt_OutStockLockInfo>>> ValidateEmptyPalletRemoval(string orderNo, string palletCode)
+        {
+            // 鑾峰彇鎵樼洏鐨勬墍鏈夐攣瀹氳褰�
+            var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode)
+                .ToListAsync();
+
+            if (!lockInfos.Any())
+                return ValidationResult<List<Dt_OutStockLockInfo>>.Error("璇ユ墭鐩樻病鏈夐攣瀹氳褰�");
+
+            // 妫�鏌ユ槸鍚︽湁鏈畬鎴愮殑閿佸畾璁板綍
+            var unfinishedLocks = lockInfos.Where(x =>
+                x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓� ||
+                x.Status == (int)OutLockStockStatusEnum.鍥炲簱涓�).ToList();
+
+            if (unfinishedLocks.Any())
+            {
+                var unfinishedCount = unfinishedLocks.Count;
+                var unfinishedQty = unfinishedLocks.Sum(x => x.AssignQuantity - x.PickedQty);
+                return ValidationResult<List<Dt_OutStockLockInfo>>.Error(
+                    $"鎵樼洏杩樻湁{unfinishedCount}鏉℃湭瀹屾垚璁板綍锛屽墿浣欐暟閲弡unfinishedQty}锛屼笉鑳藉彇璧扮┖绠�");
+            }
+
+            // 鑾峰彇宸插畬鎴愮殑閿佸畾璁板綍
+            var completedLocks = lockInfos.Where(x =>
+                x.Status == (int)OutLockStockStatusEnum.鎷i�夊畬鎴�).ToList();
+
+            if (!completedLocks.Any())
+                return ValidationResult<List<Dt_OutStockLockInfo>>.Error("璇ユ墭鐩樻病鏈夊凡瀹屾垚鎷i�夌殑璁板綍");
+
+            return ValidationResult<List<Dt_OutStockLockInfo>>.Success(completedLocks);
+        }
+
+        /// <summary>
+        /// 娓呯悊宸插畬鎴愮殑閿佸畾璁板綍
+        /// </summary>
+        private async Task CleanupCompletedLocks(List<Dt_OutStockLockInfo> completedLocks)
+        {
+            foreach (var lockInfo in completedLocks)
+            {
+                // 鏍囪閿佸畾璁板綍涓哄凡鍙栬蛋锛堝彲浠ユ柊澧炵姸鎬佹垨鐩存帴鍒犻櫎锛屾牴鎹笟鍔¢渶姹傦級
+                // 杩欓噷鎴戜滑灏嗗叾鐘舵�佹洿鏂颁负"宸插彇璧�"锛屽苟璁板綍鍙栬蛋鏃堕棿
+                lockInfo.Status = (int)OutLockStockStatusEnum.宸插彇璧�;
+                lockInfo.Operator = App.User.UserName;
+                await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
+
+                // 鍚屾椂娓呯悊瀵瑰簲鐨勫簱瀛樿褰曠姸鎬�
+                await CleanupStockInfo(lockInfo);
+            }
+        }
+
+        /// <summary>
+        /// 娓呯悊搴撳瓨淇℃伅
+        /// </summary>
+        private async Task CleanupStockInfo(Dt_OutStockLockInfo lockInfo)
+        {
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .FirstAsync(x => x.Barcode == lockInfo.CurrentBarcode && x.StockId == lockInfo.StockId);
+
+            if (stockDetail != null)
+            {
+                // 濡傛灉搴撳瓨宸茬粡鍑哄簱瀹屾垚锛屾爣璁颁负宸叉竻鐞�
+                if (stockDetail.Status == (int)StockStatusEmun.鍑哄簱瀹屾垚)
+                {
+                    stockDetail.Status = (int)StockStatusEmun.宸叉竻鐞�;
+                    await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+                }
+            }
+        }
+
+        /// <summary>
+        /// 鏇存柊璁㈠崟鐘舵��
+        /// </summary>
+        private async Task UpdateOrderStatusAfterPalletRemoval(string orderNo)
+        {
+            // 妫�鏌ヨ鍗曟槸鍚︽墍鏈夋墭鐩橀兘宸插畬鎴�
+            var allLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(x => x.OrderNo == orderNo)
+                .ToListAsync();
+
+            var unfinishedPallets = allLocks
+                .GroupBy(x => x.PalletCode)
+                .Where(g => g.Any(x => x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓� ||
+                                      x.Status == (int)OutLockStockStatusEnum.鍥炲簱涓�))
+                .ToList();
+
+            // 濡傛灉娌℃湁鏈畬鎴愮殑鎵樼洏锛屾洿鏂拌鍗曠姸鎬佷负鍑哄簱瀹屾垚
+            if (!unfinishedPallets.Any())
+            {
+                await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
+                    .SetColumns(x => new Dt_OutboundOrder
+                    {
+                        OrderStatus = (int)OutOrderStatusEnum.鍑哄簱瀹屾垚,
+                    })
+                    .Where(x => x.OrderNo == orderNo)
+                    .ExecuteCommandAsync();
+            }
+        }
+
+        /// <summary>
+        /// 璁板綍绌虹鍙栬蛋鍘嗗彶
+        /// </summary>
+        private async Task RecordEmptyPalletRemoval(string orderNo, string palletCode, List<Dt_OutStockLockInfo> completedLocks)
+        {
+            var removalRecord = new Dt_EmptyPalletRemoval
+            {
+                OrderNo = orderNo,
+                PalletCode = palletCode,
+                RemovalTime = DateTime.Now,
+                Operator = App.User.UserName,
+                CompletedItemsCount = completedLocks.Count,
+                TotalPickedQuantity = completedLocks.Sum(x => x.PickedQty)
+            };
+
+            await Db.Insertable(removalRecord).ExecuteCommandAsync();
+        }
+
+        #endregion
+
+        #region 杈呭姪鏂规硶
+
+        private string GetPalletStatusText(PalletStatusEnum status)
+        {
+            return status switch
+            {
+                PalletStatusEnum.鏈紑濮� => "鏈紑濮�",
+                PalletStatusEnum.鎷i�変腑 => "鎷i�変腑",
+                PalletStatusEnum.宸插畬鎴� => "宸插畬鎴�",
+                PalletStatusEnum.鏃犱换鍔� => "鏃犱换鍔�",
+                _ => "鏈煡"
+            };
+        }
+
+        #endregion
         #region 鍒嗘壒鍒嗘嫞
 
         /// <summary>
@@ -216,8 +551,10 @@
 
         #region 鍙栨秷鎷嗗寘
 
+        #region 鍙栨秷鎷嗗寘 - 淇鐗堟湰
+
         /// <summary>
-        /// 鍙栨秷鎷嗗寘
+        /// 鍙栨秷鎷嗗寘 - 鏀寔澶氭鎷嗗寘鐨勬儏鍐�
         /// </summary>
         public async Task<WebResponseContent> CancelSplitPackage(string orderNo, string palletCode, string newBarcode)
         {
@@ -225,15 +562,29 @@
             {
                 _unitOfWorkManage.BeginTran();
 
-                // 鏌ユ壘鎷嗗寘璁板綍骞堕獙璇�
+                // 1. 鏌ユ壘鎷嗗寘璁板綍骞堕獙璇�
                 var validationResult = await ValidateCancelSplitRequest(orderNo, palletCode, newBarcode);
                 if (!validationResult.IsValid)
                     return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
 
                 var (splitRecord, newLockInfo, newStockDetail) = validationResult.Data;
 
-                // 鎵ц鍙栨秷鎷嗗寘閫昏緫
-                await ExecuteCancelSplitLogic(splitRecord, newLockInfo, newStockDetail);
+                // 2. 鏌ユ壘鍘熷閿佸畾淇℃伅
+                var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                    .FirstAsync(x => x.Id == splitRecord.OutStockLockInfoId);
+
+                // 3. 妫�鏌ヨ鏉$爜鏄惁琚啀娆℃媶鍖�
+                var childSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
+                    .Where(x => x.OriginalBarcode == newBarcode && !x.IsReverted)
+                    .ToListAsync();
+
+                if (childSplitRecords.Any())
+                {
+                    return WebResponseContent.Instance.Error("璇ユ潯鐮佸凡琚啀娆℃媶鍖咃紝璇峰厛鍙栨秷鍚庣画鐨勬媶鍖呮搷浣�");
+                }
+
+                // 4. 鎵ц鍙栨秷鎷嗗寘閫昏緫
+                await ExecuteCancelSplitLogic(splitRecord, originalLockInfo, newLockInfo, newStockDetail);
 
                 _unitOfWorkManage.CommitTran();
 
@@ -242,10 +593,353 @@
             catch (Exception ex)
             {
                 _unitOfWorkManage.RollbackTran();
-                _logger.LogError($"鍙栨秷鎷嗗寘澶辫触 - OrderNo: {orderNo}, Barcode: {newBarcode}, Error: {ex.Message}");
+                _logger.LogError($"鍙栨秷鎷嗗寘澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Barcode: {newBarcode}, Error: {ex.Message}");
                 return WebResponseContent.Instance.Error($"鍙栨秷鎷嗗寘澶辫触锛歿ex.Message}");
             }
         }
+
+        /// <summary>
+        /// 鎵ц鍙栨秷鎷嗗寘閫昏緫 - 淇鐗堟湰
+        /// </summary>
+        private async Task ExecuteCancelSplitLogic(Dt_SplitPackageRecord splitRecord,
+            Dt_OutStockLockInfo originalLockInfo, Dt_OutStockLockInfo newLockInfo,
+            Dt_StockInfoDetail newStockDetail)
+        {
+            // 1. 鎭㈠鍘熼攣瀹氫俊鎭�
+            // 娉ㄦ剰锛氳繖閲岄渶瑕佺疮鍔狅紝鑰屼笉鏄畝鍗曠殑璧嬪�硷紝鍥犱负鍙兘鏈夊娆℃媶鍖�
+            originalLockInfo.AssignQuantity += splitRecord.SplitQty;
+            originalLockInfo.OrderQuantity += splitRecord.SplitQty;
+
+            // 濡傛灉鍘熼攣瀹氫俊鎭殑鐘舵�佹槸鎷i�夊畬鎴愶紝闇�瑕侀噸鏂拌缃负鍑哄簱涓�
+            if (originalLockInfo.Status == (int)OutLockStockStatusEnum.鎷i�夊畬鎴�)
+            {
+                originalLockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�;
+            }
+
+            await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync();
+
+            // 2. 鎭㈠鍘熷簱瀛樻槑缁�
+            var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == splitRecord.StockId);
+
+            originalStock.StockQuantity += splitRecord.SplitQty;
+
+            // 濡傛灉鍘熷簱瀛樼姸鎬佹槸鍑哄簱瀹屾垚锛岄渶瑕侀噸鏂拌缃负鍑哄簱閿佸畾
+            if (originalStock.Status == (int)StockStatusEmun.鍑哄簱瀹屾垚)
+            {
+                originalStock.Status = (int)StockStatusEmun.鍑哄簱閿佸畾;
+            }
+
+            await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync();
+
+            // 3. 鍒犻櫎鏂伴攣瀹氫俊鎭�
+            await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
+                .Where(x => x.Id == newLockInfo.Id)
+                .ExecuteCommandAsync();
+
+            // 4. 鍒犻櫎鏂板簱瀛樻槑缁�
+            await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
+                .Where(x => x.Barcode == newLockInfo.CurrentBarcode)
+                .ExecuteCommandAsync();
+
+            // 5. 鏍囪鎷嗗寘璁板綍涓哄凡鎾ら攢
+            splitRecord.IsReverted = true;
+            splitRecord.RevertTime = DateTime.Now;
+            splitRecord.RevertOperator = App.User.UserName;
+            await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync();
+
+            // 6. 妫�鏌ュ苟鏇存柊鎵规鍜岃鍗曠姸鎬�
+            await CheckAndUpdateBatchStatus(originalLockInfo.BatchNo);
+            await CheckAndUpdateOrderStatus(originalLockInfo.OrderNo);
+        }
+
+        /// <summary>
+        /// 楠岃瘉鍙栨秷鎷嗗寘璇锋眰 - 澧炲己鐗堟湰
+        /// </summary>
+        private async Task<ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateCancelSplitRequest(
+            string orderNo, string palletCode, string newBarcode)
+        {
+            // 鏌ユ壘鎷嗗寘璁板綍
+            var splitRecord = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
+                .Where(x => x.NewBarcode == newBarcode &&
+                           x.OrderNo == orderNo &&
+                           !x.IsReverted)
+                .FirstAsync();
+
+            if (splitRecord == null)
+                return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鏈壘鍒版媶鍖呰褰�");
+
+            // 鏌ユ壘鏂伴攣瀹氫俊鎭�
+            var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(x => x.CurrentBarcode == newBarcode &&
+                           x.PalletCode == palletCode &&
+                           x.OrderNo == orderNo)
+                .FirstAsync();
+
+            if (newLockInfo == null)
+                return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鏈壘鍒版柊閿佸畾淇℃伅");
+
+            // 妫�鏌ユ柊鏉$爜鏄惁宸茶鍒嗘嫞
+            var pickingRecord = await Db.Queryable<Dt_PickingRecord>()
+                .Where(x => x.Barcode == newBarcode && !x.IsCancelled)
+                .FirstAsync();
+
+            if (pickingRecord != null)
+                return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("璇ユ潯鐮佸凡琚垎鎷o紝鏃犳硶鍙栨秷鎷嗗寘");
+
+            // 妫�鏌ユ柊鏉$爜鏄惁琚啀娆℃媶鍖�
+            var childSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
+                .Where(x => x.OriginalBarcode == newBarcode && !x.IsReverted)
+                .ToListAsync();
+
+            if (childSplitRecords.Any())
+            {
+                var childBarcodes = string.Join(", ", childSplitRecords.Select(x => x.NewBarcode));
+                return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error(
+                    $"璇ユ潯鐮佸凡琚啀娆℃媶鍖咃紝鐢熸垚鐨勬柊鏉$爜锛歿childBarcodes}锛岃鍏堝彇娑堝悗缁媶鍖�");
+            }
+
+            var newStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .FirstAsync(x => x.Barcode == newBarcode);
+
+            return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((splitRecord, newLockInfo, newStockDetail));
+        }
+
+        #endregion
+
+        #region 鎵归噺鍙栨秷鎷嗗寘閾�
+
+        /// <summary>
+        /// 鎵归噺鍙栨秷鎷嗗寘閾� - 鍙栨秷鏌愪釜鏉$爜鍙婂叾鎵�鏈夊悗缁媶鍖�
+        /// </summary>
+        public async Task<WebResponseContent> CancelSplitPackageChain(string orderNo, string palletCode, string startBarcode)
+        {
+            try
+            {
+                _unitOfWorkManage.BeginTran();
+
+                // 1. 鏌ユ壘鎵�鏈夌浉鍏崇殑鎷嗗寘璁板綍锛堝舰鎴愭媶鍖呴摼锛�
+                var splitChain = await GetSplitPackageChain(orderNo, startBarcode);
+
+                if (!splitChain.Any())
+                    return WebResponseContent.Instance.Error("鏈壘鍒版媶鍖呰褰�");
+
+                // 2. 鎸夋媶鍖呴『搴忓�掑簭鍙栨秷锛堜粠鏈�鏂扮殑寮�濮嬪彇娑堬級
+                var reversedChain = splitChain.OrderByDescending(x => x.SplitTime).ToList();
+
+                foreach (var splitRecord in reversedChain)
+                {
+                    await CancelSingleSplitPackage(splitRecord, palletCode);
+                }
+
+                _unitOfWorkManage.CommitTran();
+
+                return WebResponseContent.Instance.OK($"鎴愬姛鍙栨秷鎷嗗寘閾撅紝鍏眥reversedChain.Count}娆℃媶鍖呮搷浣�");
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                _logger.LogError($"鍙栨秷鎷嗗寘閾惧け璐� - OrderNo: {orderNo}, StartBarcode: {startBarcode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error($"鍙栨秷鎷嗗寘閾惧け璐ワ細{ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 鑾峰彇鎷嗗寘閾� - 鏌ユ壘鏌愪釜鏉$爜鐨勬墍鏈夋媶鍖呰褰曪紙鍖呮嫭鍚庣画鎷嗗寘锛�
+        /// </summary>
+        public async Task<List<Dt_SplitPackageRecord>> GetSplitPackageChain(string orderNo, string startBarcode)
+        {
+            var allSplitRecords = new List<Dt_SplitPackageRecord>();
+            var visitedBarcodes = new HashSet<string>(); // 闃叉寰幆寮曠敤
+
+            // 浣跨敤闃熷垪杩涜骞垮害浼樺厛鎼滅储
+            var queue = new Queue<string>();
+            queue.Enqueue(startBarcode);
+            visitedBarcodes.Add(startBarcode);
+
+            while (queue.Count > 0)
+            {
+                var currentBarcode = queue.Dequeue();
+
+                // 鏌ユ壘浠ュ綋鍓嶆潯鐮佷负鍘熸潯鐮佺殑鎵�鏈夋媶鍖呰褰�
+                var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
+                    .Where(x => x.OriginalBarcode == currentBarcode &&
+                               x.OrderNo == orderNo &&
+                               !x.IsReverted)
+                    .ToListAsync();
+
+                foreach (var record in splitRecords)
+                {
+                    // 閬垮厤閲嶅澶勭悊
+                    if (!visitedBarcodes.Contains(record.NewBarcode))
+                    {
+                        allSplitRecords.Add(record);
+                        queue.Enqueue(record.NewBarcode);
+                        visitedBarcodes.Add(record.NewBarcode);
+                    }
+                }
+            }
+
+            return allSplitRecords;
+        }
+
+        /// <summary>
+        /// 鍙栨秷鍗曚釜鎷嗗寘璁板綍
+        /// </summary>
+        private async Task CancelSingleSplitPackage(Dt_SplitPackageRecord splitRecord, string palletCode)
+        {
+            // 鏌ユ壘鐩稿叧鏁版嵁
+            var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(x => x.CurrentBarcode == splitRecord.NewBarcode &&
+                           x.PalletCode == palletCode)
+                .FirstAsync();
+
+            var newStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .FirstAsync(x => x.Barcode == splitRecord.NewBarcode);
+
+            var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .FirstAsync(x => x.Id == splitRecord.OutStockLockInfoId);
+
+            // 鎵ц鍙栨秷閫昏緫
+            await ExecuteCancelSplitLogic(splitRecord, originalLockInfo, newLockInfo, newStockDetail);
+        }
+        #endregion
+
+        #region 鎷嗗寘淇℃伅鏌ヨ澧炲己
+
+        /// <summary>
+        /// 鑾峰彇鎷嗗寘閾句俊鎭�
+        /// </summary>
+        public async Task<WebResponseContent> GetSplitPackageChainInfo(string orderNo, string barcode)
+        {
+            try
+            {
+                var splitChain = await GetSplitPackageChain(orderNo, barcode);
+
+                var chainInfo = new SplitPackageChainInfoDto
+                {
+                    OriginalBarcode = barcode,
+                    TotalSplitTimes = splitChain.Count,
+                    SplitChain = splitChain.Select(x => new SplitChainItemDto
+                    {
+                        SplitTime = x.SplitTime,
+                        OriginalBarcode = x.OriginalBarcode,
+                        NewBarcode = x.NewBarcode,
+                        SplitQuantity = x.SplitQty,
+                        Operator = x.Operator,
+                        IsReverted = x.IsReverted
+                    }).ToList()
+                };
+
+                return WebResponseContent.Instance.OK("鑾峰彇鎴愬姛", chainInfo);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError($"鑾峰彇鎷嗗寘閾句俊鎭け璐� - OrderNo: {orderNo}, Barcode: {barcode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error("鑾峰彇鎷嗗寘閾句俊鎭け璐�");
+            }
+        }
+
+
+        /// <summary>
+        /// 鏌ユ壘鏍规潯鐮�
+        /// </summary>
+        public async Task<string> FindRootBarcode(string orderNo, string startBarcode)
+        {
+            var currentBarcode = startBarcode;
+            var visited = new HashSet<string>();
+
+            while (!string.IsNullOrEmpty(currentBarcode) && !visited.Contains(currentBarcode))
+            {
+                visited.Add(currentBarcode);
+
+                // 鏌ユ壘褰撳墠鏉$爜鏄惁鏄敱鍏朵粬鏉$爜鎷嗗寘鑰屾潵
+                var parentRecord = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
+                    .Where(x => x.NewBarcode == currentBarcode &&
+                               x.OrderNo == orderNo &&
+                               !x.IsReverted)
+                    .FirstAsync();
+
+                if (parentRecord == null)
+                {
+                    // 娌℃湁鐖剁骇鎷嗗寘璁板綍锛岃鏄庤繖鏄牴鏉$爜
+                    return currentBarcode;
+                }
+
+                currentBarcode = parentRecord.OriginalBarcode;
+            }
+
+            // 濡傛灉鍑虹幇寰幆寮曠敤锛岃繑鍥炶捣濮嬫潯鐮�
+            return startBarcode;
+        }
+        #endregion
+
+        #region 鏇存柊鎵规鐘舵�佹鏌�
+
+        /// <summary>
+        /// 妫�鏌ュ苟鏇存柊鎵规鐘舵��
+        /// </summary>
+        private async Task CheckAndUpdateBatchStatus(string batchNo)
+        {
+            var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>()
+                .FirstAsync(x => x.BatchNo == batchNo);
+
+            if (batch != null)
+            {
+                // 閲嶆柊璁$畻鎵规瀹屾垚鏁伴噺
+                var batchLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                    .Where(x => x.BatchNo == batchNo)
+                    .ToListAsync();
+
+                var completedQuantity = batchLocks.Where(x => x.Status == (int)OutLockStockStatusEnum.鎷i�夊畬鎴�)
+                                                 .Sum(x => x.PickedQty);
+
+                batch.CompletedQuantity = completedQuantity;
+
+                // 鏇存柊鎵规鐘舵��
+                if (batch.CompletedQuantity >= batch.BatchQuantity)
+                {
+                    batch.BatchStatus = (int)BatchStatusEnum.宸插畬鎴�;
+                }
+                else if (batch.CompletedQuantity > 0)
+                {
+                    batch.BatchStatus = (int)BatchStatusEnum.鎵ц涓�;
+                }
+                else
+                {
+                    batch.BatchStatus = (int)BatchStatusEnum.鍒嗛厤涓�;
+                }
+
+                await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync();
+            }
+        }
+
+        #endregion
+
+        #region DTO绫�
+
+      
+
+        public class SplitPackageChainInfoDto
+        {
+            public string OriginalBarcode { get; set; }
+            public string RootBarcode { get; set; } // 鏂板锛氭牴鏉$爜
+            public int TotalSplitTimes { get; set; }
+            public string ChainType { get; set; } // "root" 鎴� "branch"
+            public List<SplitChainItemDto> SplitChain { get; set; }
+        }
+
+        public class SplitChainItemDto
+        {
+            public DateTime SplitTime { get; set; }
+            public string OriginalBarcode { get; set; }
+            public string NewBarcode { get; set; }
+            public decimal SplitQuantity { get; set; }
+            public string Operator { get; set; }
+            public bool IsReverted { get; set; }
+        }
+
+        #endregion
 
         #endregion
 
@@ -337,11 +1031,11 @@
                     $"搴撳瓨鏁伴噺涓嶈冻锛岄渶瑕侊細{lockInfo.AssignQuantity}锛屽疄闄咃細{stockDetail.StockQuantity}");
 
             var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>()
-                .FirstAsync(x => x.BatchNo == lockInfo.BatchNo);
+                .FirstAsync(x => x.BatchNo == lockInfo.OutboundBatchNo);
 
             return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Success((lockInfo, orderDetail, stockDetail, batch));
         }
- 
+
         private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateSplitRequest(
             string orderNo, string palletCode, string originalBarcode, decimal splitQuantity)
         {
@@ -366,42 +1060,7 @@
 
             return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((lockInfo, stockDetail));
         }
-
-        private async Task<ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateCancelSplitRequest(
-            string orderNo, string palletCode, string newBarcode)
-        {
-            var splitRecord = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
-                .Where(x => x.NewBarcode == newBarcode &&
-                           x.OrderNo == orderNo &&
-                           !x.IsReverted)
-                .FirstAsync();
-
-            if (splitRecord == null)
-                return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鏈壘鍒版媶鍖呰褰�");
-
-            var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .Where(x => x.CurrentBarcode == newBarcode &&
-                           x.PalletCode == palletCode &&
-                           x.OrderNo == orderNo)
-                .FirstAsync();
-
-            if (newLockInfo == null)
-                return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鏈壘鍒版柊閿佸畾淇℃伅");
-
-            // 妫�鏌ユ柊鏉$爜鏄惁宸茶鍒嗘嫞
-            var pickingRecord = await Db.Queryable<Dt_PickingRecord>()
-                .Where(x => x.Barcode == newBarcode && !x.IsCancelled)
-                .FirstAsync();
-
-            if (pickingRecord != null)
-                return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("璇ユ潯鐮佸凡琚垎鎷o紝鏃犳硶鍙栨秷鎷嗗寘");
-
-            var newStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                .FirstAsync(x => x.Barcode == newBarcode);
-
-            return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((splitRecord, newLockInfo, newStockDetail));
-        }
-
+ 
         #endregion
 
         #region 鏍稿績閫昏緫鏂规硶
@@ -479,7 +1138,13 @@
                 Barcode = newBarcode,
                 Status = (int)StockStatusEmun.鍑哄簱閿佸畾,
                 SupplyCode = stockDetail.SupplyCode,
-                Unit = stockDetail.Unit
+                Unit = stockDetail.Unit,
+                BarcodeQty=stockDetail.BarcodeQty,
+                BarcodeUnit=stockDetail.BarcodeUnit,
+                BusinessType=stockDetail.BusinessType,
+                InboundOrderRowNo=stockDetail.InboundOrderRowNo,
+                
+               
             };
             await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
 
@@ -487,23 +1152,39 @@
             stockDetail.StockQuantity -= splitQuantity;
             await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
 
-            // 鍒涘缓鏂伴攣瀹氫俊鎭�
+           
             var newLockInfo = new Dt_OutStockLockInfo
             {
                 OrderNo = lockInfo.OrderNo,
                 OrderDetailId = lockInfo.OrderDetailId,
-                OutboundBatchNo = lockInfo.OutboundBatchNo,
+                BatchNo = lockInfo.BatchNo,
                 MaterielCode = lockInfo.MaterielCode,
+                MaterielName = lockInfo.MaterielName,
                 StockId = lockInfo.StockId,
                 OrderQuantity = splitQuantity,
+                //OriginalQuantity = quantity,
                 AssignQuantity = splitQuantity,
                 PickedQty = 0,
                 LocationCode = lockInfo.LocationCode,
-                PalletCode = palletCode,
+                PalletCode = lockInfo.PalletCode,
+                TaskNum = lockInfo.TaskNum,
                 Status = (int)OutLockStockStatusEnum.鍑哄簱涓�,
+                Unit = lockInfo.Unit,
+                SupplyCode = lockInfo.SupplyCode,
+                OrderType = lockInfo.OrderType,
                 CurrentBarcode = newBarcode,
+               // OriginalLockQuantity = quantity,
+                IsSplitted = 1,
+                ParentLockId = lockInfo.Id,
                 Operator = App.User.UserName,
+                FactoryArea = lockInfo.FactoryArea,
+                lineNo = lockInfo.lineNo,
+                WarehouseCode = lockInfo.WarehouseCode,
+                BarcodeQty = lockInfo.BarcodeQty,
+                BarcodeUnit = lockInfo.BarcodeUnit,
+               
             };
+
             await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync();
 
             // 鏇存柊鍘熼攣瀹氫俊鎭�
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs"
index cdf54d8..141197b 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs"
@@ -95,7 +95,7 @@
 
         public List<int> TaskOutboundTypes => typeof(TaskTypeEnum).GetEnumIndexList();
 
-        public TaskService(IRepository<Dt_Task> BaseDal, IMapper mapper, IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_StockInfo> stockRepository, ILocationInfoService locationInfoService, IInboundOrderService inboundOrderService, ILocationStatusChangeRecordService locationStatusChangeRecordService, IESSApiService eSSApiService, ILogger<TaskService> logger, IStockService stockService, IRecordService recordService, IInboundOrderDetailService inboundOrderDetailService, IOutboundOrderService outboundOrderService, IOutboundOrderDetailService outboundOrderDetailService, IInvokeMESService invokeMESService, IOutStockLockInfoService outStockLockInfoService, IAllocateService allocateService) : base(BaseDal)
+        public TaskService(IRepository<Dt_Task> BaseDal, IMapper mapper, IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_StockInfo> stockRepository, ILocationInfoService locationInfoService, IInboundOrderService inboundOrderService, ILocationStatusChangeRecordService locationStatusChangeRecordService, IESSApiService eSSApiService, ILogger<TaskService> logger, IStockService stockService, IRecordService recordService, IInboundOrderDetailService inboundOrderDetailService, IOutboundOrderService outboundOrderService, IOutboundOrderDetailService outboundOrderDetailService, IInvokeMESService invokeMESService, IOutStockLockInfoService outStockLockInfoService, IAllocateService allocateService, IRepository<Dt_OutboundBatch> outboundBatchRepository) : base(BaseDal)
         {
             _mapper = mapper;
             _unitOfWorkManage = unitOfWorkManage;
@@ -113,6 +113,7 @@
             _invokeMESService = invokeMESService;
             _outStockLockInfoService = outStockLockInfoService;
             _allocateService = allocateService;
+            _OutboundBatchRepository = outboundBatchRepository;
         }
 
 
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_Outbound.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_Outbound.cs"
index d68097a..0cf697c 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_Outbound.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_Outbound.cs"
@@ -637,7 +637,7 @@
         /// <summary>
         /// 鍒嗘壒鍒嗛厤搴撳瓨
         /// </summary>
-        public async Task<WebResponseContent> BatchAllocateStock(string orderNo, int orderDetailId, decimal batchQuantity, string outStation)
+        public async Task<WebResponseContent> GenerateOutboundBatchTasksAsync(int orderDetailId, decimal batchQuantity, string outStation) 
         {
             try
             {
@@ -647,7 +647,7 @@
                 List<Dt_OutStockLockInfo> outStockLockInfos = new List<Dt_OutStockLockInfo>();
                 List<Dt_LocationInfo> locationInfos = new List<Dt_LocationInfo>();
 
-                (List<Dt_Task>, List<Dt_StockInfo>?, List<Dt_OutboundOrderDetail>?, List<Dt_OutStockLockInfo>?, List<Dt_LocationInfo>?) result = await BatchAllocateStockDataHandle(orderNo, orderDetailId, batchQuantity, outStation);
+                (List<Dt_Task>, List<Dt_StockInfo>?, List<Dt_OutboundOrderDetail>?, List<Dt_OutStockLockInfo>?, List<Dt_LocationInfo>?) result = await BatchAllocateStockDataHandle(orderDetailId, batchQuantity, outStation);
 
                 if (result.Item2 != null && result.Item2.Count > 0)
                 {
@@ -676,7 +676,7 @@
             catch (Exception ex)
             {
                 _unitOfWorkManage.RollbackTran();
-                _logger.LogError($"鍒嗘壒鍒嗛厤搴撳瓨澶辫触 - OrderNo: {orderNo}, OrderDetailId: {orderDetailId}, Quantity: {batchQuantity}, Error: {ex.Message}");
+                _logger.LogError($"鍒嗘壒鍒嗛厤搴撳瓨澶辫触 -  OrderDetailId: {orderDetailId}, Quantity: {batchQuantity}, Error: {ex.Message}");
                 return WebResponseContent.Instance.Error($"鍒嗘壒鍒嗛厤澶辫触锛歿ex.Message}");
             }
         }
@@ -685,7 +685,7 @@
         /// 鍒嗘壒鍒嗛厤搴撳瓨鏁版嵁澶勭悊
         /// </summary>
         public async Task<(List<Dt_Task>, List<Dt_StockInfo>?, List<Dt_OutboundOrderDetail>?, List<Dt_OutStockLockInfo>?, List<Dt_LocationInfo>?)>
-            BatchAllocateStockDataHandle(string orderNo, int orderDetailId, decimal batchQuantity, string outStation)
+            BatchAllocateStockDataHandle( int orderDetailId, decimal batchQuantity, string outStation)
         {
             List<Dt_Task> tasks = new List<Dt_Task>();
 
@@ -697,7 +697,11 @@
             {
                 throw new Exception("鏈壘鍒板嚭搴撳崟鏄庣粏淇℃伅");
             }
-
+            var  outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>().FirstAsync(x => x.Id == outboundOrderDetail.OrderId);
+            if(outboundOrder == null)
+            {
+                throw new Exception("鏈壘鍒板嚭搴撳崟淇℃伅");
+            }
             // 楠岃瘉璁㈠崟鏄庣粏鐘舵��
             if (outboundOrderDetail.OrderDetailStatus > OrderDetailStatusEnum.New.ObjToInt() &&
                 outboundOrderDetail.OrderDetailStatus != OrderDetailStatusEnum.AssignOverPartial.ObjToInt())
@@ -732,9 +736,8 @@
             if (allocateResult.Item1 != null && allocateResult.Item1.Count > 0)
             {
                 // 鍒涘缓鍒嗘壒璁板綍
-                await CreateBatchRecord(orderNo, orderDetailId, batchQuantity, batchNo);
-
-                Dt_OutboundOrder outboundOrder = await _outboundOrderService.Repository.QueryFirstAsync(x => x.Id == outboundOrderDetail.OrderId);
+                await CreateBatchRecord(outboundOrder.OrderNo, orderDetailId, batchQuantity, batchNo);
+ 
                 TaskTypeEnum typeEnum = outboundOrder.OrderType switch
                 {
                     (int)OutOrderTypeEnum.Issue => TaskTypeEnum.Outbound,
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/OutboundBatchPickingController.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/OutboundBatchPickingController.cs"
index f481cc3..563ca1d 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/OutboundBatchPickingController.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/OutboundBatchPickingController.cs"
@@ -1,7 +1,10 @@
 锘縰sing Microsoft.AspNetCore.Mvc;
+using WIDESEA_Core;
 using WIDESEA_Core.BaseController;
+using WIDESEA_DTO.Outbound;
 using WIDESEA_IOutboundService;
 using WIDESEA_Model.Models;
+using static WIDESEA_OutboundService.OutboundBatchPickingService;
 
 namespace WIDESEA_WMSServer.Controllers.Outbound
 {
@@ -12,10 +15,203 @@
     {
         private readonly ISplitPackageService _splitPackageService;
         private readonly IOutStockLockInfoService _outStockLockInfoService;
-        public OutboundBatchPickingController(IOutboundBatchPickingService service, ISplitPackageService splitPackageService, IOutStockLockInfoService outStockLockInfoService) : base(service)
+        private readonly IOutboundBatchPickingService _outboundBatchPickingService;
+
+        private readonly ILogger<OutboundBatchPickingController> _logger;
+        public OutboundBatchPickingController(IOutboundBatchPickingService service, ISplitPackageService splitPackageService, IOutStockLockInfoService outStockLockInfoService, IOutboundBatchPickingService outboundBatchPickingService, ILogger<OutboundBatchPickingController> logger) : base(service)
         {
             _splitPackageService = splitPackageService;
             _outStockLockInfoService = outStockLockInfoService;
+            _outboundBatchPickingService = outboundBatchPickingService;
+            _logger = logger;
+        }
+
+        /// <summary>
+        /// 鍒嗘嫞纭
+        /// </summary>
+        [HttpPost("confirm-picking")]
+        public async Task<WebResponseContent> ConfirmPicking([FromBody] ConfirmPickingDto dto)
+        {
+            return await _outboundBatchPickingService.ConfirmBatchPicking(dto.OrderNo, dto.PalletCode, dto.Barcode);
+        }
+
+        /// <summary>
+        /// 鍙栨秷鍒嗘嫞
+        /// </summary>
+        [HttpPost("cancel-picking")]
+        public async Task<WebResponseContent> CancelPicking([FromBody] CancelPickingDto dto)
+        {
+            return await _outboundBatchPickingService.CancelPicking(dto.OrderNo, dto.PalletCode, dto.Barcode);
+        }
+        /// <summary>
+        /// 鍙栨秷鎷嗗寘閾�
+        /// </summary>
+        [HttpPost("cancel-split-chain")]
+        public async Task<WebResponseContent> CancelSplitChain([FromBody] CancelSplitChainDto dto)
+        {
+            return await _outboundBatchPickingService.CancelSplitPackageChain(dto.OrderNo, dto.PalletCode, dto.StartBarcode);
+        }
+
+        /// <summary>
+        /// 鑾峰彇鎷嗗寘閾句俊鎭�
+        /// </summary>
+        [HttpPost("split-package-chain-info")]
+        public async Task<WebResponseContent> GetSplitPackageChainInfo([FromBody] SplitPackageChainInfoRequestDto dto)
+        {
+            return await _outboundBatchPickingService.GetSplitPackageChainInfo(dto.OrderNo, dto.Barcode);
+        }
+        /// <summary>
+        /// 鏌ユ壘瀹屾暣鎷嗗寘閾撅紙浠庢牴鏉$爜寮�濮嬶級
+        /// </summary>
+        [HttpPost("find-root-split-chain")]
+        public async Task<WebResponseContent> FindRootSplitChain([FromBody] SplitPackageChainInfoRequestDto dto)
+        {
+            try
+            {
+                // 鏌ユ壘鏍规潯鐮�
+                var rootBarcode = await _outboundBatchPickingService. FindRootBarcode(dto.OrderNo, dto.Barcode);
+
+                // 鑾峰彇瀹屾暣鎷嗗寘閾�
+                var splitChain = await _outboundBatchPickingService.GetSplitPackageChain(dto.OrderNo, rootBarcode);
+
+                var chainInfo = new SplitPackageChainInfoDto
+                {
+                    OriginalBarcode = rootBarcode,
+                    RootBarcode = rootBarcode,
+                    TotalSplitTimes = splitChain.Count,
+                    ChainType = "root",
+                    SplitChain = splitChain.Select(x => new SplitChainItemDto
+                    {
+                        SplitTime = x.SplitTime,
+                        OriginalBarcode = x.OriginalBarcode,
+                        NewBarcode = x.NewBarcode,
+                        SplitQuantity = x.SplitQty,
+                        Operator = x.Operator,
+                        IsReverted = x.IsReverted
+                    }).ToList()
+                };
+
+                return WebResponseContent.Instance.OK("鑾峰彇鎴愬姛", chainInfo);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError($"鏌ユ壘瀹屾暣鎷嗗寘閾惧け璐� - OrderNo: {dto.OrderNo}, Barcode: {dto.Barcode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error("鏌ユ壘瀹屾暣鎷嗗寘閾惧け璐�");
+            }
+        }
+        /// <summary>
+        /// 鎵嬪姩鎷嗗寘
+        /// </summary>
+        [HttpPost("split-package")]
+        public async Task<WebResponseContent> SplitPackage([FromBody] SplitPackageDto dto)
+        {
+            return await _outboundBatchPickingService.ManualSplitPackage(dto.OrderNo, dto.PalletCode, dto.OriginalBarcode, dto.SplitQuantity);
+        }
+        /// <summary>
+        /// 鍙栨秷鎷嗗寘
+        /// </summary>
+        [HttpPost("cancel-split")]
+        public async Task<WebResponseContent> CancelSplit([FromBody] CancelSplitDto dto)
+        {
+            return await _outboundBatchPickingService.CancelSplitPackage(dto.OrderNo, dto.PalletCode, dto.NewBarcode);
+        }
+
+        /// <summary>
+        /// 鍒嗘壒鍥炲簱
+        /// </summary>
+        [HttpPost("return-stock")]
+        public async Task<WebResponseContent> ReturnStock([FromBody] ReturnStockDto dto)
+        {
+            return await _outboundBatchPickingService.BatchReturnStock(dto.OrderNo, dto.PalletCode);
+        }
+
+        /// <summary>
+        /// 鑾峰彇鎵樼洏鐨勯攣瀹氫俊鎭�
+        /// </summary>
+        [HttpPost("pallet-locks")]
+        public async Task<WebResponseContent> GetPalletLocks([FromBody] PalletLocksDto dto)
+        {
+            try
+            {
+                var locks = await _outboundBatchPickingService.GetPalletLockInfos(dto.OrderNo, dto.PalletCode);
+                return WebResponseContent.Instance.OK("鑾峰彇鎴愬姛", locks);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, $"鑾峰彇鎵樼洏閿佸畾淇℃伅寮傚父 - OrderNo: {dto.OrderNo}, PalletCode: {dto.PalletCode}");
+                return WebResponseContent.Instance.Error("绯荤粺寮傚父锛岃绋嶅悗閲嶈瘯" + ex.Message);
+            }
+        }
+        /// <summary>
+        /// 鑾峰彇宸叉嫞閫夊垪琛�
+        /// </summary>
+        [HttpPost("pallet-picked-list")]
+        public async Task<WebResponseContent> GetPalletPickedList([FromBody] PalletLocksDto dto)
+        {
+            try
+            {
+                var pickedList = await _outboundBatchPickingService.GetPalletPickedList(dto.OrderNo, dto.PalletCode);
+                return WebResponseContent.Instance.OK("鑾峰彇鎴愬姛", pickedList);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, $"鑾峰彇宸叉嫞閫夊垪琛ㄥ紓甯� - OrderNo: {dto.OrderNo}, PalletCode: {dto.PalletCode}");
+                return WebResponseContent.Instance.Error("绯荤粺寮傚父锛岃绋嶅悗閲嶈瘯" + ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 鑾峰彇鎵樼洏鐘舵��
+        /// </summary>
+        [HttpPost("pallet-status")]
+        public async Task<WebResponseContent> GetPalletStatus([FromBody] PalletLocksDto dto)
+        {
+            try
+            {
+                var status = await _outboundBatchPickingService.GetPalletStatus(dto.OrderNo, dto.PalletCode);
+                return WebResponseContent.Instance.OK("鑾峰彇鎴愬姛", status);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, $"鑾峰彇鎵樼洏鐘舵�佸紓甯� - OrderNo: {dto.OrderNo}, PalletCode: {dto.PalletCode}");
+                return WebResponseContent.Instance.Error("绯荤粺寮傚父锛岃绋嶅悗閲嶈瘯" + ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 鑾峰彇鎷嗗寘淇℃伅
+        /// </summary>
+        [HttpPost("split-package-info")]
+        public async Task<WebResponseContent> GetSplitPackageInfo([FromBody] SplitPackageInfoDto dto)
+        {
+            try
+            {
+                var info = await _outboundBatchPickingService.GetSplitPackageInfo(dto.OrderNo, dto.PalletCode, dto.Barcode);
+                return WebResponseContent.Instance.OK("鑾峰彇鎴愬姛", info);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, $"鑾峰彇鎷嗗寘淇℃伅寮傚父 - OrderNo: {dto.OrderNo}, PalletCode: {dto.PalletCode}, Barcode: {dto.Barcode}");
+                return WebResponseContent.Instance.Error("绯荤粺寮傚父锛岃绋嶅悗閲嶈瘯" +ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 鍙栬蛋绌虹
+        /// </summary>
+        [HttpPost("remove-empty-pallet")]
+        public async Task<WebResponseContent> RemoveEmptyPallet([FromBody] RemoveEmptyPalletDto dto)
+        {
+            try
+            {
+                var result = await _outboundBatchPickingService.RemoveEmptyPallet(dto.OrderNo, dto.PalletCode);
+                return result;
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, $"鍙栬蛋绌虹寮傚父 - OrderNo: {dto.OrderNo}, PalletCode: {dto.PalletCode}");
+                return WebResponseContent.Instance.Error("绯荤粺寮傚父锛岃绋嶅悗閲嶈瘯" +ex.Message);
+            }
         }
 
     }
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs"
index 012dc97..aed4552 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs"
@@ -88,5 +88,17 @@
             return Service.GenerateOutboundTask(orderDetailId, stockSelectViews);
         }
 
+        /// <summary>
+        /// 鍒嗘壒鐢熸垚鍑哄簱浠诲姟
+        /// </summary>
+        /// <param name="data"></param>
+        /// <returns></returns>
+        [HttpPost, HttpGet, Route("GenerateOutboundBatchTasks"), AllowAnonymous]
+        public async Task<WebResponseContent> GenerateOutboundBatchTasks([FromBody] GenerateOutboundBatchTasksDto data)
+        {
+            return await Service.GenerateOutboundBatchTasksAsync(data.orderDetailId,data.batchQuantity, data.outboundPlatform);
+        }
+
+        
     }
 }

--
Gitblit v1.9.3