heshaofeng
2025-11-24 0b0899370f271793f7156144b4b912438aebdf73
Merge branch 'master' of http://115.159.85.185:8098/r/ZhongRui/ALDbanyunxiangmu
已添加1个文件
已修改19个文件
1589 ■■■■ 文件已修改
项目代码/WIDESEA_WMSClient/src/extension/inbound/extend/SelectedStock.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/extension/inbound/extend/StockSelect.vue 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/extension/inbound/extend/allocateOrderDetail.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/extension/outbound/extend/NoStockOut.vue 380 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/extension/outbound/extend/outOrderDetail.vue 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/extension/stock/stockView.js 116 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/views/outbound/PickingConfirm.vue 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/views/stock/stockView.vue 228 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/CodeChunks.db-shm 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/SemanticSymbols.db-shm 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/OutboundOrderAddDTO.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/Stock/StockSelectViewDTO.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/Stock/StockViewDTO.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutboundPickingService.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs 601 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_StockService/StockInfoService.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_Outbound.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/OutboundPickingController.cs 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/extend/SelectedStock.vue
@@ -5,7 +5,7 @@
      :lazy="true"
      width="75%"
      :padding="15"
      title="出库详情"
      title="调拨出库详情"
    >
      <div class="box-head">
        <el-alert :closable="false" style="width: 100%">
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/extend/StockSelect.vue
@@ -136,7 +136,7 @@
      tableData: [],
      tableColumns: [
        { prop: "materielCode", title: "物料编号", type: "string", width: 150 },
        { prop: "materielName", title: "物料名称", type: "string", width: 150 },
        { prop: "barcode", title: "物料条码", type: "string", width: 150 },
        { prop: "palletCode", title: "托盘编号", type: "string", width: 150 },
        { prop: "locationCode", title: "货位编号", type: "string", width: 180 },
        { prop: "useableQuantity", title: "可用数量", type: "string" },
@@ -201,30 +201,23 @@
        if (!valid) return;
        // æž„造请求参数
        const keys = this.selection.map((item) => item.id);
        const requestParams = {
          taskIds: keys,
          outboundPlatform: this.outboundForm.selectedPlatform,
        };
          console.log(this.selection)
        // è°ƒç”¨å‡ºåº“接口
     if (this.selection.length <= 0) {
        return this.$message.error("请勾选");
      }
      let url = this.pkcx
        ? "api/Task/GenerateOutboundTask?orderDetailId="
        : "api/Task/GenerateOutboundTask?orderDetailId=";
        this.http
          .post("api/Task/GenerateOutboundTasks", requestParams, "数据处理中")
        .post(url + this.row.id, this.selection, "数据处理中")
          .then((x) => {
            if (!x.status) return ElMessage.error(x.message);
            ElMessage.success("操作成功");
            this.showOutboundDialog = false;
          if (!x.status) return this.$message.error(x.message);
          this.$message.success("操作成功");
            this.showDetialBox = false;
            this.$emit("parentCall", ($vue) => {
              $vue.getData();
            });
          })
          .catch((error) => {
            console.error("出库请求失败:", error);
            ElMessage.error("请求失败,请稍后重试");
          });
      });
    },
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/extend/allocateOrderDetail.vue
@@ -4,6 +4,7 @@
      v-model="showDetialBox"
      :lazy="true"
      width="75%"
      height="80%"
      title="单据明细信息"
    >
      <div class="box-head">
@@ -27,13 +28,13 @@
                @click="handleOpenPicking"
                >拣选</el-link>
                 
              <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"
