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

---
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutboundBatchPickingService.cs                   |   17 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/OutboundBatchPickingController.cs   |   23 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_Outbound.cs                            |   36 
 项目代码/WIDESEA_WMSClient/src/router/viewGird.js                                                             |    9 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/OutLockStockStatusEnum.cs                         |    6 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs                          |  112 ++
 项目代码/WIDESEA_WMSClient/src/extension/outbound/extend/outOrderDetail.vue                                   |  208 +++++
 项目代码/WMS无仓储版/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/CodeChunks.db-shm      |    0 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/SemanticSymbols.db-shm |    0 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs                      |   54 +
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundBatchPickingService.cs                     |  679 +++++++++++------
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_InboundService/InboundOrderService.cs                              |    2 
 项目代码/WIDESEA_WMSClient/src/views/outbound/BatchPickingConfirm.vue                                         | 1066 ++++++++++++++++++++++++++++
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_PickingRecord.cs                          |    7 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderService.cs                            |    2 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Common/OrderEnum/OutboundOrderEnum.cs                              |    6 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs                                     |    7 
 17 files changed, 1,973 insertions(+), 261 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 b1630d8..07bb89d 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"
@@ -27,13 +27,25 @@
                 style="float: right; height: 20px"
                 @click="handleOpenPicking"
                 >鎷i��</el-link>
-                 
+                        <el-link
+                type="primary"
+                size="small"
+                style="float: right; height: 20px; margin-right: 10px"
+                @click="handleOpenBatchPicking"
+                >鍒嗘壒鎷i��</el-link>
               <el-link
                 type="primary"
                 size="small"
                 style="float: right; height: 20px; margin-right: 10px"
                 @click="outbound"
                 >鐩存帴鍑哄簱</el-link
+              >
+               <el-link
+                type="primary"
+                size="small"
+                style="float: right; height: 20px; margin-right: 10px"
+                @click="outboundbatch"
+                >鍒嗘壒鍑哄簱</el-link
               >
               <el-link
                 type="primary"
@@ -113,8 +125,9 @@
 import SelectedStock from "./SelectedStock.vue";
 import NoStockOut from "./NoStockOut.vue";
 import { h,createVNode, render,reactive  } from 'vue';
-import { ElDialog , ElForm, ElFormItem, ElSelect,ElOption, ElButton, ElMessage } from 'element-plus';
+import { ElDialog , ElForm, ElFormItem, ElSelect,ElOption, ElButton, ElInput, ElMessage } from 'element-plus';
 import { th } from 'element-plus/es/locale';
+
 export default {
   components: { VolBox, VolForm, StockSelect, SelectedStock,NoStockOut},
   data() {
@@ -344,6 +357,11 @@
         query: { orderId: this.row.id ,orderNo:this.row.orderNo}
       })
     },
