647556386
2 天以前 91ead18d0e92b6e1ed916c5159f3431bf2071a56
Merge branch 'master' of http://115.159.85.185:8098/r/ZhongRui/ALDbanyunxiangmu
已添加1个文件
已修改11个文件
800 ■■■■ 文件已修改
项目代码/WIDESEA_WMSClient/config/buttons.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/extension/inbound/extend/EmptyTrayInbound.vue 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/extension/inbound/extend/Pallet.vue 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/extension/inbound/inboundOrder.js 340 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/extension/outbound/extend/EmptyTrayOutbound.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_IInboundService/IInboundOrderService.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_InboundService/InboundOrderService.cs 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundBatchPickingService.cs 39 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/SplitPackageService.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Inbound/InboundOrderController.cs 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ÏîÄ¿´úÂë/WIDESEA_WMSClient/config/buttons.js
@@ -235,6 +235,14 @@
    onClick: function () {
    }
},
{
    name: "空托入库",
    class: '',
    value: 'EmptyTrayInbound',
    type: 'primary',
    onClick: function () {
    }
},
]
export default buttons
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/extend/EmptyTrayInbound.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,169 @@
<template>
    <vol-box v-model="show" title="空托入库" :width="800" :height="1200">
        <template #content>
            <el-form ref="form" :model="form" label-width="90px">
                <el-form-item label="入库区域:">
                    <el-select v-model="form.locationType" placeholder="请选择入库区域">
                        <el-option v-for="item in locationTypes" :key="item.locationType" :label="item.locationTypeDesc"
                            :value="item.locationType" />
                    </el-select>
                </el-form-item>
                <el-form-item label="托盘条码:">
                    <el-input v-model="form.palletCode" placeholder="请扫描/输入托盘条码" @keyup.enter="submit" @keyup.13="submit"
                        clearable maxlength="50" @paste="handlePaste" @input="handleInput" ref="boxCodeInput" />
                </el-form-item>
            </el-form>
        </template>
        <template #footer>
            <div class="dialog-footer">
                <el-button type="primary" @click="submit">确认</el-button>
                <el-button @click="show = false">关闭</el-button>
            </div>
        </template>
    </vol-box>
</template>
<script>
import VolBox from '@/components/basic/VolBox.vue'
export default {
    components: { VolBox },
    props: {
        value: { type: Boolean, default: false }
    },
    data() {
        return {
            show: false,
            form: {
                palletCode: '',
                locationType: ''
            },
            locationTypes: []
        }
    },
    methods: {
        open() {
            this.show = true
            this.getData();
            this.$nextTick(() => {
                this.focusInput()
            })
        },
        async getData() {
            try {
                const { data } = await this.http.post("api/LocationInfo/GetLocationTypes")
                this.locationTypes = data
            } catch (e) {
                this.$message.error('获取区域类型失败')
            }
        },
        async submit() {
            if (!this.form.palletCode) {
                this.$message.warning('请输入托盘条码')
                this.focusInput()
                return
            }
            if (!this.form.locationType) {
                this.$message.warning('请选择入库区域')
                return
            }
            try {
                let param = {
                    WarehouseCode: this.form.locationType,
                    PalletCode: this.form.palletCode
                }
                const { status, message } = await this.http.post(
                    `/api/InboundOrder/EmptyMaterielGroup`,
                    param
                )
                if (status) {
                    this.$message.success("组盘成功");
                    // æ¸…空输入框数据
                    this.form.palletCode = '';
                    // èšç„¦å¹¶é€‰ä¸­è¾“入框
                    this.focusAndSelectInput();
                } else {
                    this.$message.error(message || '操作失败');
                    // å¤±è´¥æ—¶ä¸æ¸…理数据,但聚焦并选中输入框,方便修改
                    this.focusAndSelectInput();
                }
            } catch (error) {
                this.$message.error('请求异常');
                // å¼‚常时也不清理数据
                this.focusAndSelectInput();
            }
        },
        // æ‰«ææžªä¼˜åŒ–处理
        handleInput(value) {
            // è¿‡æ»¤éžæ•°å­—和条码常用字符
            this.form.palletCode = value.replace(/[^a-zA-Z0-9\-]/g, '')
        },
        handlePaste(e) {
            // ç²˜è´´æ—¶è‡ªåŠ¨æäº¤
            setTimeout(this.submit, 100)
        },
        // èšç„¦å¹¶é€‰ä¸­è¾“入框
        focusAndSelectInput() {
            this.$nextTick(() => {
                setTimeout(() => {
                    const inputRef = this.$refs.boxCodeInput;
                    if (inputRef) {
                        // Element Plus/Element UI çš„处理方式
                        const inputEl = inputRef.$el ? inputRef.$el.querySelector('input') : inputRef;
                        if (inputEl) {
                            inputEl.focus();
                            inputEl.select();
                        }
                    }
                }, 100);
            });
        },
        // åªèšç„¦è¾“入框(不清空数据)
        focusInput() {
            this.$nextTick(() => {
                const inputRef = this.$refs.boxCodeInput;
                if (inputRef) {
                    const inputEl = inputRef.$el ? inputRef.$el.querySelector('input') : inputRef;
                    inputEl?.focus();
                }
            });
        },
        // æ¸…空表单数据
        clearForm() {
            this.form.palletCode = '';
            // ä¸æ¸…空 locationType,保持区域选择
        }
    },
    watch: {
        show(val) {
            if (val) {
                this.$nextTick(() => {
                    this.focusInput()
                })
            } else {
                // å…³é—­å¼¹çª—时清空表单
                this.clearForm();
            }
        }
    }
}
</script>
<style scoped>
.dialog-footer {
    text-align: right;
}
</style>
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/extend/Pallet.vue
@@ -103,6 +103,32 @@
        <el-alert :title="error" type="error" show-icon closable @close="error = ''" />
      </div>
      <!-- æœªç»„盘列表 -->
      <div class="unpallet-section compact">
        <el-card shadow="hover" class="compact-card unpallet-card">
          <div slot="header" class="compact-header">
            <span><i class="el-icon-tickets"></i> æœªç»„盘条码</span>
            <span class="list-actions">
              <el-tag type="primary" size="small">未组盘 {{ totalStockCount }}</el-tag>
            </span>
          </div>
          <div  class="table-container">
            <el-table :data="unpalletMaterials" stripe style="width: 100%" height="100%" size="small" v-loading="unpalletBarcodesLoading">
              <el-table-column type="index" label="序号" width="60" align="center"></el-table-column>
              <el-table-column prop="barcode" label="条码" min-width="140" show-overflow-tooltip></el-table-column>
              <el-table-column prop="materielCode" label="物料编码" min-width="150" show-overflow-tooltip></el-table-column>
              <el-table-column prop="batchNo" label="批次" min-width="150" show-overflow-tooltip></el-table-column>
              <el-table-column prop="orderQuantity" label="数量" min-width="130" align="right"></el-table-column>
              <el-table-column prop="unit" label="单位" width="80" align="center"></el-table-column>
              <el-table-column prop="supplyCode" label="供应商" min-width="130" show-overflow-tooltip></el-table-column>
            </el-table>
          </div>
        </el-card>
      </div>
      <!-- ç‰©æ–™åˆ—表 - å›ºå®šé«˜åº¦å¸¦æ»šåŠ¨æ¡ -->
      <div class="material-list compact">
        <el-card shadow="hover" class="compact-card">