@@ -362,7 +363,7 @@
        }
      }, {
        default: () => h(ElForm, {
          model: formData,
          model: formData00,
          rules: {
            selectedPlatform: [
              { required: true, message: '请选择出库站台', trigger: 'change' }
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/NoStockOut.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,380 @@
<template>
  <div>
    <vol-box
      v-model="showDetailBox"
      :lazy="true"
      width="65%"
      :padding="20"
      title="无库存出库"
      class="custom-vol-box"
    >
      <div>
        <!-- ä¸Šæ–¹è¾“入框 -->
        <el-form :inline="true" :model="formData" ref="formData" style="margin-bottom: 20px; align-items: flex-end;">
          <el-form-item
            label="扫描条码:"
            style="width: 80%"
            prop="barcode"
          >
            <el-input
              ref="barcodeInput"
              v-model="formData.barcode"
              placeholder="请使用扫码枪扫描条码,或手动输入"
              @keyup.enter="handleScan"
              autofocus
              class="custom-input"
            ></el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" size="small" @click="handleScan" class="custom-button">
              <i class="el-icon-search"></i> ç¡®è®¤æ‰«æ
            </el-button>
          </el-form-item>
        </el-form>
        <!-- ä¸‹æ–¹æ˜¾ç¤ºæ¡† -->
        <div class="scan-list">
          <el-card shadow="hover" style="margin-bottom: 10px; border: none;" class="custom-card">
            <div class="card-header">
              <span class="header-title">已扫描条码列表(共{{ scannedBarcodes.length }}条)</span>
              <el-button
                class="clear-all-btn"
                @click="clearAll"
                :disabled="scannedBarcodes.length === 0"
              >清空所有</el-button>
            </div>
            <div class="card-body">
              <el-scrollbar height="400px" class="custom-scrollbar">
                <!-- ä½¿ç”¨ transition-group åŒ…裹以实现动画 -->
                <transition-group name="barcode-item-transition">
                  <div class="barcode-item" v-for="(barcode, index) in scannedBarcodes" :key="barcode" :data-index="index">
                    <span class="barcode-text">{{ index + 1 }}. {{ barcode }}</span>
                    <el-button
                      class="delete-btn"
                      @click="removeItem(index)"
                    >删除</el-button>
                  </div>
                </transition-group>
                <div class="empty-tip" v-if="scannedBarcodes.length === 0">
                  <i class="el-icon-information"></i>
                  <span>暂无扫描记录,请扫描条码</span>
                </div>
              </el-scrollbar>
            </div>
          </el-card>
        </div>
      </div>
      <template #footer>
        <div class="footer-actions">
          <el-button type="primary" size="small" @click="submit" :disabled="scannedBarcodes.length === 0" class="submit-btn">
            <i class="el-icon-check"></i> æäº¤å‡ºåº“
          </el-button>
          <el-button type="text" size="small" @click="showDetailBox = false" class="cancel-btn">
            å–消
          </el-button>
        </div>
      </template>
    </vol-box>
  </div>
</template>
<script>
import VolBox from "@/components/basic/VolBox.vue";
export default {
  components: { VolBox },
  data() {
    return {
      showDetailBox: false,
      formData: {
        barcode: "",
      },
      scannedBarcodes: [],
    };
  },
  methods: {
    open() {
      this.showDetailBox = true;
      this.scannedBarcodes = [];
      this.formData.barcode = "";
      this.$nextTick(() => {
        this.$refs.barcodeInput.focus();
      });
    },
    handleScan() {
      const barcode = this.formData.barcode.trim();
      if (!barcode) {
        this.$refs.barcodeInput.focus();
        return;
      }
      if (this.scannedBarcodes.includes(barcode)) {
        this.$message.warning(`条码 ${barcode} å·²æ‰«æè¿‡ï¼Œè¯·å‹¿é‡å¤æ‰«æ`);
        this.formData.barcode = "";
        this.$refs.barcodeInput.focus();
        return;
      }
      this.scannedBarcodes.push(barcode);
      this.formData.barcode = "";
      this.$nextTick(() => {
        this.$refs.barcodeInput.focus();
      });
    },
    removeItem(index) {
      this.scannedBarcodes.splice(index, 1);
    },
    clearAll() {
      this.$confirm("确定要清空所有扫描记录吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(() => {
        this.scannedBarcodes = [];
      }).catch(() => {
        this.$refs.barcodeInput.focus();
      });
    },
    submit() {
      if (this.scannedBarcodes.length === 0) {
        this.$message.warning("请先扫描至少一条条码");
        this.$refs.barcodeInput.focus();
        return;
      }
      const params = {
        barcodes: this.scannedBarcodes,
      };
      this.http
        .post("/api/OutboundOrder/NoStockOut", params, "数据处理中...")
        .then((res) => {
          if (!res.status) {
            this.$message.error(res.message);
            this.$refs.barcodeInput.focus();
            return;
          }
          this.$message.success("出库成功");
          this.showDetailBox = false;
          this.$emit("parentCall", ($vue) => {
            $vue.refresh();
          });
        })
        .catch((err) => {
          this.$message.error(`请求失败:${err.message || "未知错误"}`);
          this.$refs.barcodeInput.focus();
        });
    },
  },
};
</script>
<style scoped>
/* å…³é”®ï¼šå®šä¹‰åˆ—表项的过渡动画 */
.barcode-item-transition-enter-active,
.barcode-item-transition-leave-active {
  transition: all 0.3s ease;
}
.barcode-item-transition-enter-from {
  opacity: 0;
  transform: translateY(10px);
}
.barcode-item-transition-leave-to {
  opacity: 0;
  transform: translateX(30px);
}
/* ç¡®ä¿åˆ é™¤æ—¶å…¶ä»–元素平滑上移 */
.barcode-item-transition-move {
  transition: transform 1s ease;
}
.scan-list {
  width: 100%;
}
.custom-card {
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08) !important;
  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
.custom-card:hover {
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12) !important;
}
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
  padding-bottom: 10px;
  border-bottom: 1px solid #f0f0f0;
}
.header-title {
  font-weight: 600;
  font-size: 15px;
  color: #333;
}
.clear-all-btn {
  color: #f56c6c;
  font-size: 13px;
  transition: color 0.2s;
}
.clear-all-btn:hover {
  color: #e53e3e;
  background: rgba(245, 108, 108, 0.1);
}
.card-body {
  padding: 0;
}
/* è‡ªå®šä¹‰æ»šåŠ¨æ¡ */
.custom-scrollbar ::v-deep .el-scrollbar__thumb {
  background: rgba(0, 0, 0, 0.2);
  border-radius: 4px;
  width: 4px;
}
.custom-scrollbar ::v-deep .el-scrollbar__bar:hover .el-scrollbar__thumb {
  background: rgba(0, 0, 0, 0.3);
  width: 6px;
}
.custom-scrollbar ::v-deep .el-scrollbar__wrap {
  overflow-x: hidden;
}
.barcode-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 15px;
  border-bottom: 1px solid #f7f7f7;
  transition: background-color 0.2s ease;
}
.barcode-item:hover {
  background-color: #fafafa;
}
/* ä¸ºå¥‡æ•°è¡Œæ·»åŠ è½»å¾®çš„èƒŒæ™¯è‰²ï¼Œå¢žå¼ºå¯è¯»æ€§ */
.barcode-item:nth-child(odd) {
  background-color: #e1e1e1;
}
.barcode-text {
  flex: 1;
  font-size: 14px;
  color: #666;
  transition: color 0.2s;
}
.barcode-item:hover .barcode-text {
  color: #409eff;
}
.delete-btn {
  color: #ea1919;
  font-size: 20px;
  transition: all 0.2s;
  transform: scale(0.8);
}
.barcode-item:hover .delete-btn {
  opacity: 1;
  transform: scale(1);
}
.delete-btn:hover {
  color: #f56c6c !important; /* ä½¿ç”¨ !important è¦†ç›– Element UI é»˜è®¤æ ·å¼ */
  background: rgba(245, 108, 108, 0.1);
}
.empty-tip {
  text-align: center;
  padding: 80px 0;
  color: #999;
  font-size: 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.empty-tip i {
  font-size: 40px;
  margin-bottom: 15px;
  color: #dcdfe6;
}
/* è‡ªå®šä¹‰è¾“入框 */
.custom-input ::v-deep .el-input__inner {
  border-radius: 6px;
  border-color: #e4e7ed;
  transition: all 0.3s;
  height: 36px;
  line-height: 36px;
}
.custom-input ::v-deep .el-input__inner:focus {
  border-color: #409eff;
  box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.1);
}
/* è‡ªå®šä¹‰æŒ‰é’® */
.custom-button {
  border-radius: 6px;
  height: 36px;
  line-height: 36px;
  font-size: 13px;
  font-weight: 500;
  transition: all 0.2s;
}
.custom-button:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.2);
}
.footer-actions {
  text-align: right;
}
.submit-btn {
  border-radius: 6px;
  font-weight: 500;
  padding: 10px 20px;
  transition: all 0.2s;
}
.submit-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(46, 164, 79, 0.2);
}
.cancel-btn {
  color: #666;
  margin-right: 10px;
  transition: color 0.2s;
}
.cancel-btn:hover {
  color: #333;
  background: #f5f5f5;
}
</style>
<style>
/* ... (全局样式部分保持不变) ... */
.text-button:hover {
  background-color: #f0f9eb !important;
}
.el-table .warning-row {
  background: oldlace;
}
.box-table .el-table tbody tr:hover > td {
  background-color: #d8e0d4 !important;
}
.box-table .el-table tbody tr.current-row > td {
  background-color: #f0f9eb !important;
}
.el-table .success-row {
  background: #f0f9eb;
}
.box-table .el-table {
  border: 1px solid #ebeef5;
}
.box-head .el-alert__content {
  width: 100%;
}
</style>
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/outOrderDetail.vue
@@ -103,6 +103,7 @@
      ref="selectedStock"
      @parentCall="parentCall"
    ></selected-stock>
    <NoStockOut ref="NoStockOut" @parentCall="parentCall"></NoStockOut>
  </div>