+    handleOpenBatchPicking() {
+      this.$router.push({ 
+        path: '/outbound/batchpicking',
+        query: { orderId: this.row.id ,orderNo:this.row.orderNo}})
+    },
     outbound() {
       if (this.selection.length === 0) {
         return this.$message.error("璇烽�夋嫨鍗曟嵁鏄庣粏");
@@ -481,6 +499,192 @@
       vnode.appContext = this.$.appContext;
       render(vnode, mountNode);
     },
+    outboundbatch() {
+  if (this.selection.length === 0) {
+    return this.$message.error("璇烽�夋嫨鍗曟嵁鏄庣粏");
+  }
+    if (this.selection.length>1) {
+    return this.$message.error("鍙兘閫夋嫨涓�鏉″崟鎹槑缁嗚繘琛屽垎鎵瑰嚭搴�");
+  }
+  const platformOptions = [{label:'绔欏彴2',value:'2-1'},{label:'绔欏彴3',value:'3-1'}];
+  const mountNode = document.createElement('div');
+  document.body.appendChild(mountNode);
+
+  // 2. 琛ㄥ崟鏁版嵁锛堥粯璁ら�変腑绔欏彴3锛屾柊澧炲皬鏁板瓧娈碉級
+  const formData = reactive({
+    selectedPlatform: platformOptions[0].value, // 榛樿缁戝畾銆岀珯鍙�3銆嶇殑value
+    outboundDecimal: '' // 鏂板锛氬皬鏁拌緭鍏ユ瀛楁
+  });
+
+  // 3. 鍔ㄦ�佸垱寤哄脊绐楃粍浠�
+  const vnode = createVNode(ElDialog, {
+    title: '鍑哄簱鎿嶄綔 - 閫夋嫨鍑哄簱绔欏彴',
+    width: '500px',
+    modelValue: true,
+    appendToBody: true,
+    'onUpdate:modelValue': (isVisible) => {
+      if (!isVisible) {
+        render(null, mountNode);
+        document.body.removeChild(mountNode);
+      }
+    }, 
+    style: {
+      padding: '20px 0',
+      borderRadius: '8px'
+    }
+  }, {
+    default: () => h(ElForm, {
+      model: formData,
+      rules: {
+        selectedPlatform: [
+          { required: true, message: '璇烽�夋嫨鍑哄簱绔欏彴', trigger: 'change' }
+        ],
+        // 鏂板锛氬皬鏁板瓧娈甸獙璇佽鍒欙紙蹇呭~ + 鏈夋晥灏忔暟鏍煎紡锛�
+        outboundDecimal: [
+          { required: true, message: '璇疯緭鍏ュ皬鏁版暟鍊�', trigger: 'blur' },
+          { 
+            validator: (rule, value, callback) => {
+              // 楠岃瘉瑙勫垯锛氭鏁般�佹敮鎸佸皬鏁扮偣鍚庢渶澶�2浣嶏紙鍙牴鎹渶姹傝皟鏁村皬鏁颁綅鏁帮級
+              const decimalReg = /^(([1-9]\d*)|0)(\.\d{1,2})?$/;
+              if (value && !decimalReg.test(value)) {
+                callback(new Error('璇疯緭鍏ユ湁鏁堢殑灏忔暟锛堟鏁帮紝鏈�澶�2浣嶅皬鏁帮級'));
+              } else {
+                callback();
+              }
+            },
+            trigger: 'blur'
+          }
+        ]
+      },
+      ref: 'outboundForm',
+      labelWidth: '100px',
+      style: {
+        padding: '0 30px'
+      }
+    }, [
+      // 鍑哄簱绔欏彴閫夋嫨椤癸紙鏍稿績琛ㄥ崟椤癸級
+      h(ElFormItem, {
+        label: '鍑哄簱绔欏彴',
+        prop: 'selectedPlatform',
+        style: {
+          marginBottom: '24px'
+        }
+      }, [
+        h(ElSelect, {
+          placeholder: '璇烽�夋嫨鍑哄簱绔欏彴锛�3-12锛�',
+          modelValue: formData.selectedPlatform,
+          'onUpdate:modelValue': (val) => {
+            formData.selectedPlatform = val;
+          },
+          style: {
+            width: '100%',
+            height: '40px',
+            borderRadius: '4px',
+            borderColor: '#dcdfe6'
+          }
+        }, platformOptions.map(platform => 
+          h(ElOption, { label: platform.label, value: platform.value })
+        ))
+      ]),
+      // 鏂板锛氬皬鏁拌緭鍏ユ琛ㄥ崟椤�
+      h(ElFormItem, {
+        label: '鍑哄簱鏁�', // 鍙牴鎹笟鍔¢渶姹備慨鏀规爣绛惧悕锛堝鈥滃嚭搴撴暟閲忊�濃�滈噸閲忊�濈瓑锛�
+        prop: 'outboundDecimal',
+        style: {
+          marginBottom: '24px'
+        }
+      }, [
+        h(ElInput, {
+          type: 'number', // 鏁板瓧绫诲瀷锛屽師鐢熸敮鎸佸皬鏁拌緭鍏�
+          placeholder: '璇疯緭鍏ュ皬鏁版暟鍊硷紙鏈�澶�2浣嶅皬鏁帮級',
+          modelValue: formData.outboundDecimal,
+          'onUpdate:modelValue': (val) => {
+            formData.outboundDecimal = val;
+          },
+          style: {
+            width: '100%',
+            height: '40px',
+            borderRadius: '4px',
+            borderColor: '#dcdfe6'
+          },
+          step: '0.01', // 姝ラ暱0.01锛岀偣鍑讳笂涓嬬澶存椂鎸�0.01澧炲噺
+          precision: 2, // 闄愬埗鏈�澶氳緭鍏�2浣嶅皬鏁帮紙Element Plus灞炴�э級
+          min: 0.01, // 鍙�夛細闄愬埗鏈�灏忓�间负0.01锛岄伩鍏嶈緭鍏�0鎴栬礋鏁�
+        })
+      ]),
+      // 搴曢儴鎸夐挳鍖�
+      h('div', {
+        style: {
+          textAlign: 'right',
+          marginTop: '8px',
+          paddingRight: '4px'
+        }
+      }, [
+        h(ElButton, {
+          type: 'text',
+          onClick: () => {
+            render(null, mountNode);
+            document.body.removeChild(mountNode);
+            ElMessage.info('鍙栨秷鍒嗘壒鍑哄簱鎿嶄綔');
+          },
+          style: {
+            marginRight: '8px',
+            color: '#606266'
+          }
+        }, '鍙栨秷'),
+        h(ElButton, {
+          type: 'primary',
+          onClick: async () => {
+            const formRef = vnode.component.refs.outboundForm;
+            try {
+              // 琛ㄥ崟鏍¢獙锛堜細鍚屾椂鏍¢獙鍑哄簱绔欏彴鍜屽皬鏁板瓧娈碉級
+              await formRef.validate();
+            } catch (err) {
+              return;
+            }
+
+            // 4. 鏋勯�犺姹傚弬鏁帮紙鏂板灏忔暟瀛楁锛�
+            const keys = this.selection.map((item) => item.id);
+            const requestParams = {
+              taskIds: keys,
+              outboundPlatform: formData.selectedPlatform, // 鍑哄簱绔欏彴
+              outboundDecimal: formData.outboundDecimal // 鏂板锛氬皬鏁板瓧娈典紶缁欏悗绔�
+            };
+
+            // 5. 璋冪敤鍑哄簱鎺ュ彛
+            this.http
+              .post("api/Task/ ", requestParams, "鏁版嵁澶勭悊涓�")
+              .then((x) => {
+                if (!x.status) return ElMessage.error(x.message);
+                
+                ElMessage.success("鎿嶄綔鎴愬姛");
+                this.showDetialBox = false; // 鍏抽棴璇︽儏妗�
+                this.$emit("parentCall", ($vue) => {
+                  $vue.getData(); // 閫氱煡鐖剁粍浠跺埛鏂�
+                });
+                // 鍏抽棴寮圭獥
+                render(null, mountNode);
+                document.body.removeChild(mountNode);
+              })
+              .catch(() => {
+                ElMessage.error('璇锋眰澶辫触锛岃绋嶅悗閲嶈瘯');
+              });
+          },
+          style: {
+            borderRadius: '4px',
+            padding: '8px 20px'
+          }
+        }, '纭畾鍒嗘壒鍑哄簱')
+      ])
+    ])
+  });
+
+  // 缁戝畾app涓婁笅鏂囷紝纭繚El缁勪欢姝e父宸ヤ綔
+  vnode.appContext = this.$.appContext;
+  render(vnode, mountNode);
+},
+      
+
     setCurrent(row) {
       this.$refs.singleTable.setCurrentRow(row);
     },
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/router/viewGird.js" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/router/viewGird.js"
index 928d24f..977eff2 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/router/viewGird.js"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/router/viewGird.js"
@@ -79,7 +79,14 @@
   name: 'PickingConfirm', 
   component: () => import('@/views/outbound/PickingConfirm.vue'),
   meta: { title: '鎷i�夌‘璁�', keepAlive: false }
-},{
+},
+  {
+  path: '/outbound/batchpicking',
+  name: 'BatchPickingConfirm', 
+  component: () => import('@/views/outbound/BatchPickingConfirm.vue'),
+  meta: { title: '鎷i�夌‘璁�', keepAlive: false }
+},
+{
     path: '/stockInfo',
     name: 'stockInfo',
     component: () => import('@/views/stock/stockInfo.vue')
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"
new file mode 100644
index 0000000..243b5dc
--- /dev/null
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/outbound/BatchPickingConfirm.vue"
@@ -0,0 +1,1066 @@
+<template>
+  <div class="OutboundPicking-container">
+    <div class="page-header">
+      <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>
+
+    <!-- 鎵爜鍖哄煙 -->
+    <div class="scanner-area">
+      <el-card>
+        <div class="scanner-form">
+          <el-input 
+            ref="palletInput"
+            v-model="scanData.palletCode" 
+            placeholder="鎵弿鎵樼洏鐮�" 
+            @change="onPalletScan"
+            @keyup.enter.native="onPalletScan">
+          </el-input>
+          <el-input 
+            ref="barcodeInput"
+            v-model="scanData.barcode" 
+            placeholder="鎵弿鐗╂枡鏉$爜" 
+            @change="onBarcodeScan"
+            @keyup.enter.native="onBarcodeScan">
+          </el-input>
+          <el-button type="success" @click="confirmPicking">纭鎷i��</el-button>
+          <el-button type="warning" @click="openSplitDialog">鎷嗗寘</el-button>
+          <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>
+
+    <!-- 姹囨�讳俊鎭� -->
+    <div class="summary-area">
+      <el-card>
+        <div class="summary-info">
+          <el-tag type="warning">鏈嫞閫夋潯鏁�: {{summary.unpickedCount}}</el-tag>
+          <el-tag type="danger">鏈嫞閫夋暟閲�: {{summary.unpickedQuantity}}</el-tag>
+          <el-tag type="info">鎵樼洏鐘舵��: {{palletStatus}}</el-tag>
+        </div>
+      </el-card>
+    </div>
+
+    <!-- 鏁版嵁鍒楄〃 -->
+    <div class="content-area">
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-card header="鏈嫞閫夊垪琛�">
+            <el-table :data="unpickedList" border height="440">
+              <el-table-column prop="materielCode" label="鐗╂枡缂栫爜" width="120"></el-table-column>
+              <el-table-column prop="assignQuantity" label="鍒嗛厤鏁伴噺" width="100"></el-table-column>
+              <el-table-column prop="pickedQty" label="宸叉嫞鏁伴噺" width="100"></el-table-column>
+              <el-table-column prop="remainQuantity" label="鍓╀綑鏁伴噺" width="100"></el-table-column>
+              <el-table-column prop="locationCode" label="璐т綅" width="100"></el-table-column>
+              <el-table-column prop="currentBarcode" label="鏉$爜"></el-table-column>
+            </el-table>
+          </el-card>
+        </el-col>
+        
+        <el-col :span="12">
+          <el-card header="宸叉嫞閫夊垪琛�">
+            <div class="table-actions">
+              <el-button 
+                size="mini" 
+                type="danger" 
+                :disabled="selectedPickedRows.length === 0"
+                @click="batchCancelSelected">
+                鍙栨秷鎷i��
+              </el-button>
+              <span class="selection-count">宸查�夋嫨 {{selectedPickedRows.length}} 椤�</span>
+            </div>
+            <el-table 
+              :data="pickedList" 
+              border 
+              height="400"  
+              style="width: 100%"    
+              @selection-change="handlePickedSelectionChange">
+              <el-table-column type="selection" width="55"></el-table-column>
+              <el-table-column prop="materielCode" label="鐗╂枡缂栫爜" width="120"></el-table-column>
+              <el-table-column prop="pickedQty" label="宸叉嫞鏁伴噺" width="100"></el-table-column>
+              <el-table-column prop="locationCode" label="璐т綅" width="100"></el-table-column>
+              <el-table-column prop="currentBarcode" label="鏉$爜"></el-table-column>
+            </el-table>
+          </el-card>
+        </el-col>
+      </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">
+        <div class="custom-dialog">
+          <div class="custom-dialog-header">
+            <h3>鎷嗗寘鎿嶄綔</h3>
+            <el-button type="text" @click="closeCustomSplitDialog" class="close-button">X</el-button>
+          </div>
+          <div class="custom-dialog-body">
+            <el-form :model="splitForm" :rules="splitFormRules" ref="splitFormRef" label-width="100px">
+              <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>
+              </el-form-item>
+              <el-form-item label="鐗╂枡缂栫爜">
+                <el-input v-model="splitForm.materielCode" disabled></el-input>
+              </el-form-item>
+              <el-form-item label="鍓╀綑鏁伴噺">
+                <el-input v-model="splitForm.maxQuantity" disabled></el-input>
+              </el-form-item>
+              <el-form-item label="鎷嗗寘鏁伴噺" prop="splitQuantity">
+                <el-input-number 
+                  v-model="splitForm.splitQuantity" 
+                  :min="1" 
+                  :max="splitForm.maxQuantity"
+                  :precision="2"
+                  :step="1"
+                  style="width: 100%">
+                </el-input-number>
+              </el-form-item>
+            </el-form>
+          </div>
+          <div class="custom-dialog-footer">
+            <el-button @click="closeCustomSplitDialog">鍙栨秷</el-button>
+            <el-button type="primary" @click="handleSplitPackage" :loading="splitLoading">纭鎷嗗寘</el-button>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 鎾ら攢鎷嗗寘寮圭獥 -->
+    <div v-if="showRevertSplitDialog" 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="closeRevertSplitDialog" class="close-button">脳</el-button>
+          </div>
+          <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>
+              </el-form-item>
+            </el-form>
+          </div>
+          <div class="custom-dialog-footer">
+            <el-button @click="closeRevertSplitDialog">鍙栨秷</el-button>
+            <el-button type="primary" @click="handleRevertSplit" :loading="revertSplitLoading">纭鎾ら攢</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>
+            <el-button type="text" @click="closeBatchReturnDialog" class="close-button">脳</el-button>
+          </div>
+          <div class="custom-dialog-body">
+            <el-form :model="batchReturnForm" :rules="batchReturnFormRules" ref="batchReturnFormRef" label-width="100px">
+              <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>
+              <el-form-item label="鏈嫞閫夋暟閲�">
+                <el-input v-model="batchReturnForm.unpickedQuantity" disabled></el-input>
+              </el-form-item>
+              <el-form-item label="鏈嫞閫夋潯鏁�">
+                <el-input v-model="batchReturnForm.unpickedCount" disabled></el-input>
+              </el-form-item>
+            </el-form>
+          </div>
+          <div class="custom-dialog-footer">
+            <el-button @click="closeBatchReturnDialog">鍙栨秷</el-button>
+            <el-button type="primary" @click="handleBatchReturnConfirm" :loading="batchReturnLoading">纭鍥炲簱</el-button>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 鍙栬蛋绌虹寮圭獥 -->
+    <div v-if="showEmptyPalletDialog" 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="closeEmptyPalletDialog" class="close-button">脳</el-button>
+          </div>
+          <div class="custom-dialog-body">
+            <el-form :model="emptypalletOutForm" :rules="emptypalletOutFormRules" ref="emptypalletOutFormRef" label-width="100px">
+              <el-form-item label="璁㈠崟缂栧彿">
+                <el-input v-model="emptypalletOutForm.orderNo" disabled></el-input>
+              </el-form-item>
+              <el-form-item label="鎵樼洏缂栧彿" prop="palletCode">
+                <el-input 
+                  v-model="emptypalletOutForm.palletCode" 
+                  placeholder="鎵弿鎵樼洏鐮�"
+                  @keyup.enter.native="onEmptyPalletScan"
+                  @change="onEmptyPalletScan"
+                  clearable>
+                </el-input>
+              </el-form-item>
+            </el-form>
+          </div>
+          <div class="custom-dialog-footer">
+            <el-button @click="closeEmptyPalletDialog">鍙栨秷</el-button>
+            <el-button type="primary" @click="handleEmptyPalletConfirm" :loading="emptypalletOutLoading">纭鍙栬蛋绌虹</el-button>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <print-view ref="childs" @parentcall="parentcall"></print-view>
+  </div>
+</template>
+
+<script>
+import http from '@/api/http.js'
+import { ref, defineComponent } from "vue";
+import { ElMessage } from 'element-plus' 
+import { useRoute } from 'vue-router'
+import printView from "@/extension/outbound/extend/printView.vue"
+
+export default defineComponent({
+  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: ''
+      },
+      currentBatchNo: '', // 褰撳墠鎵规鍙�
+      batchList: [], // 鎵规鍒楄〃
+      selectedBatchNo: '', // 閫変腑鐨勬壒娆″彿
+      batchSummary: {}, // 鎵规姹囨�讳俊鎭�
+      unpickedList: [],
+      pickedList: [],
+      selectedPickedRows: [],
+      summary: {
+        unpickedCount: 0,
+        unpickedQuantity: 0,
+        pickedCount: 0
+      },
+      palletStatus: '鏈煡',
+      
+      // 寮圭獥鐘舵��
+      showBatchAllocateDialog: false,
+      showCustomSplitDialog: false,
+      showRevertSplitDialog: false,
+      showBatchReturnDialog: false,
+      showEmptyPalletDialog: false,
+      
+      // 鍔犺浇鐘舵��
+      batchAllocateLoading: false,
+      splitLoading: false,
+      revertSplitLoading: false,
+      batchReturnLoading: false,
+      emptypalletOutLoading: false,
+      
+      // 琛ㄥ崟鏁版嵁
+      batchAllocateForm: {
+        orderNo: '',
+        orderDetailId: '',
+        batchQuantity: 0
+      },
+      allocatableDetails: [], // 鍙垎閰嶇殑璁㈠崟鏄庣粏
+      
+      splitForm: {
+        orderNo: '',
+        batchNo: '',
+        palletCode: '',
+        originalBarcode: '',
+        materielCode: '',
+        splitQuantity: 0,
+        maxQuantity: 0
+      },
+      
+      revertSplitForm: {
+        newBarcode: ''
+      },
+      
+      batchReturnForm: {
+        orderNo: '',
+        batchNo: '',
+        unpickedCount: 0,
+        unpickedQuantity: 0
+      },
+      
+      emptypalletOutForm: {
+        orderNo: '',
+        palletCode: ''
+      },
+      
+      // 楠岃瘉瑙勫垯
+      batchAllocateFormRules: {
+        orderDetailId: [
+          { required: true, validator: validateOrderDetailId, trigger: 'change' }
+        ],
+        batchQuantity: [
+          { required: true, validator: validateBatchQuantity, trigger: 'blur' }
+        ]
+      },
+      
+      // 鍏朵粬楠岃瘉瑙勫垯...
+      isProcessing: false
+    }
+  },
+  mounted() {
+    if (this.$route.query.orderNo) {
+      this.scanData.orderNo = this.$route.query.orderNo;
+      this.batchAllocateForm.orderNo = this.$route.query.orderNo;
+      this.loadBatchList();
+    }
+    this.$nextTick(() => {
+      this.$refs.palletInput.focus();
+    });
+  },
+  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;
+    },
+
+    // 鍒嗘嫞鐩稿叧鏂规硶
+    async confirmPicking() {
+      if (this.isProcessing) return;
+      
+      if (!this.scanData.orderNo || !this.scanData.palletCode || !this.scanData.barcode) {
+        this.$message.warning('璇峰厛鎵弿鎵樼洏鐮佸拰鐗╂枡鏉$爜');
+        this.focusBarcodeInput();
+        return;
+      }
+
+      if (!this.currentBatchNo) {
+        this.$message.warning('璇峰厛閫夋嫨鎵规');
+        return;
+      }
+
+      this.isProcessing = true;
+      
+      try {
+        const res = await http.post('/api/BatchOutbound/confirm-picking', this.scanData);
+        if (res.status) {
+          this.$message.success('鎷i�夌‘璁ゆ垚鍔�');
+          this.scanData.barcode = '';
+          await this.loadBatchData();
+          if(res.data && res.data.splitResults && res.data.splitResults.length>0){
+            this.$refs.childs.open(res.data.splitResults);
+          }
+          this.$nextTick(() => {
+            this.$refs.barcodeInput.focus();
+          });
+        } else {
+          this.$message.error(res.message || '鎷i�夌‘璁ゅけ璐�');
+          this.focusBarcodeInput(true);
+        }
+      } catch (error) {
+        this.$message.error('鎷i�夌‘璁ゅけ璐�: ' + (error.message || '缃戠粶閿欒'));
+        this.focusBarcodeInput(true);
+      } finally {
+        this.isProcessing = false;
+      }
+    },
+
+    // 鎷嗗寘鐩稿叧鏂规硶
+    openSplitDialog() {
+      if (!this.scanData.palletCode) {
+        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;
+    },
+
+    async onSplitBarcodeScan() {
+      if (!this.splitForm.originalBarcode) return;
+      this.splitForm.originalBarcode = this.splitForm.originalBarcode.replace(/\n/g, '').trim();
+
+      try {
+        const res = await http.post('/api/BatchOutbound/split-package-info', {
+          orderNo: this.splitForm.orderNo,
+          batchNo: this.splitForm.batchNo,
+          barcode: this.splitForm.originalBarcode
+        });
+
+        if (res.status) {
+          this.splitForm.materielCode = res.data.materielCode;
+          this.splitForm.maxQuantity = res.data.remainQuantity;
+          this.splitForm.splitQuantity = Math.min(1, this.splitForm.maxQuantity);
+        } else {
+          this.$message.error(res.message || '鑾峰彇鎷嗗寘淇℃伅澶辫触');
+        }
+      } catch (error) {
+        this.$message.error('鑾峰彇鎷嗗寘淇℃伅澶辫触');
+      }
+    },
+
+    async handleSplitPackage() {
+      if (this.$refs.splitFormRef) {
+        this.$refs.splitFormRef.validate(async (valid) => {
+          if (valid) {
+            this.splitLoading = true;
+            try {
+              const res = await http.post('/api/BatchOutbound/manual-split-package', this.splitForm);
+              if (res.status) {
+                this.$message.success('鎷嗗寘鎴愬姛');
+                this.showCustomSplitDialog = false;
+                await this.loadBatchData();
+              } else {
+                this.$message.error(res.message || '鎷嗗寘澶辫触');
+              }
+            } catch (error) {
+              this.$message.error('鎷嗗寘澶辫触');
+            } finally {
+              this.splitLoading = false;
+            }
+          }
+        });
+      }
+    },
+
+    // 鎾ら攢鎷嗗寘
+    async onRevertSplitBarcodeScan() {
+      if (!this.revertSplitForm.newBarcode) return;
+      this.revertSplitForm.newBarcode = this.revertSplitForm.newBarcode.replace(/\n/g, '').trim();
+    },
+
+    async handleRevertSplit() {
+      if (this.$refs.revertSplitFormRef) {
+        this.$refs.revertSplitFormRef.validate(async (valid) => {
+          if (valid) {
+            this.revertSplitLoading = true;
+            try {
+              const res = await http.post('/api/BatchOutbound/cancel-split-package', {
+                orderNo: this.scanData.orderNo,
+                batchNo: this.currentBatchNo,
+                newBarcode: this.revertSplitForm.newBarcode
+              });
+              if (res.status) {
+                this.$message.success('鎾ら攢鎷嗗寘鎴愬姛');
+                this.showRevertSplitDialog = false;
+                await this.loadBatchData();
+              } else {
+                this.$message.error(res.message || '鎾ら攢鎷嗗寘澶辫触');
+              }
+            } catch (error) {
+              this.$message.error('鎾ら攢鎷嗗寘澶辫触');
+            } finally {
+              this.revertSplitLoading = false;
+            }
+          }
+        });
+      }
+    },
+
+    // 鍥炲簱鐩稿叧鏂规硶
+    openBatchReturnDialog() {
+      if (!this.currentBatchNo) {
+        this.$message.warning('璇峰厛閫夋嫨鎵规');
+        return;
+      }
+      this.showBatchReturnDialog = true;
+      this.batchReturnForm.orderNo = this.scanData.orderNo;
+      this.batchReturnForm.batchNo = this.currentBatchNo;
+      this.batchReturnForm.unpickedCount = this.summary.unpickedCount;
+      this.batchReturnForm.unpickedQuantity = this.summary.unpickedQuantity;
+    },
+
+    async handleBatchReturnConfirm() {
+      this.batchReturnLoading = true;
+      try {
+        const res = await http.post('/api/BatchOutbound/batch-return-stock', {
+          orderNo: this.scanData.orderNo,
+          batchNo: this.currentBatchNo
+        });
+        if (res.status) {
+          this.$message.success('鎵规鍥炲簱鎴愬姛');
+          this.showBatchReturnDialog = false;
+          await this.loadBatchData();
+        } else {
+          this.$message.error(res.message || '鎵规鍥炲簱澶辫触');
+        }
+      } catch (error) {
+        this.$message.error('鎵规鍥炲簱澶辫触');
+      } finally {
+        this.batchReturnLoading = false;
+      }
+    },
+
+    // 鍙栫┖绠辨柟娉�
+    async handleEmptyPalletConfirm() {
+      this.emptypalletOutLoading = true;
+      try {
+        const res = await http.post('/api/BatchOutbound/remove-empty-pallet', this.emptypalletOutForm);
+        if (res.status) {
+          this.$message.success('鍙栬蛋绌虹鎴愬姛');
+          this.showEmptyPalletDialog = false;
+          await this.loadBatchData();
+        } else {
+          this.$message.error(res.message || '鍙栬蛋绌虹澶辫触');
+        }
+      } catch (error) {
+        this.$message.error('鍙栬蛋绌虹澶辫触');
+      } finally {
+        this.emptypalletOutLoading = false;
+      }
+    },
+
+    // 鍏朵粬鍘熸湁鏂规硶...
+    onPalletScan() {
+      this.scanData.palletCode = this.scanData.palletCode.replace(/\n/g, '').trim();
+      if (!this.scanData.palletCode) return;
+      
+      this.loadActiveBatch();
+      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() {
+      this.scanData.barcode = this.scanData.barcode.replace(/\n/g, '').trim();
+      if (!this.scanData.barcode) return;
+      this.confirmPicking();
+    },
+
+    focusBarcodeInput(selectText = false) {
+      this.$nextTick(() => {
+        const input = this.$refs.barcodeInput;
+        if (input && input.$el && input.$el.querySelector('input')) {
+          const inputEl = input.$el.querySelector('input');
+          inputEl.focus();
+          if (selectText) {
+            inputEl.select();
+          }
+        }
+      });
+    },
+
+    handlePickedSelectionChange(selection) {
+      this.selectedPickedRows = selection;
+    },
+
+    async batchCancelSelected() {
+      if (this.selectedPickedRows.length === 0) {
+        this.$message.warning('璇峰厛閫夋嫨瑕佸彇娑堢殑椤�');
+        return;
+      }
+
+      this.$confirm(`纭畾瑕佸彇娑堥�変腑鐨� ${this.selectedPickedRows.length} 椤瑰悧锛焋, '鎻愮ず', {
+        confirmButtonText: '纭畾',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning'
+      }).then(async () => {
+        try {
+          for (const row of this.selectedPickedRows) {
+            try {
+              const res = await http.post('/api/BatchOutbound/cancel-picking', {
+                orderNo: this.scanData.orderNo,
+                batchNo: this.currentBatchNo,
+                palletCode: this.scanData.palletCode,
+                barcode: row.currentBarcode
+              });
+              if (!res.status) {
+                this.$message.warning(`鍙栨秷鎷i�夊け璐�: ${row.currentBarcode} - ${res.message}`);
+              }
+            } catch (error) {
+              this.$message.warning(`鍙栨秷鎷i�夊け璐�: ${row.currentBarcode} - ${error.message}`);
+            }
+          }        
+          this.$message.success('鎵归噺鍙栨秷瀹屾垚');
+          await this.loadBatchData();
+          this.selectedPickedRows = [];
+        } catch (error) {
+          this.$message.error('鎵归噺鍙栨秷鎿嶄綔澶辫触');
+        }
+      });
+    },
+
+    // 閲嶇疆鏂规硶
+    resetSplitForm() {
+      this.splitForm.originalBarcode = '';
+      this.splitForm.materielCode = '';
+      this.splitForm.splitQuantity = 0;
+      this.splitForm.maxQuantity = 0;
+    },
+
+    closeCustomSplitDialog() {
+      this.showCustomSplitDialog = false;
+      this.resetSplitForm();
+    },
+
+    openRevertSplitDialog() {
+      this.showRevertSplitDialog = true;
+      this.revertSplitForm.newBarcode = '';
+    },
+
+    closeRevertSplitDialog() {
+      this.showRevertSplitDialog = false;
+      this.revertSplitForm.newBarcode = '';
+    },
+
+    closeBatchReturnDialog() {
+      this.showBatchReturnDialog = false;
+    },
+
+    openEmptyPalletDialog() {
+      this.showEmptyPalletDialog = true;
+      this.emptypalletOutForm.orderNo = this.scanData.orderNo;
+      this.emptypalletOutForm.palletCode = '';
+    },
+
+    closeEmptyPalletDialog() {
+      this.showEmptyPalletDialog = false;
+      this.emptypalletOutForm.palletCode = '';
+    },
+
+    onEmptyPalletScan() {
+      if (!this.emptypalletOutForm.palletCode) return;
+      this.emptypalletOutForm.palletCode = this.emptypalletOutForm.palletCode.replace(/\n/g, '').trim();
+    }
+  }
+})
+</script>
+
+<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 {
+  display: flex;
+  gap: 10px;
+  align-items: center;
+  flex-wrap: wrap;
+}
+
+.scanner-form .el-input {
+  width: 200px;
+}
+
+.summary-info {
+  display: flex;
+  gap: 20px;
+  flex-wrap: wrap;
+}
+
+.table-actions {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 10px;
+  padding: 0 10px;
+}
+
+.selection-count {
+  font-size: 12px;
+  color: #909399;
+}
+
+/* 鑷畾涔夊脊绐楁牱寮� */
+.custom-dialog-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 9999;
+}
+
+.custom-dialog-wrapper {
+  position: relative;
+  z-index: 10000;
+}
+
+.custom-dialog {
+  background: white;
+  border-radius: 4px;
+  width: 500px;
+  max-width: 90vw;
+  max-height: 90vh;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+  overflow: auto;
+}
+
+.custom-dialog-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 20px 20px 10px;
+  border-bottom: 1px solid #ebeef5;
+}
+
+.custom-dialog-header h3 {
+  margin: 0;
+  color: #303133;
+}
+
+.close-button {
+  font-size: 18px;
+  color: #909399;
+  padding: 0;
+  width: 24px;
+  height: 24px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.close-button:hover {
+  color: #409EFF;
+  background-color: transparent;
+}
+
+.custom-dialog-body {
+  padding: 20px;
+}
+
+.custom-dialog-footer {
+  padding: 10px 20px 20px;
+  text-align: right;
+  border-top: 1px solid #ebeef5;
+}
+
+.custom-dialog-footer .el-button {
+  margin-left: 10px;
+}
+
+@media (max-width: 768px) {
+  .custom-dialog {
+    width: 95vw;
+    margin: 10px;
+  }
+  
+  .scanner-form {
+    flex-direction: column;
+    align-items: stretch;
+  }
+  
+  .scanner-form .el-input {
+    width: 100%;
+  }
+}
+</style>
\ 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/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/CodeChunks.db-shm" "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/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/CodeChunks.db-shm"
index 428e047..12ed131 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/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/CodeChunks.db-shm"
+++ "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/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/CodeChunks.db-shm"
Binary files differ
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/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/SemanticSymbols.db-shm" "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/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/SemanticSymbols.db-shm"
index b6152d9..57bd494 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/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/SemanticSymbols.db-shm"
+++ "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/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/SemanticSymbols.db-shm"
Binary files differ
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 879747f..ad071e1 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"
@@ -21,12 +21,18 @@
         [Description("鍑哄簱涓�")]
         鍑哄簱涓� = 1,
 
+
+       
         /// <summary>
         /// 鍑哄簱瀹屾垚
         /// </summary>
         [Description("鍑哄簱瀹屾垚")]
         鍑哄簱瀹屾垚 = 2,
 
+        [Description("閮ㄥ垎瀹屾垚")]
+
+        閮ㄥ垎瀹屾垚 =3,
+
         /// <summary>
         /// 鍏抽棴
         /// </summary>
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 32471a8..e106eab 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"
@@ -24,7 +24,8 @@
         鎵ц涓� = 1,
         宸插畬鎴� = 2,
         宸插洖搴� = 3,
-        宸插彇娑� = 4
+        宸插彇娑� = 4,
+        
     }
 
     public enum SplitPackageStatusEnum
@@ -63,6 +64,9 @@
         [Description("宸插洖搴�")]
         宸插洖搴� =8,
 
+        [Description("宸查噴鏀�")]
+        宸查噴鏀� =9,
+
         [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_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"
new file mode 100644
index 0000000..15027f8
--- /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_IOutboundService/IOutboundBatchPickingService.cs"
@@ -0,0 +1,17 @@
+锘縰sing WIDESEA_Core;
+using WIDESEA_Core.BaseRepository;
+using WIDESEA_Model.Models;
+
+namespace WIDESEA_IOutboundService
+{
+    public interface IOutboundBatchPickingService
+    {
+        IRepository<Dt_PickingRecord> Repository { get; }
+
+        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> ConfirmBatchPicking(string orderNo, string palletCode, string barcode);
+        Task<WebResponseContent> ManualSplitPackage(string orderNo, string palletCode, string originalBarcode, decimal splitQuantity);
+    }
+}
\ 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_InboundService/InboundOrderService.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_InboundService/InboundOrderService.cs"
index 729b4e1..f65373c 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_InboundService/InboundOrderService.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_InboundService/InboundOrderService.cs"
@@ -96,7 +96,7 @@
                         item.Unit = purchaseToStockResult.Unit;
                         item.OrderQuantity = purchaseToStockResult.Quantity;
                     }
-                    if (model.OrderType != InOrderTypeEnum.Allocat.ObjToInt())
+                    if (model.OrderType != InOrderTypeEnum.AllocatInbound.ObjToInt())
                     {
                         model.InboundOrderNo = CreateCodeByRule(nameof(RuleCodeEnum.InboundOrderRule));
                     }
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 798a774..7344ede 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"
@@ -44,7 +44,13 @@
 
         public int StockId { get; set; }
 
+        public string BatchNo { get; set; }
 
+        public bool IsCancelled { get; set; }
+
+        public DateTime? CancelTime { get; set; }
+
+        public string CancelOperator { get; set; }
         public string FactoryArea { get; set; }
     }
 
@@ -107,6 +113,7 @@
 
         public DateTime RevertTime { get; set; }
 
+        public string RevertOperator { get; set; }
         public int PreviousSplitRecordId { get; set; }
 
         [SugarColumn(IsNullable = true)]
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 445c6e5..2b85d56 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"
@@ -21,10 +21,10 @@
 
 namespace WIDESEA_OutboundService
 {
-    public  class OutboundBatchPickingService : ServiceBase<Dt_PickingRecord, IRepository<Dt_PickingRecord>>
+    public class OutboundBatchPickingService : ServiceBase<Dt_PickingRecord, IRepository<Dt_PickingRecord>>, IOutboundBatchPickingService
     {
 
- 
+
         private readonly IUnitOfWorkManage _unitOfWorkManage;
         public IRepository<Dt_PickingRecord> Repository => BaseDal;
 
@@ -86,72 +86,327 @@
         /// <summary>
         /// 鍒嗘壒鍒嗘嫞纭
         /// </summary>
-        public async Task<WebResponseContent> ConfirmBatchPicking(string orderNo, string batchNo, string palletCode, string barcode, decimal actualPickedQty)
+        public async Task<WebResponseContent> ConfirmBatchPicking(string orderNo, string palletCode, string barcode)
         {
             try
             {
                 _unitOfWorkManage.BeginTran();
 
                 // 1. 楠岃瘉鍒嗘嫞璇锋眰
-                var validationResult = await ValidateBatchPickingRequest(orderNo, batchNo, palletCode, barcode, actualPickedQty);
+                var validationResult = await ValidatePickingRequest(orderNo, palletCode, barcode);
                 if (!validationResult.IsValid)
                     return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
 
-                var (lockInfo, orderDetail, stockDetail) = validationResult.Data;
+                var (lockInfo, orderDetail, stockDetail, batch) = validationResult.Data;
+
+                // 浣跨敤閿佸畾淇℃伅鐨勫垎閰嶆暟閲忎綔涓哄疄闄呭垎鎷f暟閲�
+                var actualPickedQty = lockInfo.AssignQuantity;
 
                 // 2. 鎵ц鍒嗘嫞閫昏緫
-                var pickingResult = await ExecuteBatchPickingLogic(lockInfo, orderDetail, stockDetail, actualPickedQty);
+                var pickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, actualPickedQty);
 
-                // 3. 鏇存柊鎵规瀹屾垚鏁伴噺
-                await UpdateBatchCompletedQuantity(batchNo, actualPickedQty);
+                // 3. 鏇存柊鎵规鍜岃鍗曟暟鎹�
+                await UpdateBatchAndOrderData(batch, orderDetail, actualPickedQty, orderNo);
 
-                // 4. 鏇存柊璁㈠崟鐩稿叧鏁版嵁
-                await UpdateOrderRelatedData(orderDetail.Id, actualPickedQty, orderNo);
-
-                // 5. 璁板綍鎷i�夊巻鍙�
-                await RecordPickingHistory(pickingResult, orderNo, palletCode, batchNo);
+                // 4. 璁板綍鎷i�夊巻鍙�
+                await RecordPickingHistory(pickingResult, orderNo, palletCode);
 
                 _unitOfWorkManage.CommitTran();
 
-                return WebResponseContent.Instance.OK("鍒嗘壒鍒嗘嫞鎴愬姛");
+                return WebResponseContent.Instance.OK("鍒嗘嫞鎴愬姛", new
+                {
+                    PickedQuantity = actualPickedQty,
+                    Barcode = barcode,
+                    MaterialCode = lockInfo.MaterielCode
+                });
             }
             catch (Exception ex)
             {
                 _unitOfWorkManage.RollbackTran();
-                _logger.LogError($"鍒嗘壒鍒嗘嫞澶辫触 - OrderNo: {orderNo}, BatchNo: {batchNo}, Error: {ex.Message}");
-                return WebResponseContent.Instance.Error($"鍒嗘壒鍒嗘嫞澶辫触锛歿ex.Message}");
+                _logger.LogError($"鍒嗘嫞澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Barcode: {barcode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error($"鍒嗘嫞澶辫触锛歿ex.Message}");
+            }
+        }
+        /// <summary>
+        /// 鍙栨秷鍒嗘嫞
+        /// </summary>
+        public async Task<WebResponseContent> CancelPicking(string orderNo, string palletCode, string barcode)
+        {
+            try
+            {
+                _unitOfWorkManage.BeginTran();
+
+                // 鏌ユ壘鍒嗘嫞璁板綍
+                var pickingRecord = await Db.Queryable<Dt_PickingRecord>()
+                    .Where(x => x.OrderNo == orderNo &&
+                               x.PalletCode == palletCode &&
+                               x.Barcode == barcode &&
+                               !x.IsCancelled)
+                    .OrderByDescending(x => x.PickTime)
+                    .FirstAsync();
+
+                if (pickingRecord == null)
+                    return WebResponseContent.Instance.Error("鏈壘鍒板垎鎷h褰�");
+
+                // 鎭㈠閿佸畾淇℃伅鍜屽簱瀛�
+                await RevertPickingData(pickingRecord);
+
+                //鏇存柊鎵规鍜岃鍗曟暟鎹�
+                await RevertBatchAndOrderData(pickingRecord);
+
+                // 鏍囪鍒嗘嫞璁板綍涓哄凡鍙栨秷
+                pickingRecord.IsCancelled = true;
+                pickingRecord.CancelTime = DateTime.Now;
+                pickingRecord.CancelOperator = App.User.UserName;
+                await Db.Updateable(pickingRecord).ExecuteCommandAsync();
+
+                _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}");
             }
         }
 
-        private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>> ValidateBatchPickingRequest(
-            string orderNo, string batchNo, string palletCode, string barcode, decimal actualPickedQty)
+        #endregion
+
+        #region 鎵嬪姩鎷嗗寘
+
+        /// <summary>
+        /// 鎵嬪姩鎷嗗寘
+        /// </summary>
+        public async Task<WebResponseContent> ManualSplitPackage(string orderNo, string palletCode, string originalBarcode, decimal splitQuantity)
         {
-            // 鏌ユ壘鎵规閿佸畾淇℃伅
+            try
+            {
+                _unitOfWorkManage.BeginTran();
+
+                //  楠岃瘉鎷嗗寘璇锋眰
+                var validationResult = await ValidateSplitRequest(orderNo, palletCode, originalBarcode, splitQuantity);
+                if (!validationResult.IsValid)
+                    return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
+
+                var (lockInfo, stockDetail) = validationResult.Data;
+
+                // . 鎵ц鎷嗗寘閫昏緫
+                var splitResult = await ExecuteSplitLogic(lockInfo, stockDetail, splitQuantity, palletCode);
+
+                _unitOfWorkManage.CommitTran();
+
+                return WebResponseContent.Instance.OK("鎵嬪姩鎷嗗寘鎴愬姛", new
+                {
+                    NewBarcode = splitResult.NewBarcode,
+                    OriginalBarcode = originalBarcode,
+                    SplitQuantity = splitQuantity
+                });
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                _logger.LogError($"鎵嬪姩鎷嗗寘澶辫触 - OrderNo: {orderNo}, Barcode: {originalBarcode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error($"鎵嬪姩鎷嗗寘澶辫触锛歿ex.Message}");
+            }
+        }
+
+        #endregion
+
+        #region 鍙栨秷鎷嗗寘
+
+        /// <summary>
+        /// 鍙栨秷鎷嗗寘
+        /// </summary>
+        public async Task<WebResponseContent> CancelSplitPackage(string orderNo, string palletCode, string newBarcode)
+        {
+            try
+            {
+                _unitOfWorkManage.BeginTran();
+
+                // 鏌ユ壘鎷嗗寘璁板綍骞堕獙璇�
+                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);
+
+                _unitOfWorkManage.CommitTran();
+
+                return WebResponseContent.Instance.OK("鍙栨秷鎷嗗寘鎴愬姛");
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                _logger.LogError($"鍙栨秷鎷嗗寘澶辫触 - OrderNo: {orderNo}, Barcode: {newBarcode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error($"鍙栨秷鎷嗗寘澶辫触锛歿ex.Message}");
+            }
+        }
+
+        #endregion
+
+        #region 鍒嗘壒鍥炲簱
+
+        /// <summary>
+        /// 鍒嗘壒鍥炲簱 - 閲婃斁鏈嫞閫夌殑搴撳瓨
+        /// </summary>
+        public async Task<WebResponseContent> BatchReturnStock(string orderNo, string palletCode)
+        {
+            try
+            {
+                _unitOfWorkManage.BeginTran();
+
+                //  鏌ユ壘鎵樼洏涓婃湭瀹屾垚鐨勯攣瀹氳褰�
+                var unfinishedLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                    .Where(x => x.OrderNo == orderNo &&
+                               x.PalletCode == palletCode &&
+                               x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
+                    .ToListAsync();
+
+                if (!unfinishedLocks.Any())
+                    return WebResponseContent.Instance.Error("璇ユ墭鐩樻病鏈夋湭瀹屾垚鐨勯攣瀹氳褰�");
+
+                // 鎸夋壒娆″垎缁勫鐞�
+                var batchGroups = unfinishedLocks.GroupBy(x => x.BatchNo);
+
+                foreach (var batchGroup in batchGroups)
+                {
+                    var batchNo = batchGroup.Key;
+                    var batchLocks = batchGroup.ToList();
+
+                    // 閲婃斁搴撳瓨鍜岄攣瀹氳褰�
+                    foreach (var lockInfo in batchLocks)
+                    {
+                        await ReleaseLockAndStock(lockInfo);
+                    }
+
+                    // 鏇存柊鎵规鐘舵��
+                    await UpdateBatchStatusForReturn(batchNo, batchLocks);
+
+                    // 鏇存柊璁㈠崟鏄庣粏鐨勫凡鍒嗛厤鏁伴噺
+                    await UpdateOrderDetailAfterReturn(batchLocks);
+                }
+
+                _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}");
+            }
+        }
+
+        #endregion
+
+        #region 楠岃瘉鏂规硶
+        private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>> ValidatePickingRequest(
+    string orderNo, string palletCode, string barcode)
+        {
+            // 鏌ユ壘閿佸畾淇℃伅
             var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                 .Where(x => x.OrderNo == orderNo &&
-                           x.BatchNo == batchNo &&
                            x.PalletCode == palletCode &&
                            x.CurrentBarcode == barcode &&
                            x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
                 .FirstAsync();
 
             if (lockInfo == null)
-                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error("鏈壘鍒版湁鏁堢殑鎵规閿佸畾淇℃伅");
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error("鏈壘鍒版湁鏁堢殑閿佸畾淇℃伅");
 
-            if (actualPickedQty <= 0 || actualPickedQty > lockInfo.AssignQuantity - lockInfo.PickedQty)
-                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error("鍒嗘嫞鏁伴噺鏃犳晥");
+            // 妫�鏌ユ槸鍚﹀凡缁忓垎鎷e畬鎴�
+            if (lockInfo.PickedQty >= lockInfo.AssignQuantity)
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error("璇ユ潯鐮佸凡鍒嗘嫞瀹屾垚");
 
-            // 鑾峰彇璁㈠崟鏄庣粏鍜屽簱瀛樻槑缁�
+            // 鑾峰彇鍏宠仈鏁版嵁
             var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                 .FirstAsync(x => x.Id == lockInfo.OrderDetailId);
 
             var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                 .FirstAsync(x => x.Barcode == barcode && x.StockId == lockInfo.StockId);
 
-            return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Success((lockInfo, orderDetail, stockDetail));
+            // 楠岃瘉搴撳瓨鏁伴噺
+            if (stockDetail.StockQuantity < lockInfo.AssignQuantity)
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error(
+                    $"搴撳瓨鏁伴噺涓嶈冻锛岄渶瑕侊細{lockInfo.AssignQuantity}锛屽疄闄咃細{stockDetail.StockQuantity}");
+
+            var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>()
+                .FirstAsync(x => x.BatchNo == lockInfo.BatchNo);
+
+            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)
+        {
+            var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(x => x.OrderNo == orderNo &&
+                           x.PalletCode == palletCode &&
+                           x.CurrentBarcode == originalBarcode &&
+                           x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
+                .FirstAsync();
+
+            if (lockInfo == null)
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鏈壘鍒版湁鏁堢殑閿佸畾淇℃伅");
+
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .FirstAsync(x => x.Barcode == originalBarcode && x.StockId == lockInfo.StockId);
+
+            if (stockDetail.StockQuantity < splitQuantity)
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鎷嗗寘鏁伴噺涓嶈兘澶т簬搴撳瓨鏁伴噺");
+
+            if (lockInfo.AssignQuantity - lockInfo.PickedQty < splitQuantity)
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鎷嗗寘鏁伴噺涓嶈兘澶т簬鏈嫞閫夋暟閲�");
+
+            return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((lockInfo, stockDetail));
         }
 
-        private async Task<PickingResult> ExecuteBatchPickingLogic(
+        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 鏍稿績閫昏緫鏂规硶
+
+        private async Task<PickingResult> ExecutePickingLogic(
             Dt_OutStockLockInfo lockInfo, Dt_OutboundOrderDetail orderDetail,
             Dt_StockInfoDetail stockDetail, decimal actualPickedQty)
         {
@@ -180,86 +435,34 @@
             };
         }
 
-        private async Task UpdateBatchCompletedQuantity(string batchNo, decimal pickedQty)
+        private async Task<RevertPickingResult> RevertPickingData(Dt_PickingRecord pickingRecord)
         {
-            await _outboundBatchRepository.Db.Updateable<Dt_OutboundBatch>()
-                .SetColumns(x => x.CompletedQuantity == x.CompletedQuantity + pickedQty)
-                .Where(x => x.BatchNo == batchNo)
-                .ExecuteCommandAsync();
-
-            // 妫�鏌ユ壒娆℃槸鍚﹀畬鎴�
-            var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>()
-                .FirstAsync(x => x.BatchNo == batchNo);
-
-            if (batch.CompletedQuantity >= batch.BatchQuantity)
-            {
-                batch.BatchStatus = (int)BatchStatusEnum.宸插畬鎴�;
-                await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync();
-            }
-        }
-
-        #endregion
-
-        #region 鎵嬪姩鎷嗗寘
-
-        /// <summary>
-        /// 鎵嬪姩鎷嗗寘
-        /// </summary>
-        public async Task<WebResponseContent> ManualSplitPackage(string orderNo, string batchNo, string originalBarcode, decimal splitQuantity)
-        {
-            try
-            {
-                _unitOfWorkManage.BeginTran();
-
-                // 1. 楠岃瘉鎷嗗寘璇锋眰
-                var validationResult = await ValidateManualSplitRequest(orderNo, batchNo, originalBarcode, splitQuantity);
-                if (!validationResult.IsValid)
-                    return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
-
-                var (lockInfo, stockDetail) = validationResult.Data;
-
-                // 2. 鎵ц鎷嗗寘閫昏緫
-                var splitResult = await ExecuteManualSplit(lockInfo, stockDetail, splitQuantity, batchNo);
-
-                _unitOfWorkManage.CommitTran();
-
-                return WebResponseContent.Instance.OK("鎵嬪姩鎷嗗寘鎴愬姛", new { NewBarcode = splitResult.NewBarcode });
-            }
-            catch (Exception ex)
-            {
-                _unitOfWorkManage.RollbackTran();
-                _logger.LogError($"鎵嬪姩鎷嗗寘澶辫触 - OrderNo: {orderNo}, BatchNo: {batchNo}, Barcode: {originalBarcode}, Error: {ex.Message}");
-                return WebResponseContent.Instance.Error($"鎵嬪姩鎷嗗寘澶辫触锛歿ex.Message}");
-            }
-        }
-
-        private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateManualSplitRequest(
-            string orderNo, string batchNo, string originalBarcode, decimal splitQuantity)
-        {
+            // 鎭㈠閿佸畾淇℃伅
             var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .Where(x => x.OrderNo == orderNo &&
-                           x.BatchNo == batchNo &&
-                           x.CurrentBarcode == originalBarcode &&
-                           x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
-                .FirstAsync();
+                .FirstAsync(x => x.Id == pickingRecord.OutStockLockId);
 
-            if (lockInfo == null)
-                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鏈壘鍒版湁鏁堢殑閿佸畾淇℃伅");
+            lockInfo.PickedQty -= pickingRecord.PickQuantity;
+            lockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�;
+            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
 
+            // 鎭㈠搴撳瓨
             var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                .FirstAsync(x => x.Barcode == originalBarcode && x.StockId == lockInfo.StockId);
+                .FirstAsync(x => x.Barcode == pickingRecord.Barcode);
 
-            if (stockDetail.StockQuantity < splitQuantity)
-                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鎷嗗寘鏁伴噺涓嶈兘澶т簬搴撳瓨鏁伴噺");
+            stockDetail.StockQuantity += pickingRecord.PickQuantity;
+            stockDetail.OutboundQuantity -= pickingRecord.PickQuantity;
+            stockDetail.Status = (int)StockStatusEmun.鍑哄簱閿佸畾;
+            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
 
-            if (lockInfo.AssignQuantity - lockInfo.PickedQty < splitQuantity)
-                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鎷嗗寘鏁伴噺涓嶈兘澶т簬鏈嫞閫夋暟閲�");
-
-            return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((lockInfo, stockDetail));
+            return new RevertPickingResult
+            {
+                LockInfo = lockInfo,
+                StockDetail = stockDetail
+            };
         }
 
-        private async Task<SplitResultDto> ExecuteManualSplit(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
-            decimal splitQuantity, string batchNo)
+        private async Task<SplitResultDto> ExecuteSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
+            decimal splitQuantity, string palletCode)
         {
             // 鐢熸垚鏂版潯鐮�
             string newBarcode = await GenerateNewBarcode();
@@ -289,22 +492,23 @@
             {
                 OrderNo = lockInfo.OrderNo,
                 OrderDetailId = lockInfo.OrderDetailId,
-                BatchNo = batchNo,
+                OutboundBatchNo = lockInfo.OutboundBatchNo,
                 MaterielCode = lockInfo.MaterielCode,
                 StockId = lockInfo.StockId,
                 OrderQuantity = splitQuantity,
                 AssignQuantity = splitQuantity,
                 PickedQty = 0,
                 LocationCode = lockInfo.LocationCode,
-                PalletCode = lockInfo.PalletCode,
+                PalletCode = palletCode,
                 Status = (int)OutLockStockStatusEnum.鍑哄簱涓�,
                 CurrentBarcode = newBarcode,
-                Operator = App.User.UserName, 
+                Operator = App.User.UserName,
             };
             await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync();
 
             // 鏇存柊鍘熼攣瀹氫俊鎭�
             lockInfo.AssignQuantity -= splitQuantity;
+            lockInfo.OrderQuantity -= splitQuantity;
             await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
 
             // 璁板綍鎷嗗寘鍘嗗彶
@@ -313,121 +517,83 @@
             return new SplitResultDto { NewBarcode = newBarcode };
         }
 
-        #endregion
-
-        #region 鍙栨秷鎷嗗寘
-
-        /// <summary>
-        /// 鍙栨秷鎷嗗寘
-        /// </summary>
-        public async Task<WebResponseContent> CancelSplitPackage(string orderNo, string batchNo, string newBarcode)
+        private async Task ExecuteCancelSplitLogic(Dt_SplitPackageRecord splitRecord, Dt_OutStockLockInfo newLockInfo, Dt_StockInfoDetail newStockDetail)
         {
-            try
-            {
-                _unitOfWorkManage.BeginTran();
+            // 鎭㈠鍘熷簱瀛�
+            var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == splitRecord.StockId);
 
-                // 鏌ユ壘鎷嗗寘璁板綍鍜屾柊閿佸畾淇℃伅
-                var splitRecord = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
-                    .Where(x => x.NewBarcode == newBarcode && x.OrderNo == orderNo && !x.IsReverted)
-                    .FirstAsync();
+            originalStock.StockQuantity += splitRecord.SplitQty;
+            await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync();
 
-                if (splitRecord == null)
-                    return WebResponseContent.Instance.Error("鏈壘鍒版媶鍖呰褰�");
+            // 鎭㈠鍘熼攣瀹氫俊鎭�
+            var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .FirstAsync(x => x.Id == splitRecord.OutStockLockInfoId);
 
-                var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                    .Where(x => x.CurrentBarcode == newBarcode && x.BatchNo == batchNo)
-                    .FirstAsync();
+            originalLockInfo.AssignQuantity += splitRecord.SplitQty;
+            originalLockInfo.OrderQuantity += splitRecord.SplitQty;
+            await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync();
 
-                if (newLockInfo == null)
-                    return WebResponseContent.Instance.Error("鏈壘鍒版柊閿佸畾淇℃伅");
+            // 鍒犻櫎鏂板簱瀛樻槑缁�
+            await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
+                .Where(x => x.Barcode == newLockInfo.CurrentBarcode)
+                .ExecuteCommandAsync();
 
-                // 鎭㈠鍘熷簱瀛�
-                var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                    .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == splitRecord.StockId);
+            // 鍒犻櫎鏂伴攣瀹氫俊鎭�
+            await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
+                .Where(x => x.Id == newLockInfo.Id)
+                .ExecuteCommandAsync();
 
-                originalStock.StockQuantity += splitRecord.SplitQty;
-                await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync();
-
-                // 鎭㈠鍘熼攣瀹氫俊鎭�
-                var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                    .FirstAsync(x => x.Id == splitRecord.OutStockLockInfoId);
-
-                originalLockInfo.AssignQuantity += splitRecord.SplitQty;
-                await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync();
-
-                // 鍒犻櫎鏂板簱瀛樻槑缁�
-                await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
-                    .Where(x => x.Barcode == newBarcode)
-                    .ExecuteCommandAsync();
-
-                // 鍒犻櫎鏂伴攣瀹氫俊鎭�
-                await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
-                    .Where(x => x.Id == newLockInfo.Id)
-                    .ExecuteCommandAsync();
-
-                // 鏍囪鎷嗗寘璁板綍涓哄凡鎾ら攢
-                splitRecord.IsReverted = true;
-                splitRecord.RevertTime = DateTime.Now;
-                splitRecord.Operator = App.User.UserName;
-                await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync();
-
-                _unitOfWorkManage.CommitTran();
-
-                return WebResponseContent.Instance.OK("鍙栨秷鎷嗗寘鎴愬姛");
-            }
-            catch (Exception ex)
-            {
-                _unitOfWorkManage.RollbackTran();
-                _logger.LogError($"鍙栨秷鎷嗗寘澶辫触 - OrderNo: {orderNo}, BatchNo: {batchNo}, Barcode: {newBarcode}, Error: {ex.Message}");
-                return WebResponseContent.Instance.Error($"鍙栨秷鎷嗗寘澶辫触锛歿ex.Message}");
-            }
+            // 鏍囪鎷嗗寘璁板綍涓哄凡鎾ら攢
+            splitRecord.IsReverted = true;
+            splitRecord.RevertTime = DateTime.Now;
+            splitRecord.RevertOperator = App.User.UserName;
+            await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync();
         }
 
         #endregion
 
-        #region 鍒嗘壒鍥炲簱
+        #region 鏁版嵁鏇存柊鏂规硶
 
-        /// <summary>
-        /// 鍒嗘壒鍥炲簱 - 閲婃斁鏈嫞閫夌殑搴撳瓨
-        /// </summary>
-        public async Task<WebResponseContent> BatchReturnStock(string orderNo, string batchNo)
+        private async Task UpdateBatchAndOrderData(Dt_OutboundBatch batch, Dt_OutboundOrderDetail orderDetail, decimal pickedQty, string orderNo)
         {
-            try
+            // 鏇存柊鎵规瀹屾垚鏁伴噺
+            batch.CompletedQuantity += pickedQty;
+            if (batch.CompletedQuantity >= batch.BatchQuantity)
             {
-                _unitOfWorkManage.BeginTran();
-
-                // 1. 鏌ユ壘鎵规鏈畬鎴愮殑閿佸畾璁板綍
-                var unfinishedLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                    .Where(x => x.OrderNo == orderNo &&
-                               x.BatchNo == batchNo &&
-                               x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
-                    .ToListAsync();
-
-                if (!unfinishedLocks.Any())
-                    return WebResponseContent.Instance.Error("璇ユ壒娆℃病鏈夋湭瀹屾垚鐨勯攣瀹氳褰�");
-
-                // 2. 閲婃斁搴撳瓨鍜岄攣瀹氳褰�
-                foreach (var lockInfo in unfinishedLocks)
-                {
-                    await ReleaseLockAndStock(lockInfo);
-                }
-
-                // 3. 鏇存柊鎵规鐘舵��
-                await UpdateBatchStatusForReturn(batchNo);
-
-                // 4. 鏇存柊璁㈠崟鏄庣粏鐨勫凡鍒嗛厤鏁伴噺
-                await UpdateOrderDetailAfterReturn(unfinishedLocks);
-
-                _unitOfWorkManage.CommitTran();
-
-                return WebResponseContent.Instance.OK("鍒嗘壒鍥炲簱鎴愬姛");
+                batch.BatchStatus = (int)BatchStatusEnum.宸插畬鎴�;
             }
-            catch (Exception ex)
-            {
-                _unitOfWorkManage.RollbackTran();
-                _logger.LogError($"鍒嗘壒鍥炲簱澶辫触 - OrderNo: {orderNo}, BatchNo: {batchNo}, Error: {ex.Message}");
-                return WebResponseContent.Instance.Error($"鍒嗘壒鍥炲簱澶辫触锛歿ex.Message}");
-            }
+            await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync();
+
+            // 鏇存柊璁㈠崟鏄庣粏
+            orderDetail.OverOutQuantity += pickedQty;
+            orderDetail.AllocatedQuantity -= pickedQty;
+            await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
+
+            // 妫�鏌ヨ鍗曠姸鎬�
+            await CheckAndUpdateOrderStatus(orderNo);
+        }
+
+        private async Task RevertBatchAndOrderData(Dt_PickingRecord pickingRecord)
+        {
+            // 鎭㈠鎵规瀹屾垚鏁伴噺
+            var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>()
+                .FirstAsync(x => x.BatchNo == pickingRecord.BatchNo);
+
+            batch.CompletedQuantity -= pickingRecord.PickQuantity;
+            batch.BatchStatus = (int)BatchStatusEnum.鎵ц涓�;
+            await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync();
+
+            // 鎭㈠璁㈠崟鏄庣粏
+            var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                .FirstAsync(x => x.Id == pickingRecord.OrderDetailId);
+
+            orderDetail.OverOutQuantity -= pickingRecord.PickQuantity;
+            orderDetail.AllocatedQuantity += pickingRecord.PickQuantity;
+            await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
+
+            // 閲嶆柊妫�鏌ヨ鍗曠姸鎬�
+            await CheckAndUpdateOrderStatus(pickingRecord.OrderNo);
         }
 
         private async Task ReleaseLockAndStock(Dt_OutStockLockInfo lockInfo)
@@ -443,20 +609,30 @@
             }
 
             // 鏇存柊閿佸畾璁板綍鐘舵�佷负鍥炲簱
-            lockInfo.Status = (int)OutLockStockStatusEnum.鍥炲簱涓�;
+            lockInfo.Status = (int)OutLockStockStatusEnum.宸插洖搴�;
             await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
         }
 
-        private async Task UpdateBatchStatusForReturn(string batchNo)
+        private async Task UpdateBatchStatusForReturn(string batchNo, List<Dt_OutStockLockInfo> returnedLocks)
         {
-            await _outboundBatchRepository.Db.Updateable<Dt_OutboundBatch>()
-                .SetColumns(x => new Dt_OutboundBatch
-                {
-                    BatchStatus = (int)BatchStatusEnum.宸插洖搴�,
-                    Operator = App.User.UserName
-                })
-                .Where(x => x.BatchNo == batchNo)
-                .ExecuteCommandAsync();
+            var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>()
+                .FirstAsync(x => x.BatchNo == batchNo);
+
+            // 璁$畻鍥炲簱鏁伴噺
+            var returnedQty = returnedLocks.Sum(x => x.AssignQuantity - x.PickedQty);
+            batch.CompletedQuantity -= returnedQty;
+
+            if (batch.CompletedQuantity <= 0)
+            {
+                batch.BatchStatus = (int)BatchStatusEnum.宸插洖搴�;
+            }
+            else
+            {
+                batch.BatchStatus = (int)BatchStatusEnum.鎵ц涓�;
+            }
+
+            batch.Operator = App.User.UserName;
+            await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync();
         }
 
         private async Task UpdateOrderDetailAfterReturn(List<Dt_OutStockLockInfo> returnedLocks)
@@ -482,10 +658,10 @@
         private async Task<string> GenerateNewBarcode()
         {
             var seq = await _dailySequenceService.GetNextSequenceAsync();
-            return "WSLOT" + DateTime.Now.ToString("yyyyMMdd") + seq.ToString()?.PadLeft(5, '0');
+            return "WSLOT" + DateTime.Now.ToString("yyyyMMdd") + seq.ToString().PadLeft(5, '0');
         }
 
-        private async Task RecordSplitHistory(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,decimal splitQty, string newBarcode)
+        private async Task RecordSplitHistory(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, decimal splitQty, string newBarcode)
         {
             var splitHistory = new Dt_SplitPackageRecord
             {
@@ -503,12 +679,12 @@
             await _splitPackageService.Db.Insertable(splitHistory).ExecuteCommandAsync();
         }
 
-        private async Task RecordPickingHistory(PickingResult result, string orderNo, string palletCode, string batchNo)
+        private async Task RecordPickingHistory(PickingResult result, string orderNo, string palletCode)
         {
             var pickingRecord = new Dt_PickingRecord
             {
                 OrderNo = orderNo,
-               // BatchNo = batchNo,
+                // BatchNo = result.FinalLockInfo.BatchNo,
                 OrderDetailId = result.FinalLockInfo.OrderDetailId,
                 PalletCode = palletCode,
                 Barcode = result.FinalLockInfo.CurrentBarcode,
@@ -516,53 +692,66 @@
                 PickQuantity = result.ActualPickedQty,
                 PickTime = DateTime.Now,
                 Operator = App.User.UserName,
-                OutStockLockId = result.FinalLockInfo.Id
+                OutStockLockId = result.FinalLockInfo.Id,
+                //  IsCancelled = false
             };
 
             await Db.Insertable(pickingRecord).ExecuteCommandAsync();
         }
 
-        private async Task UpdateOrderRelatedData(int orderDetailId, decimal pickedQty, string orderNo)
-        {
-            // 鏇存柊璁㈠崟鏄庣粏鐨勫凡鍑哄簱鏁伴噺
-            await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
-                .SetColumns(x => new Dt_OutboundOrderDetail
-                {
-                    OverOutQuantity = x.OverOutQuantity + pickedQty,
-                    AllocatedQuantity = x.AllocatedQuantity - pickedQty
-                })
-                .Where(x => x.Id == orderDetailId)
-                .ExecuteCommandAsync();
-
-            // 妫�鏌ヨ鍗曠姸鎬�
-            await CheckAndUpdateOrderStatus(orderNo);
-        }
-
         private async Task CheckAndUpdateOrderStatus(string orderNo)
         {
             var orderDetails = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
-                  .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id)
-                  .Where((o, item) => item.OrderNo == orderNo)
-                  .Select((o, item) => o)
-                  .ToListAsync();
-
-
+                .LeftJoin<Dt_OutboundOrder>((detail, order) => detail.OrderId == order.Id)
+                .Where((detail, order) => order.OrderNo == orderNo)
+                .Select((detail, order) => detail)
+                .ToListAsync();
 
             bool allCompleted = orderDetails.All(x => x.OverOutQuantity >= x.NeedOutQuantity);
 
-            if (allCompleted)
-            {
-                await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
-                    .SetColumns(x => new Dt_OutboundOrder { OrderStatus = (int)OutOrderStatusEnum.鍑哄簱瀹屾垚 })
-                    .Where(x => x.OrderNo == orderNo)
-                    .ExecuteCommandAsync();
-            }
+            var orderStatus = allCompleted ? (int)OutOrderStatusEnum.鍑哄簱瀹屾垚 : (int)OutOrderStatusEnum.鍑哄簱涓�;
+
+            await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
+                .SetColumns(x => x.OrderStatus == orderStatus)
+                .Where(x => x.OrderNo == orderNo)
+                .ExecuteCommandAsync();
+        }
+
+        #endregion
+
+        #region DTO绫�
+
+        public class PickingResult
+        {
+            public Dt_OutStockLockInfo FinalLockInfo { get; set; }
+            public decimal ActualPickedQty { get; set; }
+        }
+
+        public class RevertPickingResult
+        {
+            public Dt_OutStockLockInfo LockInfo { get; set; }
+            public Dt_StockInfoDetail StockDetail { get; set; }
+        }
+
+        public class SplitResultDto
+        {
+            public string NewBarcode { get; set; }
+        }
+
+        public class ValidationResult<T>
+        {
+            public bool IsValid { get; set; }
+            public string ErrorMessage { get; set; }
+            public T Data { get; set; }
+
+            public static ValidationResult<T> Success(T data) => new ValidationResult<T> { IsValid = true, Data = data };
+            public static ValidationResult<T> Error(string message) => new ValidationResult<T> { IsValid = false, ErrorMessage = message };
         }
 
         #endregion
     }
 
-    
+
     // 鏀寔绫�
     public class SplitResultDto
     {
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/OutboundOrderDetailService.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/OutboundOrderDetailService.cs"
index 450ce11..94e20ec 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/OutboundOrderDetailService.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/OutboundOrderDetailService.cs"
@@ -66,6 +66,11 @@
             var outboundOrder = _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
                 .First(x => x.Id == orderId);
 
+            if (!CanReassignOrder(outboundOrder))
+            {
+                throw new Exception($"璁㈠崟{outboundOrder.OrderNo}鐘舵�佷笉鍏佽閲嶆柊鍒嗛厤搴撳瓨");
+            }
+
             List<Dt_StockInfo> outStocks = new List<Dt_StockInfo>();
             List<Dt_OutStockLockInfo> outStockLockInfos = new List<Dt_OutStockLockInfo>();
             List<Dt_LocationInfo> locationInfos = new List<Dt_LocationInfo>();
@@ -79,7 +84,7 @@
                     BatchNo = x.Key.BatchNo,
                     SupplyCode = x.Key.SupplyCode,
                     Details = x.ToList(),
-                    TotalNeedQuantity = x.Sum(v => v.OrderQuantity - v.OverOutQuantity - v.LockQuantity - v.MoveQty)
+                    TotalNeedQuantity = CalculateReassignNeedQuantity(x.ToList())
                 })
                 .Where(x => x.TotalNeedQuantity > 0)
                 .ToList();
@@ -127,6 +132,39 @@
             }
 
             return (outStocks, outboundOrderDetails, outStockLockInfos, locationInfos);
+        }
+
+        /// <summary>
+        /// 妫�鏌ヨ鍗曟槸鍚﹀厑璁搁噸鏂板垎閰�
+        /// </summary>
+        private bool CanReassignOrder(Dt_OutboundOrder outboundOrder)
+        {
+            // 鍏佽閲嶆柊鍒嗛厤鐨勭姸鎬�
+            var allowedStatus = new[] {OutOrderStatusEnum.鏈紑濮�, OutOrderStatusEnum.鍑哄簱涓�,OutOrderStatusEnum.閮ㄥ垎瀹屾垚};
+
+            return allowedStatus.Contains((OutOrderStatusEnum)outboundOrder.OrderStatus);
+        }
+
+        /// <summary>
+        /// 閲嶆柊璁$畻闇�姹傛暟閲忥紙鑰冭檻閲嶆柊鍒嗛厤鐨勫満鏅級
+        /// </summary>
+        private decimal CalculateReassignNeedQuantity(List<Dt_OutboundOrderDetail> details)
+        {
+            decimal totalNeed = 0;
+
+            foreach (var detail in details)
+            {
+                // 鍏抽敭淇敼锛氶噸鏂板垎閰嶆椂锛屽彧鑰冭檻鏈嚭搴撶殑閮ㄥ垎锛屽拷鐣ラ攣瀹氭暟閲�
+                // 鍥犱负閿佸畾鏁伴噺鍦ㄥ洖搴撴椂宸茬粡琚噸缃�
+                decimal remainingNeed = detail.OrderQuantity - detail.OverOutQuantity - detail.MoveQty;
+
+                if (remainingNeed > 0)
+                {
+                    totalNeed += remainingNeed;
+                }
+            }
+
+            return totalNeed;
         }
         private (bool success, string message) DistributeLockQuantityByFIFO(
            List<Dt_OutboundOrderDetail> details,
@@ -231,7 +269,7 @@
         /// <summary>
         /// 涓哄垎鎵瑰垎閰嶅簱瀛�
         /// </summary>
-        public  async Task<(List<Dt_StockInfo>, List<Dt_OutboundOrderDetail>, List<Dt_OutStockLockInfo>, List<Dt_LocationInfo>)>
+        public async Task<(List<Dt_StockInfo>, List<Dt_OutboundOrderDetail>, List<Dt_OutStockLockInfo>, List<Dt_LocationInfo>)>
             AssignStockForBatch(Dt_OutboundOrderDetail orderDetail, decimal batchQuantity, string batchNo)
         {
             if (orderDetail == null)
@@ -263,7 +301,7 @@
             foreach (var item in groupDetails)
             {
                 var needQuantity = item.TotalNeedQuantity;
-                               
+
                 // 鑾峰彇鍙敤搴撳瓨锛堟寜鍏堣繘鍏堝嚭鎺掑簭锛�
                 List<Dt_StockInfo> stockInfos = _stockService.StockInfoService.GetUseableStocks(item.MaterielCode, item.BatchNo, item.SupplyCode);
                 if (!stockInfos.Any())
@@ -272,7 +310,7 @@
                 }
 
                 // 鍒嗛厤搴撳瓨锛堟寜鍏堣繘鍏堝嚭锛�
-                var (autoAssignStocks, stockAllocations) = _stockService.StockInfoService.GetOutboundStocks  (stockInfos, item.MaterielCode, needQuantity, out decimal residueQuantity);
+                var (autoAssignStocks, stockAllocations) = _stockService.StockInfoService.GetOutboundStocks(stockInfos, item.MaterielCode, needQuantity, out decimal residueQuantity);
 
                 // 妫�鏌ュ垎閰嶇粨鏋�
                 decimal allocatedQuantity = needQuantity - residueQuantity;
@@ -300,7 +338,7 @@
                 locationInfos.AddRange(_locationInfoService.GetLocationInfos(
                   outStocks.Select(x => x.LocationCode).Distinct().ToList()));
 
-             
+
             }
 
             return (outStocks, groupDetails.SelectMany(x => x.Details).ToList(), outStockLockInfos, locationInfos);
@@ -370,13 +408,13 @@
                     {
                         return (false, $"搴撳瓨鏄庣粏ID[{stockDetail.Id}]鐨勬潯鐮佷负绌�");
                     }
-                                 
+
 
                     // 鍒涘缓鍑哄簱閿佸畾淇℃伅
                     var lockInfo = _outStockLockInfoService.GetOutStockLockInfo(
-                        outboundOrder, detail, stockInfo, assignQuantity, stockDetail.Barcode,batchNo);
+                        outboundOrder, detail, stockInfo, assignQuantity, stockDetail.Barcode, batchNo);
                     outStockLockInfos.Add(lockInfo);
- 
+
                     // 鏇存柊鏄庣粏鐨勫凡鍒嗛厤鏁伴噺
                     detail.AllocatedQuantity += assignQuantity;
                     remainingAllocate -= assignQuantity;
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/OutboundOrderService.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/OutboundOrderService.cs"
index ab67148..51bb24d 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/OutboundOrderService.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/OutboundOrderService.cs"
@@ -72,7 +72,7 @@
                     item.MoveQty = moveissueoStockResult.Quantity;
                 }
 
-                if (model.OrderType != InOrderTypeEnum.Allocat.ObjToInt() || model.OrderType != InOrderTypeEnum.InternalAllocat.ObjToInt())
+                if (model.OrderType != InOrderTypeEnum.AllocatOutbound.ObjToInt() || model.OrderType != InOrderTypeEnum.InternalAllocat.ObjToInt())
                 {
                     model.OrderNo = CreateCodeByRule(nameof(RuleCodeEnum.OutboundOrderRule));
                 }
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/OutboundPickingService.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/OutboundPickingService.cs"
index a0497ba..2dc95ec 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/OutboundPickingService.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/OutboundPickingService.cs"
@@ -295,6 +295,8 @@
                 //鎵ц鍥炲簱鎿嶄綔
                 await ExecuteReturnOperations(orderNo, palletCode, stockInfo, task, statusAnalysis);
 
+                await ReleaseAllLocksForReallocation(orderNo, palletCode, statusAnalysis);
+
                 _unitOfWorkManage.CommitTran();
 
 
@@ -1307,6 +1309,116 @@
             await UpdateStockInfoStatus(stockInfo);
         }
 
+        /// <summary>
+        /// 瀹屽叏閲婃斁閿佸畾锛屽厑璁搁噸鏂板垎閰嶅簱瀛�
+        /// </summary>
+        private async Task ReleaseAllLocksForReallocation(string orderNo, string palletCode, PalletStatusAnalysis analysis)
+        {
+            _logger.LogInformation($"寮�濮嬮噴鏀鹃攣瀹氫互渚块噸鏂板垎閰� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}");
+
+            // 1. 澶勭悊鏈垎鎷g殑鍑哄簱閿佸畾璁板綍 - 瀹屽叏閲婃斁
+            if (analysis.HasRemainingLocks)
+            {
+                await ReleaseRemainingLocks(analysis.RemainingLocks);
+            }
+
+            // 2. 澶勭悊宸插洖搴撶殑閿佸畾璁板綍 - 鍒犻櫎鎴栨爣璁颁负鏃犳晥
+            await CleanupReturnedLocks(orderNo, palletCode);
+
+            // 3. 閲嶇疆璁㈠崟鏄庣粏鐨勯攣瀹氭暟閲�
+            await ResetOrderDetailLockQuantities(analysis);
+
+            _logger.LogInformation($"閿佸畾閲婃斁瀹屾垚 - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}");
+        }
+
+        /// <summary>
+        /// 閲婃斁鏈垎鎷g殑閿佸畾璁板綍
+        /// </summary>
+        private async Task ReleaseRemainingLocks(List<Dt_OutStockLockInfo> remainingLocks)
+        {
+            var lockIds = remainingLocks.Select(x => x.Id).ToList();
+
+            // 灏嗛攣瀹氳褰曠姸鎬佹敼涓�"宸查噴鏀�"锛屾垨鑰呯洿鎺ュ垹闄�
+            //  鏍囪涓哄凡閲婃斁 
+            await _outStockLockInfoService.Db.Updateable<Dt_OutStockLockInfo>()
+                .SetColumns(it => new Dt_OutStockLockInfo
+                {
+                    Status = (int)OutLockStockStatusEnum.宸查噴鏀�, // 闇�瑕佹柊澧炶繖涓姸鎬�
+                   // ReleaseTime = DateTime.Now,
+                    Operator = App.User.UserName
+                })
+                .Where(it => lockIds.Contains(it.Id))
+                .ExecuteCommandAsync();
+
+            //  鐩存帴鍒犻櫎锛堟洿褰诲簳锛�
+            // await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
+            //     .Where(it => lockIds.Contains(it.Id))
+            //     .ExecuteCommandAsync();
+
+            _logger.LogInformation($"閲婃斁{remainingLocks.Count}鏉℃湭鍒嗘嫞閿佸畾璁板綍");
+        }
+
+        /// <summary>
+        /// 娓呯悊宸插洖搴撶殑閿佸畾璁板綍
+        /// </summary>
+        private async Task CleanupReturnedLocks(string orderNo, string palletCode)
+        {
+            // 鏌ユ壘鎵�鏈夌姸鎬佷负鍥炲簱涓殑閿佸畾璁板綍骞堕噴鏀�
+            var returnedLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(it => it.OrderNo == orderNo &&
+                           it.PalletCode == palletCode &&
+                           it.Status == (int)OutLockStockStatusEnum.鍥炲簱涓�)
+                .ToListAsync();
+
+            if (returnedLocks.Any())
+            {
+                var returnedLockIds = returnedLocks.Select(x => x.Id).ToList();
+
+                await _outStockLockInfoService.Db.Updateable<Dt_OutStockLockInfo>()
+                    .SetColumns(it => new Dt_OutStockLockInfo
+                    {
+                        Status = (int)OutLockStockStatusEnum.宸查噴鏀�,
+                        //ReleaseTime = DateTime.Now,
+                        Operator = App.User.UserName
+                    })
+                    .Where(it => returnedLockIds.Contains(it.Id))
+                    .ExecuteCommandAsync();
+
+                _logger.LogInformation($"娓呯悊{returnedLocks.Count}鏉″洖搴撲腑閿佸畾璁板綍");
+            }
+        }
+
+        /// <summary>
+        /// 閲嶇疆璁㈠崟鏄庣粏鐨勯攣瀹氭暟閲�
+        /// </summary>
+        private async Task ResetOrderDetailLockQuantities(PalletStatusAnalysis analysis)
+        {
+            // 鏀堕泦鎵�鏈夊彈褰卞搷鐨勮鍗曟槑缁咺D
+            var affectedOrderDetailIds = new HashSet<int>();
+
+            if (analysis.HasRemainingLocks)
+            {
+                foreach (var lockInfo in analysis.RemainingLocks)
+                {
+                    affectedOrderDetailIds.Add(lockInfo.OrderDetailId);
+                }
+            }
+
+            // 閲嶇疆杩欎簺璁㈠崟鏄庣粏鐨勯攣瀹氭暟閲�
+            foreach (var orderDetailId in affectedOrderDetailIds)
+            {
+                await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
+                    .SetColumns(it => new Dt_OutboundOrderDetail
+                    {
+                        LockQuantity = 0, // 閲嶇疆閿佸畾鏁伴噺
+                        OrderDetailStatus = OrderDetailStatusEnum.New.ObjToInt() // 閲嶇疆鐘舵�佷负鏂板缓
+                    })
+                    .Where(it => it.Id == orderDetailId)
+                    .ExecuteCommandAsync();
+            }
+
+            _logger.LogInformation($"閲嶇疆{affectedOrderDetailIds.Count}涓鍗曟槑缁嗙殑閿佸畾鏁伴噺");
+        }
         private async Task HandleRemainingLocksReturn(List<Dt_OutStockLockInfo> remainingLocks, int stockId)
         {
             var lockIds = remainingLocks.Select(x => x.Id).ToList();
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 bcdc51f..abac8ee 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"
@@ -384,6 +384,13 @@
             return WebResponseContent.Instance.OK();
         }
 
+
+        public async Task<WebResponseContent> OutAllocateTaskCompleted(Dt_Task task)
+        {
+            _logger.LogInformation($"TaskService  OutAllocateTaskCompleted: {task.TaskNum}");
+
+           return  await OutboundTaskCompleted(task);          
+        }
         public async Task<WebResponseContent> OutboundTaskCompleted(Dt_Task task)
         {
             _logger.LogInformation($"TaskService  OutboundTaskCompleted: {task.TaskNum}");
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 6cbf577..d68097a 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"
@@ -143,14 +143,22 @@
             {
                 throw new Exception("鏈壘鍒板嚭搴撳崟鏄庣粏淇℃伅");
             }
-            if (outboundOrderDetails.FirstOrDefault(x => x.OrderDetailStatus > OrderDetailStatusEnum.New.ObjToInt() && x.OrderDetailStatus != OrderDetailStatusEnum.AssignOverPartial.ObjToInt()) != null)
+            //if (outboundOrderDetails.FirstOrDefault(x => x.OrderDetailStatus > OrderDetailStatusEnum.New.ObjToInt() && x.OrderDetailStatus != OrderDetailStatusEnum.AssignOverPartial.ObjToInt()) != null)
+            //{
+            //    throw new Exception("鎵�閫夊嚭搴撳崟鏄庣粏瀛樺湪鍑哄簱涓垨宸插畬鎴�");
+            //}
+
+            if (outboundOrderDetails.FirstOrDefault(x => x.OrderDetailStatus > OrderDetailStatusEnum.Outbound.ObjToInt() && x.OrderDetailStatus != OrderDetailStatusEnum.AssignOverPartial.ObjToInt()) != null)
             {
-                throw new Exception("鎵�閫夊嚭搴撳崟鏄庣粏瀛樺湪鍑哄簱涓垨宸插畬鎴�");
+                throw new Exception("鎵�閫夊嚭搴撳崟鏄庣粏瀛樺湪宸插畬鎴愮姸鎬侊紝鏃犳硶閲嶆柊鍒嗛厤");
             }
+
             List<Dt_StockInfo>? stockInfos = null;
             List<Dt_OutboundOrderDetail>? orderDetails = null;
             List<Dt_OutStockLockInfo>? outStockLockInfos = null;
             List<Dt_LocationInfo>? locationInfos = null;
+
+            CleanupPreviousInvalidLocks(outboundOrderDetails);
 
             (List<Dt_StockInfo>, List<Dt_OutboundOrderDetail>, List<Dt_OutStockLockInfo>, List<Dt_LocationInfo>) result = _outboundOrderDetailService.AssignStockOutbound(outboundOrderDetails);
             if (result.Item1 != null && result.Item1.Count > 0)
@@ -188,7 +196,31 @@
             }
             return (tasks, stockInfos, orderDetails, outStockLockInfos, locationInfos);
         }
+        /// <summary>
+        /// 娓呯悊涔嬪墠鐨勬棤鏁堥攣瀹氳褰�
+        /// </summary>
+        private  void  CleanupPreviousInvalidLocks(List<Dt_OutboundOrderDetail> orderDetails)
+        {
+            var orderIds = orderDetails.Select(x => x.OrderId).Distinct().ToList();
+            var orderNos =  _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
+                .Where(x => orderIds.Contains(x.Id))
+                .Select(x => x.OrderNo)
+                .ToList();
 
+            // 娓呯悊鐘舵�佷负"宸查噴鏀�"鎴�"鍥炲簱涓�"鐨勬棫閿佸畾璁板綍
+            foreach (var orderNo in orderNos)
+            {
+               _outStockLockInfoService.Db.Updateable<Dt_OutStockLockInfo>()
+                    .SetColumns(x => new Dt_OutStockLockInfo
+                    {
+                        Status = (int)OutLockStockStatusEnum.宸查噴鏀�
+                    })
+                    .Where(x => x.OrderNo == orderNo &&
+                               (x.Status == (int)OutLockStockStatusEnum.鍥炲簱涓� ||
+                                x.Status == (int)OutLockStockStatusEnum.宸查噴鏀�))
+                    .ExecuteCommand();
+            }
+        }
 
         /// <summary>
         /// 鐢熸垚鍑哄簱浠诲姟鍚庢暟鎹洿鏂板埌鏁版嵁搴�
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"
new file mode 100644
index 0000000..f481cc3
--- /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_WMSServer/Controllers/Outbound/OutboundBatchPickingController.cs"
@@ -0,0 +1,23 @@
+锘縰sing Microsoft.AspNetCore.Mvc;
+using WIDESEA_Core.BaseController;
+using WIDESEA_IOutboundService;
+using WIDESEA_Model.Models;
+
+namespace WIDESEA_WMSServer.Controllers.Outbound
+{
+ 
+    [Route("api/OutboundBatchPicking")]
+    [ApiController]
+    public class OutboundBatchPickingController : ApiBaseController<IOutboundBatchPickingService, Dt_PickingRecord>
+    {
+        private readonly ISplitPackageService _splitPackageService;
+        private readonly IOutStockLockInfoService _outStockLockInfoService;
+        public OutboundBatchPickingController(IOutboundBatchPickingService service, ISplitPackageService splitPackageService, IOutStockLockInfoService outStockLockInfoService) : base(service)
+        {
+            _splitPackageService = splitPackageService;
+            _outStockLockInfoService = outStockLockInfoService;
+        }
+
+    }
+
+}

--
Gitblit v1.9.3