@@ -110,7 +136,6 @@
            <span><i class="el-icon-tickets"></i> ç»„盘数据</span>
            <span class="list-actions">
              <el-tag type="primary" size="small">共 {{ materials.length }} æ¡</el-tag>
              <el-tag type="primary" size="small">未组盘 {{ totalStockCount }}</el-tag>
              <el-tag type="primary" size="small">未入库数量 {{ totalStockSum }}{{ uniqueUnit }}</el-tag>
              <el-tag v-if="trayBarcode" type="success" size="small">托盘: {{ trayBarcode }}</el-tag>
              <el-tag v-if="form.warehouseType" type="info" size="small">仓库: {{ currentWarehouseName }}</el-tag>
@@ -177,6 +202,10 @@
      error: '',
      debugMode: false,
      currentFocus: 'warehouse',
      unpalletBarcodes:[],
      unpalletBarcodesLoading: false,
      unpalletMaterials: [], // æœªç»„盘详细数据列表
      // æ‰«ç æžªç›¸å…³å˜é‡
      scanCode: '',
@@ -257,6 +286,7 @@
            this.initwarehouseTypes(); // åˆå§‹åŒ–仓库
            this.initLocationTypes(); // åˆå§‹åŒ–仓库区域
            this.fetchStockStatistics(); // åŠ è½½ç»Ÿè®¡æ•°æ®
            this.fetchUnpalletMaterialDetails();
          }, 300);
        });
      }
@@ -276,6 +306,7 @@
        this.backData = [];
        this.$refs.palletForm?.reset();
        this.fetchStockStatistics(); // å•据号变了,刷新统计
        this.fetchUnpalletMaterialDetails();
      }
    }
  },