</template>
<script>
@@ -110,10 +111,12 @@
import VolForm from "@/components/basic/VolForm.vue";
import StockSelect from "./StockSelect.vue";
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 { th } from 'element-plus/es/locale';
export default {
  components: { VolBox, VolForm, StockSelect, SelectedStock },
  components: { VolBox, VolForm, StockSelect, SelectedStock,NoStockOut},
  data() {
    return {
      row: null,
@@ -189,7 +192,7 @@
          prop: "orderDetailStatus",
          title: "订单明细状态",
          type: "tag",
          width: 180,
          width: 90,
          bindKey: "orderDetailStatusEnum",
        },
        {
@@ -198,6 +201,13 @@
          type: "icon",
          width: 90,
          icon: "el-icon-s-grid",
        },
        {
          prop: "NoStockOut",
          title: "无库存出库",
          type: "icon",
          width: 100,
          icon: "el-icon-setting",
        },
        {
          prop: "viewDetail",
@@ -304,6 +314,8 @@
    tableButtonClick(row, column) {
      if (column.prop == "assignStock") {
        this.$refs.child.open(row);
      } else if (column.prop == "NoStockOut") {
        this.$refs.NoStockOut.open(row);
      } else {
        //点击打开出库详情
        this.$refs.selectedStock.open(row);
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/stock/stockView.js
@@ -1,8 +1,4 @@
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
import { el } from "element-plus/es/locales.mjs";
let extension = {
  components: {
    //查询界面扩展组件
@@ -35,65 +31,65 @@
      //       });
      //   }
      // }
      this.columns.forEach(column => {
        if (column.field == 'materielCode') {
          column.formatter = (row) => {
            var str = '';
            var list = row.materielCode.split(',');
            for (let index = 0; index < list.length; index++) {
              str += list[index] + '<br>';
            }
            return str = list[0] == "" ? "空箱" : str;
          }
        }
        if (column.field == 'batchNo') {
          column.formatter = (row) => {
            var str = '';
            var list = row.batchNo.split(',');
            for (let index = 0; index < list.length; index++) {
              str += list[index] + '<br>';
            }
            return str = list[0] == "" ? "无" : str;
          }
        }
        if (column.field == 'materielInfo') {
          const today = new Date()
          column.formatter = (row) => {
            if (row.details.length > 0) {
              const today = new Date();
              const closestDate = row.details
                .map(x => {
                  const date = new Date(x.effectiveDate);
                  const diffInDays = Math.ceil(Math.abs((today - date) / (1000 * 60 * 60 * 24)));
                  return { date, diffInDays };
                })
                .reduce((closest, current) => (current.diffInDays < closest.diffInDays ? current : closest))
                .date;
      // this.columns.forEach(column => {
      //   if (column.field == 'materielCode') {
      //     column.formatter = (row) => {
      //       var str = '';
      //       var list = row.materielCode.split(',');
      //       for (let index = 0; index < list.length; index++) {
      //         str += list[index] + '<br>';
      //       }
      //       return str = list[0] == "" ? "空箱" : str;
      //     }
      //   }
      //   if (column.field == 'batchNo') {
      //     column.formatter = (row) => {
      //       var str = '';
      //       var list = row.batchNo.split(',');
      //       for (let index = 0; index < list.length; index++) {
      //         str += list[index] + '<br>';
      //       }
      //       return str = list[0] == "" ? "无" : str;
      //     }
      //   }
      //   if (column.field == 'materielInfo') {
      //     const today = new Date()
      //     column.formatter = (row) => {
      //       if (row.details.length > 0) {
      //         const today = new Date();
      //         const closestDate = row.details
      //           .map(x => {
      //             const date = new Date(x.effectiveDate);
      //             const diffInDays = Math.ceil(Math.abs((today - date) / (1000 * 60 * 60 * 24)));
      //             return { date, diffInDays };
      //           })
      //           .reduce((closest, current) => (current.diffInDays < closest.diffInDays ? current : closest))
      //           .date;
              const daysSinceClosest = Math.ceil(Math.abs((today - closestDate) / (1000 * 60 * 60 * 24)));
              return '<span style="color: #F56C6C">' + daysSinceClosest + "天" + '</span>';
            } else {
              return '<span style="color: #F56C6C">' + "无保质期" + '</span>';
            }
      //         const daysSinceClosest = Math.ceil(Math.abs((today - closestDate) / (1000 * 60 * 60 * 24)));
      //         return '<span style="color: #F56C6C">' + daysSinceClosest + "天" + '</span>';
      //       } else {
      //         return '<span style="color: #F56C6C">' + "无保质期" + '</span>';
      //       }
          }
        }
        if (column.field == 'sumStock') {
          column.formatter = (row) => {
            if (row.details.length > 0) {
              var sum = 0;
              const closestDate = row.details
                .map(x => {
                  sum += (x.stockQuantity)
                })
              return '<span style="color: #F56C6C">' + sum + row.details[0].unit + '</span>';
            } else {
              return '<span style="color: #F56C6C">' + "1个" + '</span>';
            }
      //     }
      //   }
      //   if (column.field == 'sumStock') {
      //     column.formatter = (row) => {
      //       if (row.details.length > 0) {
      //         var sum = 0;
      //         const closestDate = row.details
      //           .map(x => {
      //             sum += (x.stockQuantity)
      //           })
      //         return '<span style="color: #F56C6C">' + sum + row.details[0].unit + '</span>';
      //       } else {
      //         return '<span style="color: #F56C6C">' + "1个" + '</span>';
      //       }
          }
        }
      })
      //     }
      //   }
      // })
    },
    onInited() {
      //框架初始化配置后
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/outbound/PickingConfirm.vue
@@ -28,7 +28,7 @@
          <el-button type="success" @click="confirmPicking">确认拣选</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>
          <!-- <el-button type="danger" @click="handleDirectOutbound">直接出库</el-button>  -->
@@ -250,6 +250,49 @@
        </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>
  </div>
    <!-- ç›´æŽ¥å‡ºåº“弹窗 -->
    <div v-if="showDirectOutDialog" class="custom-dialog-overlay">
      <div class="custom-dialog-wrapper">
@@ -290,7 +333,7 @@
        </div>
      </div>
    </div>
  </div>
  <print-view ref="childs" @parentcall="parentcall"></print-view>
</template>
@@ -431,6 +474,20 @@
          { required: true, validator: validateDirectOutPalletCode, trigger: 'blur' }
        ]
      },
      showEmptyPalletDialog: false, // å–走空箱弹窗显示状态
      emptypalletOutLoading: false, // å–走空箱加载状态
      emptypalletOutForm: {
        orderNo: '',
        palletCode: ''
      },
      emptypalletOutFormRules: {
        palletCode: [
          { required: true, validator: validateDirectOutPalletCode, trigger: 'blur' }
        ]
      },
      returnForm: {
        orderNo: '',
        palletCode: '',
@@ -708,6 +765,109 @@
    handleDirectOutbound() {
      this.openDirectOutDialog();
    },
   // æ‰“开取走空箱弹窗
    openEmptyPalletDialog() {
      console.log('打开取走空箱弹窗');
      this.showEmptyPalletDialog = true;
      // é‡ç½®è¡¨å•
      this.resetEmptyPalletForm();
      // è®¾ç½®è®¢å•信息
      this.emptypalletOutForm.orderNo = this.scanData.orderNo;
      // æ¸…除表单验证
      this.$nextTick(() => {
        if (this.$refs.emptyPalletFormRef) {
          this.$refs.emptyPalletFormRef.clearValidate();
        }
      });
    },
    // å…³é—­å–走空箱弹窗
    closeEmptyPalletDialog() {
      this.showEmptyPalletDialog = false;
      this.resetEmptyPalletForm();
      // æ¸…除表单验证
      if (this.$refs.emptyPalletFormRef) {
        this.$refs.emptyPalletFormRef.clearValidate();
      }
    },
    // å–走空箱托盘码扫码
    onEmptyPalletScan() {
      if (!this.emptypalletOutForm.palletCode) return;
      this.emptypalletOutForm.palletCode = this.emptypalletOutForm.palletCode.replace(/\n/g, '').trim();
      // æ¸…除验证状态
      if (this.$refs.emptyPalletFormRef) {
        this.$refs.emptyPalletFormRef.clearValidate(['palletCode']);
      }
    },
    // å–走空箱确认
    async handleEmptyPalletConfirm() {
      // è¡¨å•验证
      if (this.$refs.emptyPalletFormRef) {
        this.$refs.emptyPalletFormRef.validate((valid) => {
          if (valid) {
            this.submitEmptyPallet();
          } else {
            this.$message.warning('请扫描托盘码');
            return false;
          }
        });
      } else {
        // å¦‚果没有表单引用,使用原有的验证
        if (!this.emptypalletOutForm.palletCode) {
          this.$message.warning('请扫描托盘码');
          return;
        }
        this.submitEmptyPallet();
      }
    },
    // æäº¤å–走空箱请求
    async submitEmptyPallet() {
      this.emptypalletOutLoading = true;
      try {
        const res = await this.http.post('/api/OutboundPicking/remove-empty-pallet', {
          orderNo: this.emptypalletOutForm.orderNo,
          palletCode: this.emptypalletOutForm.palletCode
        });
        debugger;
        if (res.status) {
          this.$message.success('取走空箱成功');
          this.showEmptyPalletDialog = false;
          this.loadData();
        } else {
          this.$message.error(res.message || '取走空箱失败');
        }
      } catch (error) {
        this.$message.error('取走空箱失败');
      } finally {
        this.emptypalletOutLoading = false;
      }
    },
    // é‡ç½®å–走空箱表单
    resetEmptyPalletForm() {
      this.emptypalletOutForm.palletCode = '';
    },
    // ä¿®æ”¹åŽŸæœ‰çš„å–èµ°ç©ºç®±æŒ‰é’®ç‚¹å‡»äº‹ä»¶
    handleEmptyPallet() {
      this.openEmptyPalletDialog();
    },
    async loadData() {
      if (!this.scanData.orderNo || !this.scanData.palletCode) {
        return;
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/stock/stockView.vue
@@ -27,18 +27,12 @@
      sortName: "stockId",
    });
    const editFormFields = ref({
      palletCode: "",
      locationCode: "",
      locationName: "",
    });
    const editFormOptions = ref([
      
    ]);
    const searchFormFields = ref({
      palletCode: "",
      // locationCode: "",
      materielCode:"",
      batchNo:""
    });
    const searchFormOptions = ref([
      [
@@ -69,7 +63,7 @@
        title: "托盘编号",
        type: "string",
        width: 150,
        link: true,
        // link: true,
        align: "left",
      },
      {
@@ -92,7 +86,6 @@
        type: "string",
        width: 80,
        align: "left",
        bind: { key: "warehouses", data: [] },
      },
      {
        field: "roadwayNo",
@@ -110,90 +103,13 @@
        align: "left",
      },
      {
        field: "batchNo",
        title: "所含物料批次",
        type: "string",
        width: 200,
        align: "left"
      },
      {
        field: "materielInfo",
        title: "所含物料最早临期",
        type: "string",
        width: 140,
        align: "left",
      },
      {
        field: "sumStock",
        title: "总库存",
        type: "string",
        width: 140,
        align: "left",
      },
      {
        field: "row",
        title: "货位行",
        type: "string",
        width: 90,
        align: "left",
        hidden: true,
      },
      {
        field: "column",
        title: "货位列",
        type: "int",
        width: 120,
        align: "left",
        hidden: true,
      },
      {
        field: "layer",
        title: "货位层",
        type: "string",
        width: 200,
        align: "left",
        hidden: true,
      },
      {
        field: "depth",
        title: "货位深度",
        type: "string",
        width: 180,
        align: "left",
        hidden: true,
      },
      {
        field: "stockStatus",
        title: "库存状态",
        type: "string",
        width: 200,
        align: "left",
        bind: { key: "stockStatusEmun", data: [] },
      },
      {
        field: "locationType",
        title: "货位类型",
        type: "string",
        width: 100,
        align: "left",
        bind:{key: "locationTypeEnum", data: []}
      },
      {
        field: "locationStatus",
        title: "货位状态",
        type: "string",
        width: 120,
        align: "left",
        bind: { key: "locationStatusEnum", data: [] },
      },
      {
        field: "enalbeStatus",
        title: "禁用状态",
        type: "string",
        width: 80,
        align: "left",
        bind: { key: "enableStatusEnum", data: [] },
      },
      {
        field: "creater",
        title: "创建人",
@@ -235,143 +151,7 @@
      cnName: "库存明细信息",
      table: "StockInfoDetail",
      columns: [
        {
          field: "id",
          title: "Id",
          type: "int",
          width: 90,
          hidden: true,
          readonly: true,
          require: true,
          align: "left",
        },
        {
          field: "stockId",
          title: "库存信息主键",
          type: "string",
          width: 90,
          align: "left",
          hidden: true
        },
        {
          field: "materielCode",
          title: "物料编号",
          type: "string",
          width: 110,
          align: "left",
        },
        {
          field: "materielName",
          title: "物料名称",
          type: "string",
          width: 130,
          align: "left",
        },
        {
          field: "orderNo",
          title: "单据编号",
          type: "decimal",
          width: 130,
          align: "left",
        },
        {
          field: "batchNo",
          title: "批次号",
          type: "string",
          width: 180,
          align: "left",
        },
        {
          field: "serialNumber",
          title: "序列号",
          type: "int",
          width: 120,
          align: "left",
          hidden: true,
        },
        {
          field: "stockQuantity",
          title: "库存数量",
          type: "string",
          width: 80,
          align: "left",
        },
        {
          field: "outboundQuantity",
          title: "出库数量",
          type: "string",
          width: 80,
          align: "left",
        },
        {
          field: "unit",
          title: "单位",
          type: "string",
          width: 50,
          align: "left",
        },
        {
          field: "productionDate",
          title: "生产日期",
          type: "string",
          width: 80,
          align: "left",
        },
        {
          field: "effectiveDate",
          title: "有效日期",
          type: "string",
          width: 80,
          align: "left",
        },
        {
          field: "status",
          title: "库存明细状态",
          type: "string",
          width: 120,
          align: "left",
          bind: { key: "stockStatusEmun", data: [] }
        },
        {
          field: "creater",
          title: "创建人",
          type: "string",
          width: 90,
          align: "left",
          hidden: true
        },
        {
          field: "createDate",
          title: "创建时间",
          type: "datetime",
          width: 160,
          align: "left",
          hidden: true
        },
        {
          field: "modifier",
          title: "修改人",
          type: "string",
          width: 100,
          align: "left",
          hidden: true
        },
        {
          field: "modifyDate",
          title: "修改时间",
          type: "datetime",
          width: 160,
          align: "left",
          hidden: true
        },
        {
          field: "remark",
          title: "备注",
          type: "string",
          width: 100,
          align: "left",
          hidden: true
        },
      ],
      sortName: "id",
      key: "id",
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/CodeChunks.db-shm
Binary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/SemanticSymbols.db-shm
Binary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs
@@ -189,6 +189,10 @@
                if (first != null)
                {
                    locationCaches.Add(new LocationCache { LocationCode = first.LocationCode, DateTime = DateTime.Now });
                    Db.Updateable<Dt_LocationInfo>().SetColumns(x => new Dt_LocationInfo
                    {
                        LocationStatus = (int)LocationStatusEnum.InStockLock,
                    }).Where(x => x.Id == first.Id).ExecuteCommand();
                }
                return first;
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/OutboundOrderAddDTO.cs
@@ -92,6 +92,8 @@
        /// </summary>
        public string orderNo { get; set; }
        public string documentsNO { get; set; }
        public string business_type { get; set; }
        public int status { get; set; }
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Stock/StockSelectViewDTO.cs
@@ -20,5 +20,6 @@
        public string LocationCode { get; set; }
        
        public string Barcode { get; set; }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Stock/StockViewDTO.cs
@@ -22,11 +22,13 @@
        /// <summary>
        /// è´§ä½ç¼–号
        /// </summary>
        [SugarColumn(Length = 255, ColumnDescription = "货位编号")]
        public string LocationCode { get; set; }
        /// <summary>
        /// è´§ä½åç§°
        /// </summary>
        [SugarColumn(Length = 255, ColumnDescription = "货位名称")]
        public string LocationName { get; set; }
        /// <summary>
@@ -62,6 +64,7 @@
        /// <summary>
        /// å··é“编号
        /// </summary>
        [SugarColumn(Length = 255, ColumnDescription = "巷道编号")]
        public string RoadwayNo { get; set; }
        /// <summary>
@@ -77,6 +80,7 @@
        /// <summary>
        /// æ‰˜ç›˜å·
        /// </summary>
        [SugarColumn(Length = 255, ColumnDescription = "托盘号")]
        public string PalletCode { get; set; }
        /// <summary>
@@ -87,11 +91,13 @@
        /// <summary>
        /// ç‰©æ–™ç¼–码
        /// </summary>
        [SugarColumn(Length = 255, ColumnDescription = "物料编码")]
        public string MaterielCode { get; set; }
        /// <summary>
        /// ç‰©æ–™æ‰¹å·
        /// </summary>
        [SugarColumn(Length = 255, ColumnDescription = "物料批号")]
        public string BatchNo { get; set; }
        /// <summary>
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutboundPickingService.cs
@@ -24,5 +24,7 @@
        Task<WebResponseContent> CancelPicking(string orderNo, string palletCode, string barcode);
        Task<WebResponseContent> ConfirmPicking(string orderNo, string palletCode, string barcode);
        Task<WebResponseContent> ReturnRemaining(string orderNo, string palletCode, string reason);
        Task<WebResponseContent> RemoveEmptyPallet(string orderNo, string palletCode);
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs
@@ -299,7 +299,7 @@
            if (!checkResult.Item1) throw new Exception(checkResult.Item2);
            Dt_OutboundOrder outboundOrder = _outboundOrderService.Repository.QueryFirst(x => x.Id == outboundOrderDetail.OrderId);
            var originalNeedQuantity = outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity;
            var originalNeedQuantity = outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity-outboundOrderDetail.MoveQty;
            var needQuantity = originalNeedQuantity;
@@ -352,10 +352,10 @@
            {
                return (false, "该明细不可操作");
            }
            if (stockSelectViews.Sum(x => x.UseableQuantity) > outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity)
            {
                return (false, "选择数量超出单据数量");
            }
            //if (stockSelectViews.Sum(x => x.UseableQuantity) > outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity - outboundOrderDetail.MoveQty)
            //{
            //    return (false, "选择数量超出单据数量");
            //}
            return (true, "成功");
        }
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -10,6 +10,7 @@
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using WIDESEA_Common.CommonEnum;
using WIDESEA_Common.LocationEnum;
using WIDESEA_Common.OrderEnum;
using WIDESEA_Common.StockEnum;
@@ -17,6 +18,7 @@
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
using WIDESEA_Core.Enums;
using WIDESEA_Core.Helper;
using WIDESEA_DTO.Basic;
using WIDESEA_DTO.Inbound;
@@ -86,6 +88,8 @@
            _dailySequenceService = dailySequenceService;
        }
        #region æŸ¥è¯¢æ–¹æ³•
        // èŽ·å–æœªæ‹£é€‰åˆ—è¡¨
        public async Task<List<Dt_OutStockLockInfo>> GetUnpickedList(string orderNo, string palletCode)
        {
@@ -147,6 +151,8 @@
            return summary;
        }
        #endregion
        #region æ ¸å¿ƒä¸šåŠ¡æµç¨‹
        /// <summary>
@@ -252,11 +258,11 @@
            {
                _unitOfWorkManage.BeginTran();
                // 1. åŸºç¡€éªŒè¯
                if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode))
                    return WebResponseContent.Instance.Error("订单号和托盘码不能为空");
                // 2. èŽ·å–åº“å­˜å’Œä»»åŠ¡ä¿¡æ¯
                //  èŽ·å–åº“å­˜å’Œä»»åŠ¡ä¿¡æ¯
                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>().FirstAsync(x => x.PalletCode == palletCode);
                if (stockInfo == null)
@@ -266,23 +272,34 @@
                if (task == null)
                    return WebResponseContent.Instance.Error("未找到对应的任务信息");
                // 3. åˆ†æžéœ€è¦å›žåº“的货物
                var returnAnalysis = await AnalyzeReturnItems(orderNo, palletCode, stockInfo.Id);
                if (!returnAnalysis.HasItemsToReturn)
                    return await HandleNoReturnItems(orderNo, palletCode,task);
                //分析需要回库的货物
                //var returnAnalysis = await AnalyzeReturnItems(orderNo, palletCode, stockInfo.Id);
                //if (!returnAnalysis.HasItemsToReturn)
                //    return await HandleNoReturnItems(orderNo, palletCode, task);
                // 4. æ‰§è¡Œå›žåº“操作
                await ExecuteReturnOperations(orderNo, palletCode, stockInfo, task, returnAnalysis);
                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
                if (!statusAnalysis.HasItemsToReturn)
                    return await HandleNoReturnItems(orderNo, palletCode, task, stockInfo.Id);
                // 5. åˆ›å»ºå›žåº“任务
                await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, returnAnalysis);
                // 4. æ£€æŸ¥æ˜¯å¦æœ‰è¿›è¡Œä¸­çš„任务
                if (statusAnalysis.HasActiveTasks)
                {
                    return WebResponseContent.Instance.Error($"托盘 {palletCode} æœ‰è¿›è¡Œä¸­çš„任务,不能执行回库操作");
                }
                //执行回库操作
                await ExecuteReturnOperations(orderNo, palletCode, stockInfo, task, statusAnalysis);
                _unitOfWorkManage.CommitTran();
                // 6. æ›´æ–°è®¢å•状态(不触发MES回传)
                // åˆ›å»ºå›žåº“任务
                await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, TaskTypeEnum.InPick);
                // æ›´æ–°è®¢å•状态(不触发MES回传)
                await UpdateOrderStatusForReturn(orderNo);
                return WebResponseContent.Instance.OK($"回库操作成功,共回库数量:{returnAnalysis.TotalReturnQty}");
                return WebResponseContent.Instance.OK($"回库操作成功,共回库数量:{statusAnalysis.TotalReturnQty}");
            }
            catch (Exception ex)
            {
@@ -292,6 +309,71 @@
            }
        }
        /// <summary>
        /// ç©ºæ‰˜ç›˜å–走接口(带订单号)
        /// éªŒè¯æ‰˜ç›˜æ˜¯å¦çœŸçš„为空,清理数据,更新订单状态,创建取托盘任务
        /// </summary>
        public async Task<WebResponseContent> RemoveEmptyPallet(string orderNo, string palletCode)
        {
            try
            {
                _unitOfWorkManage.BeginTran();
                if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode))
                    return WebResponseContent.Instance.Error("订单号和托盘码不能为空");
                // æ£€æŸ¥è®¢å•是否存在
                var order = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
                    .Where(x => x.OrderNo == orderNo)
                    .FirstAsync();
                if (order == null)
                    return WebResponseContent.Instance.Error($"未找到订单 {orderNo}");
                //检查托盘是否存在且属于该订单
                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
                    .Where(x => x.PalletCode == palletCode)
                    .FirstAsync();
                if (stockInfo == null)
                    return WebResponseContent.Instance.Error($"未找到托盘 {palletCode} å¯¹åº”的库存信息");
                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
                if (!statusAnalysis.CanRemove)
                {
                    if (!statusAnalysis.IsEmptyPallet)
                    {
                        return WebResponseContent.Instance.Error($"托盘 {palletCode} ä¸Šè¿˜æœ‰è´§ç‰©ï¼Œä¸èƒ½å–èµ°");
                    }
                    if (statusAnalysis.HasActiveTasks)
                    {
                        return WebResponseContent.Instance.Error($"托盘 {palletCode} è¿˜æœ‰è¿›è¡Œä¸­çš„任务,不能取走");
                    }
                }
                // æ¸…理零库存数据
                await CleanupZeroStockData(stockInfo.Id);
                // åˆ é™¤æˆ–取消相关任务
                await HandleTaskCleanup(orderNo, palletCode);
                // æ›´æ–°è®¢å•相关数据
                await UpdateOrderData(orderNo, palletCode);
                _unitOfWorkManage.CommitTran();
                _logger.LogInformation($"空托盘取走操作成功 - è®¢å•: {orderNo}, æ‰˜ç›˜: {palletCode}, æ“ä½œäºº: {App.User.UserName}");
                return WebResponseContent.Instance.OK("空托盘取走操作成功");
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                _logger.LogError($"RemoveEmptyPallet失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
                return WebResponseContent.Instance.Error($"空托盘取走失败: {ex.Message}");
            }
        }
        #endregion
        #region åˆ†æ‹£ç¡®è®¤ç§æœ‰æ–¹æ³•
@@ -501,30 +583,34 @@
        {
            decimal remainingStockQty = stockQuantity - actualQty;
            // 1. æ›´æ–°åŽŸæ¡ç åº“å­˜
            // æ›´æ–°åŽŸæ¡ç åº“å­˜
            stockDetail.StockQuantity = remainingStockQty;
            stockDetail.OutboundQuantity = remainingStockQty;
            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
            // 2. ç”Ÿæˆæ–°æ¡ç 
            //生成新条码
            string newBarcode = await GenerateNewBarcode();
            // 3. åˆ›å»ºæ–°é”å®šä¿¡æ¯
            //创建新锁定信息
            var newLockInfo = await CreateSplitLockInfo(lockInfo, actualQty, newBarcode);
            // 4. è®°å½•拆包历史
            // è®°å½•拆包历史
            await RecordSplitHistory(lockInfo, stockDetail, actualQty, remainingStockQty, newBarcode);
            // 5. æ›´æ–°åŽŸé”å®šä¿¡æ¯
            // æ›´æ–°åŽŸé”å®šä¿¡æ¯
            lockInfo.AssignQuantity = remainingStockQty;
            lockInfo.PickedQty = 0;
            lockInfo.Operator = App.User.UserName;
            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
            // 6. è®¾ç½®ç»“æžœ
            // è®¾ç½®ç»“æžœ
            result.FinalLockInfo = newLockInfo;
            result.FinalBarcode = newBarcode;
            result.SplitResults.AddRange(CreateSplitResults(lockInfo, actualQty, remainingStockQty, newBarcode, stockDetail.Barcode));
            await UpdateOrderRelatedData(lockInfo.OrderDetailId, actualQty, lockInfo.OrderNo);
            _logger.LogInformation($"拆包分拣更新订单明细 - OrderDetailId: {lockInfo.OrderDetailId}, åˆ†æ‹£æ•°é‡: {actualQty}");
        }
        private async Task HandleFullPicking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
@@ -846,6 +932,8 @@
            await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
                .Where(x => x.Id == lockInfo.Id)
                .ExecuteCommandAsync();
            await UpdateOrderDetailOnCancel(pickingRecord.OrderDetailId, cancelQty);
        }
        private async Task HandleNormalBarcodeCancel(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, decimal cancelQty)
@@ -943,58 +1031,6 @@
            return task;
        }
        private async Task<ReturnAnalysisResult> AnalyzeReturnItems(string orderNo, string palletCode, int stockId)
        {
            var result = new ReturnAnalysisResult();
            // æƒ…况1:获取未分拣的出库锁定记录
            var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                .Where(it => it.OrderNo == orderNo &&
                           it.PalletCode == palletCode &&
                           it.Status == (int)OutLockStockStatusEnum.出库中)
                .ToListAsync();
            if (remainingLocks.Any())
            {
                result.HasRemainingLocks = true;
                result.RemainingLocks = remainingLocks;
                result.RemainingLocksReturnQty = remainingLocks.Sum(x => x.AssignQuantity - x.PickedQty);
            }
            // æƒ…况2:检查托盘上是否有其他库存货物
            var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                .Where(it => it.StockId == stockId &&
                            (it.Status == StockStatusEmun.入库确认.ObjToInt() ||
                             it.Status == StockStatusEmun.入库完成.ObjToInt() ||
                             it.Status == StockStatusEmun.出库锁定.ObjToInt()))
                .Where(it => it.StockQuantity > 0)
                .ToListAsync();
            if (palletStockGoods.Any())
            {
                result.HasPalletStockGoods = true;
                result.PalletStockGoods = palletStockGoods;
                result.PalletStockReturnQty = palletStockGoods.Sum(x => x.StockQuantity);
            }
            // æƒ…况3:检查拆包记录
            var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
                .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && !it.IsReverted && it.Status != (int)SplitPackageStatusEnum.已回库)
                .ToListAsync();
            if (splitRecords.Any())
            {
                result.HasSplitRecords = true;
                result.SplitRecords = splitRecords;
                result.SplitReturnQty = await CalculateSplitReturnQuantity(splitRecords, stockId);
            }
            result.TotalReturnQty = result.RemainingLocksReturnQty + result.PalletStockReturnQty + result.SplitReturnQty;
            result.HasItemsToReturn = result.TotalReturnQty > 0;
            return result;
        }
        private async Task<decimal> CalculateSplitReturnQuantity(List<Dt_SplitPackageRecord> splitRecords, int stockId)
        {
            decimal totalQty = 0;
@@ -1034,39 +1070,73 @@
            return totalQty;
        }
        private async Task<WebResponseContent> HandleNoReturnItems(string orderNo, string palletCode,Dt_Task originalTask)
        private async Task<WebResponseContent> HandleNoReturnItems(string orderNo, string palletCode, Dt_Task originalTask, int stockInfoId)
        {
            // æ£€æŸ¥æ˜¯å¦æ‰€æœ‰è´§ç‰©éƒ½å·²æ‹£é€‰å®Œæˆ
            var allPicked = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode)
                .AnyAsync(it => it.Status == (int)OutLockStockStatusEnum.拣选完成);
            //var allPicked = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
            //    .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode)
            //    .AnyAsync(it => it.Status == (int)OutLockStockStatusEnum.拣选完成);
            if (allPicked)
            //if (allPicked)
            //{
            //    // åˆ é™¤åŽŸå§‹å‡ºåº“ä»»åŠ¡ ç»„空盘   ç©ºç›˜å›žåº“
            //    //await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
            //    return WebResponseContent.Instance.OK("所有货物已拣选完成,托盘为空");
            //}
            //else
            //{
            //    // åˆ é™¤åŽŸå§‹å‡ºåº“ä»»åŠ¡
            //    //await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
            //    return WebResponseContent.Instance.Error("没有需要回库的剩余货物");
            //}
            try
            {
                // åˆ é™¤åŽŸå§‹å‡ºåº“ä»»åŠ¡
                await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
                return WebResponseContent.Instance.OK("所有货物已拣选完成,托盘为空");
                var locationtype = 0;
                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
                        .Where(x => x.PalletCode == palletCode)
                        .FirstAsync();
                if (stockInfo == null)
                {
                    var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>().FirstAsync(x => x.LocationCode == originalTask.SourceAddress);
                    locationtype = firstLocation?.LocationType ?? 1;
            }
            else
            {
                // åˆ é™¤åŽŸå§‹å‡ºåº“ä»»åŠ¡
                await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
                return WebResponseContent.Instance.Error("没有需要回库的剩余货物");
                    locationtype = stockInfo.LocationType;
            }
                var targetAddress = originalTask.TargetAddress;
                await CleanupZeroStockData(stockInfoId);
                var emptystockInfo = new Dt_StockInfo() { PalletType = PalletTypeEnum.Empty.ObjToInt(), StockStatus = StockStatusEmun.组盘暂存.ObjToInt(), PalletCode = palletCode, LocationType = locationtype };
                emptystockInfo.Details = new List<Dt_StockInfoDetail>();
                _stockInfoService.AddMaterielGroup(emptystockInfo);
            //空托盘如何处理  è¿˜æœ‰ä¸€ä¸ªå‡ºåº“任务要处理。
                originalTask.PalletType = PalletTypeEnum.Empty.ObjToInt();
                await CreateReturnTaskAndHandleESS(orderNo, palletCode, originalTask, TaskTypeEnum.InEmpty);
            }
            catch (Exception ex)
            {
                _logger.LogError($" HandleNoReturnItems  å¤±è´¥: {ex.Message}");
                return WebResponseContent.Instance.Error($" å›žåº“空托盘失败!");
            }
            return WebResponseContent.Instance.OK("空托盘回库任务创建成功");
         
        }
        private async Task ExecuteReturnOperations(string orderNo, string palletCode, Dt_StockInfo stockInfo,
            Dt_Task task, ReturnAnalysisResult analysis)
            Dt_Task task, PalletStatusAnalysis analysis)
        {
            // æƒ…况1:处理未分拣的出库锁定记录
            if (analysis.HasRemainingLocks)
            {
                await HandleRemainingLocksReturn(analysis.RemainingLocks, stockInfo.Id);
                // å…³é”®ï¼šæ›´æ–°è®¢å•明细的已拣选数量
                await UpdateOrderDetailsOnReturn(analysis.RemainingLocks);
               // await UpdateOrderDetailsOnReturn(analysis.RemainingLocks);
            }
            // å¤„理托盘上其他库存货物
@@ -1213,7 +1283,7 @@
        /// <param name="originalTask"></param>
        /// <param name="analysis"></param>
        /// <returns></returns>
        private async Task CreateReturnTaskAndHandleESS(string orderNo, string palletCode, Dt_Task originalTask, ReturnAnalysisResult analysis)
        private async Task CreateReturnTaskAndHandleESS(string orderNo, string palletCode, Dt_Task originalTask, TaskTypeEnum taskTypeEnum)
        {
            var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>()
                .FirstAsync(x => x.LocationCode == originalTask.SourceAddress);
@@ -1232,7 +1302,7 @@
                SourceAddress = stations[originalTask.TargetAddress],
                TargetAddress = newLocation.LocationCode,
                TaskStatus = TaskStatusEnum.New.ObjToInt(),
                TaskType = TaskTypeEnum.InPick.ObjToInt(),
                TaskType = taskTypeEnum.ObjToInt(),
                PalletType = originalTask.PalletType,
                WarehouseId = originalTask.WarehouseId
@@ -1242,7 +1312,10 @@
            var targetAddress = originalTask.TargetAddress;        
         
            // åˆ é™¤åŽŸå§‹å‡ºåº“ä»»åŠ¡
            await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
            _taskRepository.DeleteAndMoveIntoHty(originalTask, OperateTypeEnum.自动完成);
            // await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
            // ç»™ ESS å‘送流动信号和创建任务
            await SendESSCommands(palletCode, targetAddress, returnTask);
@@ -1274,10 +1347,7 @@
                        taskType = "putaway",
                        taskGroupCode = "",
                        groupPriority = 0,
                        tasks = new List<TasksType>
                    {
                        new()
                        {
                        tasks = new List<TasksType>{  new() {
                            taskCode = returnTask.TaskNum.ToString(),
                            taskPriority = 0,
                            taskDescribe = new TaskDescribeType
@@ -1290,8 +1360,7 @@
                                deadline = 0,
                                storageTag = ""
                            }
                        }
                    }
                        } }
                    };
                    var resultTask = await _eSSApiService.CreateTaskAsync(essTask);