@@ -316,6 +347,43 @@
        callback(new Error('请选择仓库区域'));
      } else {
        callback();
      }
    },
    // æ ¹æ®æ¡ç åˆ—表获取详细数据
    async fetchUnpalletMaterialDetails() {
      try {
        // å°è¯•调用接口获取详细数据
        // æ³¨æ„ï¼šå¦‚果这个接口不存在,可以注释掉或根据实际API调整
        const response = await http.post('/api/InboundOrder/UnPalletGroupBarcode?orderNo='+this.docNo, {
        });
        console.log('未组盘数据:', response.data);
        if (response.status && Array.isArray(response.data)) {
          this.unpalletMaterials = response.data;
          this.unpalletBarcodes = response.data.map(item => item.barcode || '');
          this.totalStockCount = response.data.length;
        } else {
          // å¦‚果接口返回格式不同,尝试其他方式
          // å¦‚果接口不存在,这里会进入catch,设置为空数组
          this.unpalletMaterials = [];
        }
      } catch (err) {
        console.warn('获取未组盘详细数据接口可能不存在,使用条码列表显示:', err);
        // å¦‚果接口不存在,将条码列表转换为简单的显示格式
        // æˆ–者保持为空,让用户知道需要选择仓库和区域来查看详细数据
        this.unpalletMaterials = this.unpalletBarcodes.map(barcode => ({
          barcode: barcode,
          materielCode: '-',
          batchNo: '-',
          stockQuantity: '-',
          unit: '-',
          supplyCode: '-',
          warehouseType: '-'
        }));
      }
    },
    /**
@@ -399,6 +467,7 @@
                console.log('仓库区域验证通过:', value);
                // åŒºåŸŸé€‰æ‹©åŽï¼Œè‡ªåŠ¨èšç„¦åˆ°æ‰˜ç›˜è¾“å…¥æ¡†
                this.focusLocationSelect();
                // åˆ·æ–°æœªç»„盘数据(根据选择的仓库和区域过滤)
              }
            });
          }, 100);
@@ -555,6 +624,8 @@
      this.trayBarcode = '';
      this.barcode = '';
      this.materials = [];
      this.unpalletBarcodes = [];
      this.unpalletMaterials = [];
      this.loading = false;
      this.error = '';
      this.scanCode = '';
@@ -814,6 +885,13 @@
            });
          });
          
          const removeIndex = this.unpalletMaterials.findIndex(item => item.barcode === currentBarcode);
          if (removeIndex > -1) {
            this.unpalletMaterials.splice(removeIndex, 1); // åˆ é™¤æœªç»„盘对应数据
            this.unpalletBarcodes = this.unpalletMaterials.map(item => item.barcode || ''); // æ›´æ–°æ¡ç æ•°ç»„
            this.totalStockCount = Math.max(0, this.totalStockCount - 1);
          }
          this.$message({
            message: `成功添加条码: ${currentBarcode}`,
            type: 'success',
@@ -1297,5 +1375,37 @@
    border: 1px solid #DCDFE6;
    border-radius: 4px;
  }
  .unpallet-section.compact {
  margin-bottom: 8px;
  flex-shrink: 0;
}
.unpallet-card {
  flex-shrink: 0;
}
.unpallet-barcode-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 8px 0;
  max-height: 180px;
  overflow-y: auto;
}
.unpallet-barcode-list>>>.el-tag {
  cursor: pointer;
  max-width: calc(33.333% - 4px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@media (max-width: 768px) {
  .unpallet-barcode-list>>>.el-tag {
    max-width: calc(50% - 4px);
  }
}
}
</style>
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/inboundOrder.js
@@ -2,11 +2,11 @@
import http from '@/api/http.js'
import { h, createVNode, render, reactive, ref } from 'vue';
import { ElDialog, ElForm, ElFormItem, ElInput, ElButton, ElMessage, ElSelect, ElOption } from 'element-plus'; // å¼•å…¥ElMessage,解决提示无反应
import gridHeader from './extend/EmptyTrayInbound.vue'
let extension = {
  components: {
    //查询界面扩展组件
    gridHeader: '',
    gridHeader: gridHeader,
    gridBody: '',
    gridFooter: '',
    //新建、编辑弹出框扩展组件
@@ -245,186 +245,194 @@
          }
        }
      },
      {
        name: '空托盘入库',
        type: 'primary',
        value: '空托盘入库',
      // {
      //   name: '空托盘入库',
      //   type: 'primary',
      //   value: '空托盘入库',
        onClick: function () {
          const mountNode = document.createElement('div');
          document.body.appendChild(mountNode);
      //   onClick: function () {
      //     const mountNode = document.createElement('div');
      //     document.body.appendChild(mountNode);
          // å“åº”式表单数据:料箱码(必填,扫码枪/手动输入)
          const formData = reactive({
            boxCode: '',
            warehouseCode: ''
          });
      //     // å“åº”式表单数据:料箱码(必填,扫码枪/手动输入)
      //     const formData = reactive({
      //       boxCode: '',
      //       warehouseCode: ''
      //     });
          const warehouses = ref([]);
          const isLoadingWarehouses = ref(false);
      //     const warehouses = ref([]);
      //     const isLoadingWarehouses = ref(false);
          const getWarehouseList = async () => {
            isLoadingWarehouses.value = true;
            try {
              const { data, status } = await http.post('/api/LocationInfo/GetLocationTypes');
              if (status && Array.isArray(data)) {
                // æ ¼å¼åŒ–仓库选项:适配ElSelect的label-value格式
                warehouses.value = data.map(item => ({
                  label: item.locationTypeDesc,
                  value: item.locationType
                }));
              } else {
                ElMessage.error('获取区域列表失败');
                warehouses.value = [];
              }
            } catch (err) {
              ElMessage.error('区域数据请求异常,请稍后重试');
              warehouses.value = [];
            } finally {
              isLoadingWarehouses.value = false;
            }
          };
      //     const getWarehouseList = async () => {
      //       isLoadingWarehouses.value = true;
      //       try {
      //         const { data, status } = await http.post('/api/LocationInfo/GetLocationTypes');
      //         if (status && Array.isArray(data)) {
      //           // æ ¼å¼åŒ–仓库选项:适配ElSelect的label-value格式
      //           warehouses.value = data.map(item => ({
      //             label: item.locationTypeDesc,
      //             value: item.locationType
      //           }));
      //         } else {
      //           ElMessage.error('获取区域列表失败');
      //           warehouses.value = [];
      //         }
      //       } catch (err) {
      //         ElMessage.error('区域数据请求异常,请稍后重试');
      //         warehouses.value = [];
      //       } finally {
      //         isLoadingWarehouses.value = false;
      //       }
      //     };
          // æäº¤è¡¨å•的统一逻辑(供回车触发和按钮点击共用)
          const submitForm = async () => {
            const formRef = vnode.component.refs.batchInForm;
            try {
              // æ‰§è¡Œè¡¨å•校验(料箱码必填)
              await formRef.validate();
            } catch (err) {
              ElMessage.warning('请输入有效的料箱码');
              return;
            }
      //     // æäº¤è¡¨å•的统一逻辑(供回车触发和按钮点击共用)
      //     const submitForm = async () => {
      //       const formRef = vnode.component.refs.batchInForm;
      //       try {
      //         // æ‰§è¡Œè¡¨å•校验(料箱码必填)
      //         await formRef.validate();
      //       } catch (err) {
      //         ElMessage.warning('请输入有效的料箱码');
      //         return;
      //       }
            http.post('/api/InboundOrder/EmptyMaterielGroup', {
              palletCode: formData.boxCode.trim(),
              warehouseCode: formData.warehouseCode
            }).then(({ data, status, message }) => {
              if (status) {
                ElMessage.success(`入库成功,料箱码:${formData.boxCode.trim()}`);
                this.refresh();
                formData.boxCode = '';
      //       http.post('/api/InboundOrder/EmptyMaterielGroup', {
      //         palletCode: formData.boxCode.trim(),
      //         warehouseCode: formData.warehouseCode
      //       }).then(({ data, status, message }) => {
      //         if (status) {
      //           ElMessage.success(`入库成功,料箱码:${formData.boxCode.trim()}`);
      //           this.refresh();
      //           formData.boxCode = '';
                setTimeout(() => {
                  const inputRef = vnode.component.refs.boxCodeInput;
                  inputRef?.focus();
                }, 100);
              } else {
                ElMessage.error(message || data?.message || '入库失败');
                selectBoxCodeInput();
              }
            }).catch(() => {
              ElMessage.error('请求失败,请稍后重试');
              selectBoxCodeInput();
            });
          };
      //           setTimeout(() => {
      //             const inputRef = vnode.component.refs.boxCodeInput;
      //             inputRef?.focus();
      //           }, 100);
      //         } else {
      //           ElMessage.error(message || data?.message || '入库失败');
      //           selectBoxCodeInput();
      //         }
      //       }).catch(() => {
      //         ElMessage.error('请求失败,请稍后重试');
      //         selectBoxCodeInput();
      //       });
      //     };
          const selectBoxCodeInput = () => {
            setTimeout(() => {
              const inputRef = vnode.component.refs.boxCodeInput;
              if (inputRef) {
                const targetInput = inputRef.$el?.querySelector('input') || inputRef;
                targetInput?.focus();
                targetInput?.select();
              }
            }, 100);
          }
          const vnode = createVNode(ElDialog, {
            title: '空托盘入库',
            width: '400px',
            modelValue: true,
            appendToBody: true,
      //     const selectBoxCodeInput = () => {
      //       setTimeout(() => {
      //         const inputRef = vnode.component.refs.boxCodeInput;
      //         if (inputRef) {
      //           const targetInput = inputRef.$el?.querySelector('input') || inputRef;
      //           targetInput?.focus();
      //           targetInput?.select();
      //         }
      //       }, 100);
      //     }
      //     const vnode = createVNode(ElDialog, {
      //       title: '空托盘入库',
      //       width: '400px',
      //       modelValue: true,
      //       appendToBody: true,
            onOpened: async () => {
              await getWarehouseList();
              const inputRef = vnode.component.refs.boxCodeInput;
              inputRef?.focus();
            },
            'onUpdate:modelValue': (isVisible) => {
              if (!isVisible) {
                render(null, mountNode);
                document.body.removeChild(mountNode);
              }
            }
          }, {
            default: () => h(ElForm, {
              model: formData,
              rules: {
                boxCode: [
                  { required: true, message: '请输入料箱码', trigger: ['blur', 'enter'] }
                ],
                warehouseCode: [
                  { required: true, message: '请选择区域', trigger: ['change', 'blur'] }
                ]
              },
              ref: 'batchInForm'
            }, [
              //仓库数据
              h(ElFormItem, { label: '区域', prop: 'warehouseCode', required: true }, [
                h(ElSelect, {
                  modelValue: formData.warehouseCode,
                  'onUpdate:modelValue': (val) => {
                    formData.warehouseCode = val;
                  },
                  placeholder: '请选择入库区域',
                  filterable: true, // æ”¯æŒæœç´¢ä»“库
                  loading: isLoadingWarehouses.value, // åŠ è½½çŠ¶æ€
                  style: { width: '100%' }
                }, [
                  // æ¸²æŸ“仓库下拉选项
                  warehouses.value.map(item => h(ElOption, {
                    label: item.label,
                    value: item.value
                  }))
                ])
              ]),
              // æ–™ç®±ç è¾“入项(支持聚焦、回车提交)
              h(ElFormItem, { label: '料箱码', prop: 'boxCode', required: true }, [
                h(ElInput, {
                  type: 'text',
                  modelValue: formData.boxCode,
                  'onUpdate:modelValue': (val) => {
                    formData.boxCode = val;
                  },
                  ref: 'boxCodeInput',
                  placeholder: '扫码输入或手动输入料箱码',
                  // ç›‘听回车事件(扫码枪默认会发送回车)
                  onKeydown: (e) => {
                    if (e.key === 'Enter') {
                      e.preventDefault();
                      submitForm();
                    }
                  }
                })
              ]),
              // åº•部按钮区
              h('div', { style: { textAlign: 'right', marginTop: '16px' } }, [
                h(ElButton, {
                  type: 'text',
                  onClick: () => {
                    render(null, mountNode);
                    document.body.removeChild(mountNode);
                    ElMessage.info('取消入库任务');
                  }
                }, '取消'),
                h(ElButton, {
                  type: 'primary',
                  onClick: submitForm
                }, '确定')
              ])
            ])
          });
      //       onOpened: async () => {
      //         await getWarehouseList();
      //         const inputRef = vnode.component.refs.boxCodeInput;
      //         inputRef?.focus();
      //       },
      //       'onUpdate:modelValue': (isVisible) => {
      //         if (!isVisible) {
      //           render(null, mountNode);
      //           document.body.removeChild(mountNode);
      //         }
      //       }
      //     }, {
      //       default: () => h(ElForm, {
      //         model: formData,
      //         rules: {
      //           boxCode: [
      //             { required: true, message: '请输入料箱码', trigger: ['blur', 'enter'] }
      //           ],
      //           warehouseCode: [
      //             { required: true, message: '请选择区域', trigger: ['change', 'blur'] }
      //           ]
      //         },
      //         ref: 'batchInForm'
      //       }, [
      //         //仓库数据
      //         h(ElFormItem, { label: '区域', prop: 'warehouseCode', required: true }, [
      //           h(ElSelect, {
      //             modelValue: formData.warehouseCode,
      //             'onUpdate:modelValue': (val) => {
      //               formData.warehouseCode = val;
      //             },
      //             placeholder: '请选择入库区域',
      //             filterable: true, // æ”¯æŒæœç´¢ä»“库
      //             loading: isLoadingWarehouses.value, // åŠ è½½çŠ¶æ€
      //             style: { width: '100%' }
      //           }, [
      //             // æ¸²æŸ“仓库下拉选项
      //             warehouses.value.map(item => h(ElOption, {
      //               label: item.label,
      //               value: item.value
      //             }))
      //           ])
      //         ]),
      //         // æ–™ç®±ç è¾“入项(支持聚焦、回车提交)
      //         h(ElFormItem, { label: '料箱码', prop: 'boxCode', required: true }, [
      //           h(ElInput, {
      //             type: 'text',
      //             modelValue: formData.boxCode,
      //             'onUpdate:modelValue': (val) => {
      //               formData.boxCode = val;
      //             },
      //             ref: 'boxCodeInput',
      //             placeholder: '扫码输入或手动输入料箱码',
      //             // ç›‘听回车事件(扫码枪默认会发送回车)
      //             onKeydown: (e) => {
      //               if (e.key === 'Enter') {
      //                 e.preventDefault();
      //                 submitForm();
      //               }
      //             }
      //           })
      //         ]),
      //         // åº•部按钮区
      //         h('div', { style: { textAlign: 'right', marginTop: '16px' } }, [
      //           h(ElButton, {
      //             type: 'text',
      //             onClick: () => {
      //               render(null, mountNode);
      //               document.body.removeChild(mountNode);
      //               ElMessage.info('取消入库任务');
      //             }
      //           }, '取消'),
      //           h(ElButton, {
      //             type: 'primary',
      //             onClick: submitForm
      //           }, '确定')
      //         ])
      //       ])
      //     });
          vnode.appContext = this.$.appContext;
          render(vnode, mountNode);
        }
      }
      //     vnode.appContext = this.$.appContext;
      //     render(vnode, mountNode);
      //   }
      // }
    ], box: [], detail: []
  },
  methods: {
    //下面这些方法可以保留也可以删除
    onInit() {
      var EmptyTrayInboundBtn = this.buttons.find(x => x.value == "EmptyTrayInbound");
        if (EmptyTrayInboundBtn != null) {
          EmptyTrayInboundBtn.onClick = () => {
               this.$refs.gridHeader.open();
            }
        }
      this.columns.forEach(column => {
        if (column.field === 'orderStatistics') {
          column.formatter = (row) => {
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/EmptyTrayOutbound.vue
@@ -1,17 +1,19 @@
<template>
  <vol-box v-model="show" title="空托出库" :width="400" :height="600">
  <vol-box v-model="show" title="空托出库" :width="800" :height="1200">
    <template #content>
      <el-form ref="form" :model="form" label-width="90px">
        <el-form-item label="出库区域:">
          <el-select v-model="locationType" placeholder="请选择出库区域">
            <el-option v-for="item in locationTypes" :key="item.locationType" :label="item.locationTypeDesc.toString()" :value="item.locationType">
            <el-option v-for="item in locationTypes" :key="item.locationType" :label="item.locationTypeDesc.toString()"
              :value="item.locationType">
            </el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <el-form ref="form" :model="form" label-width="90px">
        <el-form-item label="出库数量:">
          <el-input-number v-model="num" :min="1" :max="999" :controls="true" placeholder="请选择出库数量" style="width: 100%;"></el-input-number>
          <el-input-number v-model="num" :min="1" :max="999" :controls="true" placeholder="请选择出库数量"
            style="width: 100%;"></el-input-number>
        </el-form-item>
      </el-form>
    </template>
@@ -39,7 +41,7 @@
      num: 1,
      show: false,
      locationTypes: [],
      locationType:"",
      locationType: "",
    }
  },
  methods: {
@@ -63,7 +65,7 @@
    },
    getData() {
      this.http.post("api/LocationInfo/GetLocationTypes",null, "查询中")
      this.http.post("api/LocationInfo/GetLocationTypes", null, "查询中")
        .then((x) => {
          this.locationTypes = x.data;
        })
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IInboundService/IInboundOrderService.cs
@@ -25,5 +25,7 @@
        WebResponseContent UnPalletQuantity(string orderNo);
        WebResponseContent UndoPalletGroup(string palletCode , string barcode = "");
        WebResponseContent UnPalletGroupBarcode(string orderNo);
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_InboundService/InboundOrderService.cs
@@ -645,15 +645,19 @@
                {
                    resultDTO.UniqueUnit = "";
                }
                var validDetails = _stockDetailRepository.Db.Queryable<Dt_StockInfoDetail>().Where(s => s.OrderNo == orderNo).ToList();
                resultDTO.StockSumQuantity = orderDetail.Details.Sum(d => d.OrderQuantity);
                resultDTO.StockCount = orderDetail.Details.Count;
                if (validDetails.Any())
                {
                    resultDTO.StockSumQuantity -= validDetails.Sum(d => d.StockQuantity);
                    // æ˜Žç»†è®°å½•数:符合条件的有效记录条数
                    resultDTO.StockCount -= validDetails.Count;
                }
                var inbound =_inboundOrderRepository.Db.Queryable<Dt_InboundOrder>().Where(x => x.InboundOrderNo == orderNo);
                var inboundDetails = _inboundOrderDetailRepository.Db.Queryable<Dt_InboundOrderDetail>().Where(x => x.OrderId == inbound.First().Id).ToList();
                resultDTO.StockSumQuantity = inboundDetails.Where(x=>x.ReceiptQuantity==0).Sum(x=>x.OrderQuantity);
                resultDTO.StockCount = inboundDetails.Where(x => x.ReceiptQuantity == 0).Count();
                //var validDetails = _stockDetailRepository.Db.Queryable<Dt_StockInfoDetail>().Where(s => s.OrderNo == orderNo).ToList();
                //resultDTO.StockSumQuantity = orderDetail.Details.Sum(d => d.OrderQuantity);
                //resultDTO.StockCount = orderDetail.Details.Count;
                //if (validDetails.Any())
                //{
                //    resultDTO.StockSumQuantity -= validDetails.Sum(d => d.StockQuantity);
                //    // æ˜Žç»†è®°å½•数:符合条件的有效记录条数
                //    resultDTO.StockCount -= validDetails.Count;
                //}
                return content.OK("", resultDTO);
            }
            catch (Exception ex)
@@ -881,5 +885,18 @@
        //    return new PageGridData<Dt_InboundOrder>();
        //}
        public WebResponseContent UnPalletGroupBarcode(string orderNo)
        {
            WebResponseContent content = new WebResponseContent();
            var inbound = _inboundOrderRepository.Db.Queryable<Dt_InboundOrder>().Where(x => x.InboundOrderNo == orderNo).First();
            if(inbound == null)
            {
                return content.Error();
            }
            var details = _inboundOrderDetailRepository.Db.Queryable<Dt_InboundOrderDetail>().Where(x => x.OrderId == inbound.Id && x.ReceiptQuantity == 0).ToList();
            return content.OK(data:details);
        }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundBatchPickingService.cs
@@ -943,7 +943,7 @@
        /// <summary>
        /// æ‰§è¡Œæ‰‹åŠ¨æ‹†åŒ…é€»è¾‘ - ä¿®å¤ç‰ˆæœ¬
        /// æ‰§è¡Œæ‰‹åŠ¨æ‹†åŒ…é€»è¾‘
        /// </summary>
        private async Task<List<SplitResult>> ExecuteManualSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
            decimal splitQuantity, string palletCode)
@@ -1001,8 +1001,8 @@
                    MaterielCode = stockDetail.MaterielCode,
                    OrderNo = stockDetail.OrderNo,
                    BatchNo = stockDetail.BatchNo,
                    StockQuantity = newStockQuantity,  // ä¿®å¤ï¼šä½¿ç”¨æ­£ç¡®çš„æ‹†åŒ…数量
                    OutboundQuantity = 0,  // æ–°æ¡ç åˆå§‹å‡ºåº“数量为0
                    StockQuantity = newStockQuantity,
                    OutboundQuantity = 0,
                    Barcode = newBarcode,
                    Status = (int)StockStatusEmun.出库锁定,
                    SupplyCode = stockDetail.SupplyCode,
@@ -1011,6 +1011,8 @@
                    BarcodeUnit = stockDetail.BarcodeUnit,
                    BusinessType = stockDetail.BusinessType,
                    InboundOrderRowNo = stockDetail.InboundOrderRowNo,
                    FactoryArea = stockDetail.FactoryArea,
                    WarehouseCode = stockDetail.WarehouseCode,
                };
                await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
@@ -3156,17 +3158,7 @@
            _logger.LogInformation($"需要自动拆包 - åº“å­˜: {stockDetail.StockQuantity}, åˆ†é…: {lockInfo.AssignQuantity}, æ‹†åŒ…数量: {splitQuantity}");
            // æ‰§è¡Œè‡ªåŠ¨æ‹†åŒ…
            var splitResult = await ExecuteAutoSplitLogic(lockInfo, stockDetail, splitQuantity, palletCode);
            // å°†æ‹†åŒ…数量传递给调用方,用于验证
            if (splitResult != null && splitResult.Any())
            {
                // åœ¨è¿”回结果中携带拆包数量信息
                foreach (var result in splitResult)
                {
                    result.quantityTotal = splitQuantity.ToString("F2");
                }
            }
            var splitResult = await ExecuteAutoSplitLogic(lockInfo, stockDetail, splitQuantity,  palletCode);
            return splitResult;
        }
@@ -3176,7 +3168,7 @@
        /// åŽŸåˆ™ï¼šåªåˆ†ç¦»ç‰©ç†åº“å­˜ï¼Œä¸æ”¹å˜åŽŸè®¢å•çš„ä»»ä½•åˆ†é…å’Œå‡ºåº“æ•°é‡
        /// </summary>
        private async Task<List<SplitResult>> ExecuteAutoSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
            decimal splitQuantity, string palletCode)
            decimal splitQuantity,string palletCode)
        {
            _logger.LogInformation($"开始执行自动拆包逻辑 - åŽŸæ¡ç : {stockDetail.Barcode}, æ‹†åŒ…数量: {splitQuantity}");
@@ -3218,6 +3210,8 @@
                    BarcodeUnit = stockDetail.BarcodeUnit,
                    BusinessType = stockDetail.BusinessType,
                    InboundOrderRowNo = stockDetail.InboundOrderRowNo,
                    FactoryArea=stockDetail.FactoryArea,
                    WarehouseCode = stockDetail.WarehouseCode,
                };
                await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
@@ -3265,7 +3259,7 @@
                await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode, true, originalStockQty);
                // åˆ›å»ºæ‹†åŒ…结果列表
                var splitResults = CreateSplitResults(lockInfo, splitQuantity, lockInfo.AssignQuantity, newBarcode, stockDetail.Barcode);
                var splitResults = CreateSplitResults(lockInfo, splitQuantity, stockDetail.StockQuantity, newBarcode, stockDetail.Barcode);
                _logger.LogInformation($"自动拆包逻辑执行完成 - åˆ›å»ºäº†æœªåˆ†é…çš„库存和锁定记录");
@@ -3715,20 +3709,29 @@
        {
            var splitHistory = new Dt_SplitPackageRecord
            {
                OrderNo = lockInfo.OrderNo,
                FactoryArea = lockInfo.FactoryArea,
                TaskNum = lockInfo.TaskNum,
                OutStockLockInfoId = lockInfo.Id,
                StockId = stockDetail.StockId,
                Operator = App.User.UserName,
                IsReverted = false,
                OriginalBarcode = stockDetail.Barcode,
                NewBarcode = newBarcode,
                SplitQty = splitQty,
               // RemainQuantity = remainQty,
                MaterielCode = lockInfo.MaterielCode,
                SplitTime = DateTime.Now,
                OrderNo = lockInfo.OrderNo,
                PalletCode = lockInfo.PalletCode,
                Status = (int)SplitPackageStatusEnum.已拆包,
                IsAutoSplit = isAutoSplit,
                // SplitType = isAutoSplit ? "自动拆包" : "手动拆包"
                OriginalStockQuantity = originalStockQuantity ?? stockDetail.StockQuantity,
                //RemainingStockQuantity = stockDetail.StockQuantity - splitQty
                TaskNum = lockInfo.TaskNum
            };
            await _splitPackageService.Db.Insertable(splitHistory).ExecuteCommandAsync();
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -2844,7 +2844,8 @@
                        FactoryArea = item.FactoryArea,
                        Status = 0,
                        OrderNo = item.OrderNo,
                        BusinessType = materielGroupDTO.orderTypes.ToString()
                        BusinessType = materielGroupDTO.orderTypes.ToString(),
                    });
                    item.WarehouseCode = item.WarehouseCode;
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/SplitPackageService.cs
@@ -108,6 +108,7 @@
                    OutboundQuantity = request.SplitQuantity,
                    Barcode = newBarcode,
                    InboundOrderRowNo = baseStockDetail.InboundOrderRowNo,
                    FactoryArea = baseStockDetail.FactoryArea,
                };
                await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -303,11 +303,11 @@
                _recordService.StockQuantityChangeRecordService.AddStockChangeRecord(stockInfo, stockInfo.Details, beforeQuantity, stockInfo.Details.Sum(x => x.StockQuantity) + beforeQuantity, WIDESEA_Common.StockEnum.StockChangeType.MaterielGroup);
            }
            catch(Exception ex)
            catch (Exception ex)
            {
                _logger.LogInformation($"InboundTaskCompleted AddLocationStatusChangeRecord : {ex.Message} " );
                _logger.LogInformation($"InboundTaskCompleted AddLocationStatusChangeRecord : {ex.Message} ");
            }
                try
            try
            {
                foreach (var inboundOrder in inboundOrders)
                {
@@ -579,7 +579,7 @@
                {
                    _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforelocationStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum);
                }
                catch(Exception ex)
                catch (Exception ex)
                {
                    _logger.LogInformation($"InEmptyTaskCompleted AddLocationStatusChangeRecord : {ex.Message} ");
                }
@@ -696,7 +696,7 @@
                {
                    await Db.Deleteable(task).ExecuteCommandAsync();
                }
                await RecalculateOrderStatus(task.OrderNo);
                try
                {
@@ -757,8 +757,8 @@
        {
            try
            {
                // èŽ·å–å—å½±å“çš„è®¢å•æ˜Žç»†ID(去重)
                //var affectedDetailIds = returnLocks
                //    .Select(x => x.OrderDetailId)
@@ -999,7 +999,7 @@
                    _logger.LogInformation($"更新订单状态 - OrderNo: {orderNo}, æ—§çŠ¶æ€: {outboundOrder.OrderStatus}, æ–°çŠ¶æ€: {newStatus}");
                }
            }
            catch (Exception ex)
            {
@@ -1136,8 +1136,33 @@
                                allocatefeedmodel.Details.Add(detailModel);
                            }
                            var groupedResult = allocatefeedmodel.Details.GroupBy(item => new
                            {
                                item.WarehouseCode,
                                item.MaterialCode,
                                item.Unit,
                                item.LineNo
                            }).Select(group => new AllocateDtoDetail
                            {
                                 WarehouseCode = group.Key.WarehouseCode,
                                 MaterialCode = group.Key.MaterialCode,
                                 LineNo = group.Key.LineNo,
                                 Qty = group.Sum(x => x.Qty),
                                 Unit = group.Key.Unit,
                                 Barcodes = group.SelectMany(x => x.Barcodes)
                                                       .GroupBy(b => b.Barcode)
                                                       .Select(b => new BarcodeInfo
                                                       {
                                                           Barcode = b.Key,
                                                           BatchNo = b.First().BatchNo,
                                                           SupplyCode = b.First().SupplyCode,
                                                           Qty = b.Max(x => x.Qty),
                                                           Unit = b.First().Unit
                                                       }) .ToList()
                             }) .ToList();
                            allocatefeedmodel.Details = groupedResult;
                            var result = await _invokeMESService.FeedbackAllocate(allocatefeedmodel);
                          var result = await _invokeMESService.FeedbackAllocate(allocatefeedmodel);
                            if (result != null && result.code == 200)
                            {
                                await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
@@ -1222,6 +1247,31 @@
                                }
                                feedmodel.details.Add(detailModel);
                            }
                            var groupedResult = feedmodel.details.GroupBy(item => new
                            {
                                item.warehouseCode,
                                item.materialCode,
                                item.unit,
                                item.lineNo
                            }).Select(group => new FeedbackOutboundDetailsModel
                            {
                                warehouseCode = group.Key.warehouseCode,
                                materialCode = group.Key.materialCode,
                                lineNo = group.Key.lineNo,
                                qty = group.Sum(x => x.qty),
                                unit = group.Key.unit,
                                barcodes = group.SelectMany(x => x.barcodes)
                                                       .GroupBy(b => b.barcode)
                                                       .Select(b => new WIDESEA_DTO.Outbound.BarcodesModel
                                                       {
                                                           barcode = b.Key,
                                                           batchNo = b.First().batchNo,
                                                           supplyCode = b.First().supplyCode,
                                                           qty = b.Max(x => x.qty),
                                                           unit = b.First().unit
                                                       }).ToList()
                            }).ToList();
                            feedmodel.details = groupedResult;
                            var result = await _invokeMESService.FeedbackOutbound(feedmodel);
                            if (result != null && result.code == 200)
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Inbound/InboundOrderController.cs
@@ -66,8 +66,7 @@
        [HttpPost, Route("Test"), AllowAnonymous, MethodParamsValidate]
        public async Task<WebResponseContent> Test()
        {
        {
            //var originalTask = _taskRepository.Db.Queryable<Dt_Task>().First();
            //var result = _task_HtyService.DeleteAndMoveIntoHty(originalTask, OperateTypeEnum.人工删除);
@@ -91,7 +90,7 @@
            //var  ddddssss = "WSLOT" + DateTime.Now.ToString("yyyyMMddHHmmss") + ssss.ToString().PadLeft(5, '0');
            //erpApiService.GetSuppliersAsync();
            erpApiService.GetMaterialUnitAsync();
           // erpApiService.GetMaterialUnitAsync();
            //var sss = await _invokeMESService.NewMaterielToMes(new WIDESEA_DTO.Basic.MaterielToMesDTO
            //{
@@ -214,6 +213,12 @@
        }
        [HttpPost, Route("UnPalletGroupBarcode"), AllowAnonymous, MethodParamsValidate]
        public WebResponseContent UnPalletGroupBarcode(string orderNo)
        {
            return Service.UnPalletGroupBarcode(orderNo);
        }
        [HttpPost, Route("UndoPalletGroup"), AllowAnonymous, MethodParamsValidate]
        public WebResponseContent UndoPalletGroup(string palletCode,string barcode="")
        {