@@ -1356,6 +1425,8 @@
            }
        }
        private async Task UpdateOrderStatusForReturn(string orderNo)
        {
            try
@@ -1419,6 +1490,7 @@
                    operationType = 1,
                    Operator = App.User.UserName,
                    orderNo = outboundOrder.UpperOrderNo,
                    documentsNO = outboundOrder.OrderNo,
                    status = outboundOrder.OrderStatus,
                    details = new List<FeedbackOutboundDetailsModel>()
                };
@@ -1473,7 +1545,324 @@
        #endregion
        #region ç©ºæ‰˜ç›˜
        /// <summary>
        /// æ¸…理零库存数据
        /// </summary>
        private async Task CleanupZeroStockData(int stockId)
        {
            try
            {
                // 1. åˆ é™¤åº“存数量为0的明细记录
                var deleteDetailCount = await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
                    .Where(x => x.StockId == stockId && x.StockQuantity == 0 && (x.Status == StockStatusEmun.出库完成.ObjToInt() || x.Status ==
                                          StockStatusEmun.入库完成.ObjToInt()))
                    .ExecuteCommandAsync();
                await _stockInfoService.Db.Deleteable<Dt_StockInfo>()
                   .Where(x => x.Id == stockId).ExecuteCommandAsync();
                _logger.LogInformation($"清理零库存明细记录 - StockId: {stockId}, åˆ é™¤è®°å½•æ•°: {deleteDetailCount}");
            }
            catch (Exception ex)
            {
                _logger.LogWarning($"清理零库存数据失败 - StockId: {stockId}, Error: {ex.Message}");
                // æ³¨æ„ï¼šæ¸…理失败不应该影响主流程
            }
        }
        /// <summary>
        /// å¤„理任务清理(按订单和托盘)
        /// </summary>
        private async Task HandleTaskCleanup(string orderNo, string palletCode)
        {
            try
            {
                // 1. æŸ¥æ‰¾æ‰€æœ‰ä¸Žè¯¥è®¢å•和托盘相关的任务
                var tasks = await _taskRepository.Db.Queryable<Dt_Task>().Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode).ToListAsync();
                if (tasks.Any())
                {
                    foreach (var task in tasks)
                    {
                        task.TaskStatus = (int)TaskStatusEnum.Finish;
                    }
                    // await _taskRepository.Db.Updateable(tasks).ExecuteCommandAsync();
                    _taskRepository.DeleteAndMoveIntoHty(tasks, OperateTypeEnum.自动完成);
                    _logger.LogInformation($"完成{tasks.Count}个托盘任务 - è®¢å•: {orderNo}, æ‰˜ç›˜: {palletCode}");
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning($"处理任务清理失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
                throw new Exception($"任务清理失败: {ex.Message}");
            }
        }
        /// <summary>
        /// æ›´æ–°è®¢å•相关数据
        /// </summary>
        private async Task UpdateOrderData(string orderNo, string palletCode)
        {
            try
            {
                // æ£€æŸ¥è®¢å•是否还有其他托盘在处理中
                var otherActivePallets = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                    .Where(x => x.OrderNo == orderNo &&
                               x.PalletCode != palletCode &&
                             (x.Status == (int)OutLockStockStatusEnum.出库中 || x.Status == (int)OutLockStockStatusEnum.回库中))
                    .AnyAsync();
                var otherActiveTasks = await _taskRepository.Db.Queryable<Dt_Task>()
                    .Where(x => x.OrderNo == orderNo &&
                               x.PalletCode != palletCode
                    // && x.TaskStatus.In((int)TaskStatusEnum.待执行, (int)TaskStatusEnum.执行中)
                     )
                    .AnyAsync();
                // å¦‚果没有其他托盘在处理,检查订单是否应该完成
                if (!otherActivePallets && !otherActiveTasks)
                {
                    await CheckAndUpdateOrderCompletion(orderNo);
                }
                else
                {
                    _logger.LogInformation($"订单 {orderNo} è¿˜æœ‰å…¶ä»–托盘在处理,不更新订单状态");
                }
                // 3. æ›´æ–°æ‹£é€‰è®°å½•状态(可选)
                await UpdatePickingRecordsStatus(orderNo, palletCode);
            }
            catch (Exception ex)
            {
                _logger.LogWarning($"更新订单数据失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
                throw new Exception($"更新订单数据失败: {ex.Message}");
            }
        }
        /// <summary>
        /// æ£€æŸ¥å¹¶æ›´æ–°è®¢å•完成状态
        /// </summary>
        private async Task CheckAndUpdateOrderCompletion(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();
            bool allCompleted = true;
            foreach (var detail in orderDetails)
            {
                if (detail.OverOutQuantity < detail.NeedOutQuantity)
                {
                    allCompleted = false;
                    break;
                }
            }
            var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
                .FirstAsync(x => x.OrderNo == orderNo);
            if (outboundOrder != null && allCompleted && outboundOrder.OrderStatus != (int)OutOrderStatusEnum.出库完成)
            {
                outboundOrder.OrderStatus = (int)OutOrderStatusEnum.出库完成;
                await _outboundOrderService.Db.Updateable(outboundOrder).ExecuteCommandAsync();
                _logger.LogInformation($"订单 {orderNo} å·²æ ‡è®°ä¸ºå‡ºåº“完成");
                // å‘MES反馈订单完成(如果需要)
                await HandleOrderCompletion(outboundOrder, orderNo);
            }
        }
        /// <summary>
        /// æ›´æ–°æ‹£é€‰è®°å½•状态
        /// </summary>
        private async Task UpdatePickingRecordsStatus(string orderNo, string palletCode)
        {
            try
            {
                // å¯ä»¥å°†ç›¸å…³çš„æ‹£é€‰è®°å½•标记为已完成
                var pickingRecords = await Db.Queryable<Dt_PickingRecord>()
                    .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode)
                    .ToListAsync();
                // è¿™é‡Œå¯ä»¥æ ¹æ®éœ€è¦æ›´æ–°æ‹£é€‰è®°å½•的状态字段
                // ä¾‹å¦‚:pickingRecord.Status = (int)PickingStatusEnum.已完成;
                _logger.LogInformation($"找到{pickingRecords.Count}条拣选记录 - è®¢å•: {orderNo}, æ‰˜ç›˜: {palletCode}");
            }
            catch (Exception ex)
            {
                _logger.LogWarning($"更新拣选记录状态失败: {ex.Message}");
            }
        }
        #endregion
        #region è¾…助方法
        /// <summary>
        /// ç»Ÿä¸€åˆ†æžæ‰˜ç›˜çŠ¶æ€ - è¿”回托盘的完整状态信息
        /// </summary>
        private async Task<PalletStatusAnalysis> AnalyzePalletStatus(string orderNo, string palletCode, int stockId)
        {
            var result = new PalletStatusAnalysis
            {
                OrderNo = orderNo,
                PalletCode = palletCode,
                StockId = stockId
            };
            // 1. åˆ†æžæœªåˆ†æ‹£çš„出库锁定记录
            var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                .Where(it => it.OrderNo == orderNo &&
                           it.PalletCode == palletCode &&
                           it.Status == (int)OutLockStockStatusEnum.出库中)
                .ToListAsync();
            if (remainingLocks.Any())
            {
                result.HasRemainingLocks = true;
                result.RemainingLocks = remainingLocks;
                result.RemainingLocksReturnQty = remainingLocks.Sum(x => x.AssignQuantity - x.PickedQty);
            }
            // 2. åˆ†æžæ‰˜ç›˜ä¸Šçš„库存货物
            var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                .Where(it => it.StockId == stockId &&
                     (it.Status == StockStatusEmun.入库确认.ObjToInt() ||
                      it.Status == StockStatusEmun.入库完成.ObjToInt() ||
                      it.Status == StockStatusEmun.出库锁定.ObjToInt()))
                .Where(it => it.StockQuantity > 0)
                .ToListAsync();
            if (palletStockGoods.Any())
            {
                result.HasPalletStockGoods = true;
                result.PalletStockGoods = palletStockGoods;
                result.PalletStockReturnQty = palletStockGoods.Sum(x => x.StockQuantity);
            }
            // 3. åˆ†æžæ‹†åŒ…记录
            var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
                .Where(it => it.OrderNo == orderNo &&
                           it.PalletCode == palletCode &&
                           !it.IsReverted &&
                           it.Status != (int)SplitPackageStatusEnum.已回库)
                .ToListAsync();
            if (splitRecords.Any())
            {
                result.HasSplitRecords = true;
                result.SplitRecords = splitRecords;
                result.SplitReturnQty = await CalculateSplitReturnQuantity(splitRecords, stockId);
            }
            // 4. è®¡ç®—总回库数量和空托盘状态
            result.TotalReturnQty = result.RemainingLocksReturnQty + result.PalletStockReturnQty + result.SplitReturnQty;
            result.HasItemsToReturn = result.TotalReturnQty > 0;
            result.IsEmptyPallet = !result.HasItemsToReturn;
            // 5. æ£€æŸ¥æ˜¯å¦æœ‰è¿›è¡Œä¸­çš„任务
            result.HasActiveTasks = await _taskRepository.Db.Queryable<Dt_Task>()
                .Where(x => x.OrderNo == orderNo && x.TaskType == TaskTypeEnum.InPick.ObjToInt() &&
                           x.PalletCode == palletCode &&
                           x.TaskStatus == (int)TaskStatusEnum.New)
                .AnyAsync();
            return result;
        }
        /// <summary>
        /// æ£€æŸ¥æ‰˜ç›˜æ˜¯å¦ä¸ºç©º
        /// </summary>
        private async Task<bool> IsPalletEmpty(string orderNo, string palletCode)
        {
            try
            {
                // èŽ·å–åº“å­˜ä¿¡æ¯
                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
                    .Where(x => x.PalletCode == palletCode)
                    .FirstAsync();
                if (stockInfo == null)
                    return false;
                // ä½¿ç”¨ç»Ÿä¸€çš„状态分析
                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
                return statusAnalysis.IsEmptyPallet;
            }
            catch (Exception ex)
            {
                _logger.LogWarning($"检查托盘是否为空失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// æ£€æŸ¥å¹¶å¤„理空托盘
        /// </summary>
        private async Task<bool> CheckAndHandleEmptyPallet(string orderNo, string palletCode)
        {
            try
            {
                // 1. èŽ·å–åº“å­˜ä¿¡æ¯
                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
                    .Where(x => x.PalletCode == palletCode)
                    .FirstAsync();
                if (stockInfo == null)
                {
                    _logger.LogWarning($"未找到托盘 {palletCode} çš„库存信息");
                    return false;
                }
                // 2. ä½¿ç”¨ç»Ÿä¸€çš„状态分析
                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
                // 3. æ£€æŸ¥æ˜¯å¦ä¸ºç©ºæ‰˜ç›˜ä¸”没有进行中的任务
                if (!statusAnalysis.IsEmptyPallet || statusAnalysis.HasActiveTasks)
                {
                    return false;
                }
                _logger.LogInformation($"检测到空托盘,开始自动处理 - è®¢å•: {orderNo}, æ‰˜ç›˜: {palletCode}");
                //// æ¸…理零库存数据
                //await CleanupZeroStockData(stockInfo.Id);
                //// æ›´æ–°åº“存主表状态为空托盘
                //await UpdateStockInfoAsEmpty(stockInfo);
                //// å¤„理出库锁定记录
                //await HandleOutStockLockRecords(orderNo, palletCode);
                //// å¤„理任务状态
                //await HandleTaskStatusForEmptyPallet(orderNo, palletCode);
                //// æ›´æ–°è®¢å•数据
                //await UpdateOrderDataForEmptyPallet(orderNo, palletCode);
                ////记录操作历史
                //await RecordAutoEmptyPalletOperation(orderNo, palletCode);
                _logger.LogInformation($"空托盘自动处理完成 - è®¢å•: {orderNo}, æ‰˜ç›˜: {palletCode}");
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError($"自动处理空托盘失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
                return false;
            }
        }
        private async Task<string> GenerateNewBarcode()
        {
@@ -1668,6 +2057,32 @@
        public List<Dt_StockInfoDetail> PalletStockGoods { get; set; } = new List<Dt_StockInfoDetail>();
        public List<Dt_SplitPackageRecord> SplitRecords { get; set; } = new List<Dt_SplitPackageRecord>();
    }
    public class PalletStatusAnalysis
    {
        public string OrderNo { get; set; }
        public string PalletCode { get; set; }
        public int StockId { get; set; }
        // å›žåº“相关属性
        public bool HasItemsToReturn { get; set; }
        public bool HasRemainingLocks { get; set; }
        public bool HasPalletStockGoods { get; set; }
        public bool HasSplitRecords { get; set; }
        public decimal RemainingLocksReturnQty { get; set; }
        public decimal PalletStockReturnQty { get; set; }
        public decimal SplitReturnQty { get; set; }
        public decimal TotalReturnQty { get; set; }
        public List<Dt_OutStockLockInfo> RemainingLocks { get; set; } = new List<Dt_OutStockLockInfo>();
        public List<Dt_StockInfoDetail> PalletStockGoods { get; set; } = new List<Dt_StockInfoDetail>();
        public List<Dt_SplitPackageRecord> SplitRecords { get; set; } = new List<Dt_SplitPackageRecord>();
        // ç©ºæ‰˜ç›˜ç›¸å…³å±žæ€§
        public bool IsEmptyPallet { get; set; }
        public bool HasActiveTasks { get; set; }
        // ä¾¿åˆ©æ–¹æ³•
        public bool CanReturn => HasItemsToReturn && !HasActiveTasks;
        public bool CanRemove => IsEmptyPallet && !HasActiveTasks;
    }
    #endregion
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_StockService/StockInfoService.cs
@@ -254,6 +254,7 @@
                    LocationCode = a.LocationCode,
                    MaterielCode = b.MaterielCode,
                    MaterielName = b.MaterielName,
                    Barcode=b.Barcode,
                    PalletCode = a.PalletCode,
                    UseableQuantity = b.StockQuantity - b.OutboundQuantity
                }, a => locationCodes.Contains(a.LocationCode), b => b.StockQuantity > b.OutboundQuantity && b.MaterielCode == materielCode, x => true).GroupBy(x => x.PalletCode).Select(x => new StockSelectViewDTO
@@ -261,6 +262,7 @@
                    LocationCode = x.FirstOrDefault()?.LocationCode ?? "",
                    MaterielCode = x.FirstOrDefault()?.MaterielCode ?? "",
                    MaterielName = x.FirstOrDefault()?.MaterielName ?? "",
                    Barcode=x.FirstOrDefault()?.Barcode??"",
                    PalletCode = x.Key,
                    UseableQuantity = x.Sum(x => x.UseableQuantity)
                }).ToList();
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_Outbound.cs
@@ -219,6 +219,7 @@
                        _outboundOrderService.Repository.UpdateData(outboundOrder);
                    }
                    outboundOrder.Operator = App.User.UserName;
                    outboundOrder.OrderStatus = OutOrderStatusEnum.出库中.ObjToInt();
                    _outboundOrderService.Repository.UpdateData(outboundOrder);
                    WebResponseContent content = _outboundOrderDetailService.LockOutboundStockDataUpdate(stockInfos, outboundOrderDetails, outStockLockInfos, locationInfos, tasks: tasks);
@@ -239,6 +240,9 @@
                    {
                        _outboundOrderService.Repository.UpdateData(outboundOrder);
                    }
                    outboundOrder.Operator = App.User.UserName;
                    outboundOrder.OrderStatus = OutOrderStatusEnum.出库中.ObjToInt();
                    _outboundOrderService.Repository.UpdateData(outboundOrder);
                    _outboundOrderDetailService.Repository.UpdateData(outboundOrderDetails);
                }
                _unitOfWorkManage.CommitTran();
@@ -471,10 +475,10 @@
                throw new Exception("未找到出库单明细信息");
            }
            if (stockSelectViews.Sum(x => x.UseableQuantity) > outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity)
            {
                throw new Exception("选择数量超出单据数量");
            }
            //if (stockSelectViews.Sum(x => x.UseableQuantity) > outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity)
            //{
            //    throw new Exception("选择数量超出单据数量");
            //}
            List<Dt_StockInfo>? stockInfos = null;
            Dt_OutboundOrderDetail? orderDetail = null;
            List<Dt_OutStockLockInfo>? outStockLockInfos = null;
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/OutboundPickingController.cs
@@ -91,6 +91,13 @@
            return await Service.ReturnRemaining(dto.OrderNo, dto.PalletCode, "");
        }
        [HttpPost("remove-empty-pallet")]
        public async Task<WebResponseContent> RemoveEmptyPallet ([FromBody] ConfirmPickingDto dto)
        {
            return await Service.RemoveEmptyPallet(dto.OrderNo, dto.PalletCode);
        }
        //[HttpPost("direct-outbound")]
        //public async Task<WebResponseContent> DirectOutbound([FromBody] DirectOutboundRequest dto)
        //{