heshaofeng
2025-12-04 1e8ca092e08494e78c398c6262aff94ac5a5bb22
Merge branch 'master' of http://115.159.85.185:8098/r/ZhongRui/ALDbanyunxiangmu
已修改7个文件
562 ■■■■ 文件已修改
项目代码/WIDESEA_WMSClient/src/views/outbound/BatchPickingConfirm.vue 282 ●●●●● 补丁 | 查看 | 原始文档 | 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_CheckService/ReCheckOrderService.cs 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Core/BaseRepository/RepositoryBase.cs 249 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Inbound/InboundOrderController.cs 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/outbound/BatchPickingConfirm.vue
@@ -92,7 +92,7 @@
    </div>
    <!-- æ‹†åŒ…弹窗 -->
    <div v-if="showCustomSplitDialog" class="custom-dialog-overlay">
    <div  v-show="showCustomSplitDialog" class="custom-dialog-overlay">
      <div class="custom-dialog-wrapper">
        <div class="custom-dialog">
          <div class="custom-dialog-header">
@@ -154,7 +154,7 @@
    </div>
    <!-- æ’¤é”€æ‹†åŒ…弹窗 -->
    <div v-if="showRevertSplitDialog" class="custom-dialog-overlay">
    <div  v-show="showRevertSplitDialog" class="custom-dialog-overlay">
      <div class="custom-dialog-wrapper">
        <div class="custom-dialog">
          <div class="custom-dialog-header">
@@ -214,7 +214,7 @@
    </div>
    <!-- æ‹†åŒ…链信息弹窗 -->
<div v-if="showSplitChainDialog" class="custom-dialog-overlay">
<div v-show="showSplitChainDialog" class="custom-dialog-overlay">
  <div class="custom-dialog-wrapper">
    <div class="custom-dialog" style="width: 750px;">
      <div class="custom-dialog-header">
@@ -501,11 +501,87 @@
          { required: true, message: '请输入托盘码', trigger: 'blur' }
        ]
      },
       // å¼¹çª—状态 - æ”¹ä¸ºä½¿ç”¨å¯¹è±¡ç®¡ç†ï¼Œé¿å…åŒæ—¶æ‰“开多个弹窗
      dialogs: {
        customSplit: false,
        revertSplit: false,
        splitChain: false,
        batchReturn: false,
        emptyPallet: false
      },
      
      // åŠ è½½çŠ¶æ€
      loading: {
        split: false,
        revertSplit: false,
        batchReturn: false,
        emptyPallet: false,
        splitChain: false
      },
      // å½“前活动的弹窗类型
      activeDialog: null,
      isProcessing: false
    }
  },
  computed: {
     // è®¡ç®—属性映射到dialogs对象
    showCustomSplitDialog: {
      get() { return this.dialogs.customSplit; },
      set(val) {
        this.dialogs.customSplit = val;
        this.activeDialog = val ? 'customSplit' : null;
      }
    },
    showRevertSplitDialog: {
      get() { return this.dialogs.revertSplit; },
      set(val) {
        this.dialogs.revertSplit = val;
        this.activeDialog = val ? 'revertSplit' : null;
      }
    },
    showSplitChainDialog: {
      get() { return this.dialogs.splitChain; },
      set(val) {
        this.dialogs.splitChain = val;
        this.activeDialog = val ? 'splitChain' : null;
      }
    },
    showBatchReturnDialog: {
      get() { return this.dialogs.batchReturn; },
      set(val) {
        this.dialogs.batchReturn = val;
        this.activeDialog = val ? 'batchReturn' : null;
      }
    },
    showEmptyPalletDialog: {
      get() { return this.dialogs.emptyPallet; },
      set(val) {
        this.dialogs.emptyPallet = val;
        this.activeDialog = val ? 'emptyPallet' : null;
      },
    },
     // åŠ è½½çŠ¶æ€æ˜ å°„
    splitLoading: {
      get() { return this.loading.split; },
      set(val) { this.loading.split = val; }
    },
    revertSplitLoading: {
      get() { return this.loading.revertSplit; },
      set(val) { this.loading.revertSplit = val; }
    },
    batchReturnLoading: {
      get() { return this.loading.batchReturn; },
      set(val) { this.loading.batchReturn = val; }
    },
    emptypalletOutLoading: {
      get() { return this.loading.emptyPallet; },
      set(val) { this.loading.emptyPallet = val; }
    },
    splitChainLoading: {
      get() { return this.loading.splitChain; },
      set(val) { this.loading.splitChain = val; }
    },
    // æ˜¯å¦å¯ä»¥å–消整个拆包链
    canCancelWholeChain() {
      return this.splitChainInfo.splitChain && 
@@ -574,10 +650,23 @@
        this.$message.warning('请先扫描托盘码');
        return;
      }
         // å…³é—­å…¶ä»–所有弹窗
      this.closeAllDialogs();
        // å»¶è¿Ÿæ‰“开新弹窗,确保其他弹窗完全关闭
      this.$nextTick(() => {
      this.showCustomSplitDialog = true;
      this.resetSplitForm();
      this.splitForm.orderNo = this.scanData.orderNo;
      this.splitForm.palletCode = this.scanData.palletCode;
        // ç¡®ä¿è¾“入框获得焦点
        this.$nextTick(() => {
          const inputs = document.querySelectorAll('.custom-dialog input');
          if (inputs.length > 0) {
            inputs[0].focus();
          }
        });
      });
    },
    async onSplitBarcodeScan() {
@@ -608,8 +697,9 @@
    async handleSplitPackage() {
      if (this.$refs.splitFormRef) {
        this.$refs.splitFormRef.validate(async (valid) => {
          if (valid) {
        const valid = await this.$refs.splitFormRef.validate();
        if (!valid) return;
            this.splitLoading = true;
            try {
              const res = await http.post('/api/OutboundBatchPicking/split-package', {
@@ -626,12 +716,10 @@
                this.$message.error(res.message || '拆包失败');
              }
            } catch (error) {
              this.$message.error('拆包失败');
          this.$message.error('拆包失败: ' + (error.message || '网络错误'));
            } finally {
              this.splitLoading = false;
            }
          }
        });
      }
    },
// åœ¨æ‹†åŒ…弹窗中查看拆包链
@@ -653,15 +741,13 @@
    async onRevertSplitBarcodeScan() {
      if (!this.revertSplitForm.newBarcode) return;
      this.revertSplitForm.newBarcode = this.revertSplitForm.newBarcode.replace(/\n/g, '').trim();
      // æ–°å¢žï¼šæ‰«æåŽè‡ªåŠ¨æ˜¾ç¤ºæ‹†åŒ…é“¾ä¿¡æ¯
      await this.viewSplitChain(this.revertSplitForm.newBarcode);
    },
    async handleRevertSplit() {
      if (this.$refs.revertSplitFormRef) {
        this.$refs.revertSplitFormRef.validate(async (valid) => {
          if (valid) {
        const valid = await this.$refs.revertSplitFormRef.validate();
        if (!valid) return;
            this.revertSplitLoading = true;
            try {
              const res = await http.post('/api/OutboundBatchPicking/cancel-split', {
@@ -677,12 +763,10 @@
                this.$message.error(res.message || '撤销拆包失败');
              }
            } catch (error) {
              this.$message.error('撤销拆包失败');
          this.$message.error('撤销拆包失败: ' + (error.message || '网络错误'));
            } finally {
              this.revertSplitLoading = false;
            }
          }
        });
      }
    },
// æŸ¥æ‰¾å®Œæ•´æ‹†åŒ…链(从根条码开始)
@@ -724,7 +808,13 @@
    if (res.status) {
      this.splitChainInfo = res.data;
      
      // æ˜¾ç¤ºæç¤ºä¿¡æ¯ï¼Œå‘Šè¯‰ç”¨æˆ·è¿™æ˜¯ä»€ä¹ˆç±»åž‹çš„æ‹†åŒ…链
          // å…³é—­å…¶ä»–弹窗后再打开拆包链弹窗
          this.closeAllDialogs();
          await this.$nextTick(() => {
            this.showSplitChainDialog = true;
            // æ˜¾ç¤ºæç¤ºä¿¡æ¯
      let chainType = "当前条码的拆包链";
      if (this.splitChainInfo.chainType === 'root') {
        chainType = "完整拆包链(从原始条码开始)";
@@ -733,12 +823,12 @@
      }
      
      this.$message.info(`已加载${chainType},共${this.splitChainInfo.totalSplitTimes}次拆包`);
      this.showSplitChainDialog = true;
          });
    } else {
      this.$message.error(res.message || '获取拆包链信息失败');
    }
  } catch (error) {
    this.$message.error('获取拆包链信息失败');
        this.$message.error('获取拆包链信息失败: ' + (error.message || '网络错误'));
  } finally {
    this.splitChainLoading = false;
  }
@@ -788,20 +878,15 @@
},
    // å–消单个拆包记录
async cancelSingleSplit(newBarcode) {
  // å…ˆè®°å½•当前信息,然后关闭弹窗
  const originalBarcode = this.splitChainInfo.originalBarcode;
  this.closeSplitChainDialog();
  await this.$nextTick();
  try {
    await this.$confirm(
        await ElMessageBox.confirm(
      `确定要取消条码 ${newBarcode} çš„æ‹†åŒ…操作吗?`, 
      '取消单个拆包', 
      {
        confirmButtonText: '确定取消',
        cancelButtonText: '再想想',
        type: 'warning'
            type: 'warning',
            customClass: 'message-box-top'
      }
    );
    
@@ -816,19 +901,17 @@
    if (res.status) {
      this.$message.success('取消拆包成功');
      await this.loadPalletData();
      // é‡æ–°æ‰“开弹窗显示更新后的状态
      await this.viewSplitChain(originalBarcode);
          // é‡æ–°åŠ è½½æ‹†åŒ…é“¾ä¿¡æ¯
          if (this.splitChainInfo.originalBarcode) {
            await this.viewSplitChain(this.splitChainInfo.originalBarcode);
          }
    } else {
      this.$message.error(res.message || '取消拆包失败');
      await this.viewSplitChain(originalBarcode);
    }
  } catch (error) {
    if (error === 'cancel') {
      // ç”¨æˆ·å–消后重新打开弹窗
      await this.viewSplitChain(originalBarcode);
    } else {
      this.$message.error('取消拆包失败');
      await this.viewSplitChain(originalBarcode);
        if (error !== 'cancel') {
          this.$message.error('取消拆包失败: ' + error.message);
    }
  } finally {
    this.revertSplitLoading = false;
@@ -837,59 +920,40 @@
// å–消整个拆包链  
async cancelWholeSplitChain() {
  // å…ˆè®°å½•当前拆包链信息,然后关闭弹窗
  const originalBarcode = this.splitChainInfo.originalBarcode;
  this.closeSplitChainDialog();
  // ç»™ä¸€ç‚¹æ—¶é—´è®©å¼¹çª—完全关闭
  await this.$nextTick();
  if (!this.canCancelWholeChain) return;
  
  try {
    // çŽ°åœ¨æ˜¾ç¤ºç¡®è®¤å¯¹è¯æ¡†ï¼Œç¡®ä¿å®ƒåœ¨æœ€å‰é¢
    await this.$confirm(
      `确定要取消整个拆包链吗?\n这将取消从条码 ${originalBarcode} å¼€å§‹çš„æ‰€æœ‰æ‹†åŒ…操作。`,
        await ElMessageBox.confirm(
          `确定要取消整个拆包链吗?\n这将取消从条码 ${this.splitChainInfo.originalBarcode} å¼€å§‹çš„æ‰€æœ‰æ‹†åŒ…操作。`,
      '取消拆包链确认', 
      {
        confirmButtonText: '确定取消',
        cancelButtonText: '再想想',
        type: 'warning',
        center: true,
        closeOnClickModal: false
            closeOnClickModal: false,
            customClass: 'message-box-top'
      }
    );
    
    // ç”¨æˆ·ç¡®è®¤åŽæ‰§è¡Œå–消操作
    this.revertSplitLoading = true;
    
    const res = await http.post('/api/OutboundBatchPicking/cancel-split-chain', {
      orderNo: this.scanData.orderNo,
      palletCode: this.scanData.palletCode,
      startBarcode: originalBarcode
          startBarcode: this.splitChainInfo.originalBarcode
    });
    console.log('取消拆包链响应:', res);
    
    if (res.status) {
      this.$message.success('取消拆包链成功');
          this.closeSplitChainDialog();
      await this.loadPalletData();
      // å¯é€‰ï¼šé‡æ–°æ‰“开拆包链信息弹窗显示更新后的状态
      // await this.viewSplitChain(originalBarcode);
    } else {
      this.$message.error(res.message || '取消拆包链失败');
      // å¤±è´¥åŽé‡æ–°æ‰“开弹窗
      await this.viewSplitChain(originalBarcode);
    }
  } catch (error) {
    // ç”¨æˆ·å–消操作
    if (error === 'cancel') {
      console.log('用户取消了拆包链操作');
      // ç”¨æˆ·å–消后重新打开弹窗
      await this.viewSplitChain(originalBarcode);
    } else {
      console.error('取消拆包链错误:', error);
        if (error !== 'cancel') {
      this.$message.error('取消拆包链失败: ' + error.message);
      // å‡ºé”™åŽé‡æ–°æ‰“开弹窗
      await this.viewSplitChain(originalBarcode);
    }
  } finally {
    this.revertSplitLoading = false;
@@ -907,18 +971,31 @@
      const date = new Date(dateTime);
      return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}`;
    },
 closeAllDialogs() {
      this.showCustomSplitDialog = false;
      this.showRevertSplitDialog = false;
      this.showSplitChainDialog = false;
      this.showBatchReturnDialog = false;
      this.showEmptyPalletDialog = false;
      this.activeDialog = null;
    },
    // å›žåº“相关方法
    openBatchReturnDialog() {
      if (!this.scanData.palletCode) {
        this.$message.warning('请先扫描托盘码');
        return;
      }
      // å…³é—­å…¶ä»–弹窗
      this.closeAllDialogs();
      this.$nextTick(() => {
      this.showBatchReturnDialog = true;
      this.batchReturnForm.orderNo = this.scanData.orderNo;
      this.batchReturnForm.palletCode = this.scanData.palletCode;
      this.batchReturnForm.unpickedCount = this.summary.unpickedCount;
      this.batchReturnForm.unpickedQuantity = this.summary.unpickedQuantity;
      });
    },
    async handleBatchReturnConfirm() {
@@ -936,7 +1013,7 @@
          this.$message.error(res.message || '回库失败');
        }
      } catch (error) {
        this.$message.error('回库失败');
        this.$message.error('回库失败: ' + (error.message || '网络错误'));
      } finally {
        this.batchReturnLoading = false;
      }
@@ -944,9 +1021,14 @@
    // å–空箱方法
    handleEmptyPallet() {
      // å…³é—­å…¶ä»–弹窗
      this.closeAllDialogs();
      this.$nextTick(() => {
      this.showEmptyPalletDialog = true;
      this.emptypalletOutForm.orderNo = this.scanData.orderNo;
      this.emptypalletOutForm.palletCode = '';
      });
    },
    async handleEmptyPalletConfirm() {
@@ -964,7 +1046,7 @@
          this.$message.error(res.message || '取走空箱失败');
        }
      } catch (error) {
        this.$message.error('取走空箱失败');
        this.$message.error('取走空箱失败: ' + (error.message || '网络错误'));
      } finally {
        this.emptypalletOutLoading = false;
      }
@@ -974,9 +1056,15 @@
    async loadPalletData() {
      if (!this.scanData.orderNo || !this.scanData.palletCode) return;
      
      await this.loadUnpickedList();
      await this.loadPickedList();
      await this.loadPalletStatus();
      try {
        await Promise.all([
          this.loadUnpickedList(),
          this.loadPickedList(),
          this.loadPalletStatus()
        ]);
      } catch (error) {
        console.error('加载托盘数据失败:', error);
      }
    },
    async loadUnpickedList() {
@@ -986,12 +1074,12 @@
          palletCode: this.scanData.palletCode
        });
        if (res.status) {
          //this.unpickedList = res.data || [];
          this.unpickedList = (res.data || []).filter(item => item.canPick === true);
          this.summary.unpickedCount = this.unpickedList.length;
          this.summary.unpickedQuantity = this.unpickedList.reduce((sum, item) => sum + (item.remainQuantity || 0), 0);
        }
      } catch (error) {
        console.error('加载未拣选列表失败:', error);
        this.$message.error('加载未拣选列表失败');
      }
    },
@@ -1003,19 +1091,14 @@
          palletCode: this.scanData.palletCode
        });
        if (res.status) {
          this.pickedList = res.data || [];
          this.pickedList = res.data.map(item => {
  // æ–¹å¼1:保留原barcode字段,新增currentBarcode
  return {
          this.pickedList = res.data.map(item => ({
    ...item,
    currentBarcode: item.barcode
  };
});
          }));
          this.summary.pickedCount = this.pickedList.length;
        }
      } catch (error) {
        console.error('加载已拣选列表失败:', error);
        this.$message.error('加载已拣选列表失败');
      }
    },
@@ -1030,6 +1113,7 @@
          this.palletStatus = res.data.statusText || '未知';
        }
      } catch (error) {
        console.error('加载托盘状态失败:', error);
        this.palletStatus = '未知';
      }
    },
@@ -1074,12 +1158,18 @@
        return;
      }
      this.$confirm(`确定要取消选中的 ${this.selectedPickedRows.length} é¡¹å—?`, '提示', {
      try {
        await ElMessageBox.confirm(
          `确定要取消选中的 ${this.selectedPickedRows.length} é¡¹å—?`,
          '提示',
          {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(async () => {
        try {
            type: 'warning',
            customClass: 'message-box-top'
          }
        );
          for (const row of this.selectedPickedRows) {
            try {
              const res = await http.post('/api/OutboundBatchPicking/cancel-picking', {
@@ -1098,9 +1188,10 @@
          await this.loadPalletData();
          this.selectedPickedRows = [];
        } catch (error) {
        if (error !== 'cancel') {
          this.$message.error('批量取消操作失败');
        }
      });
      }
    },
    // é‡ç½®æ–¹æ³•
@@ -1117,8 +1208,13 @@
    },
    openRevertSplitDialog() {
       // å…³é—­å…¶ä»–弹窗
      this.closeAllDialogs();
      this.$nextTick(() => {
      this.showRevertSplitDialog = true;
      this.revertSplitForm.newBarcode = '';
      });
    },
    closeRevertSplitDialog() {
@@ -1184,15 +1280,20 @@
/* è‡ªå®šä¹‰å¼¹çª—样式 */
:deep(.el-message-box) {
  z-index: 10010 !important;
  z-index: 9999 !important;
}
:deep(.el-overlay) {
  z-index: 10009 !important;
  z-index: 9998 !important;
}
:deep(.el-message) {
  z-index: 10011 !important;
  z-index: 10000 !important;
}
/* ç¡®ä¿ç¡®è®¤å¯¹è¯æ¡†åœ¨æœ€å‰é¢ */
:deep(.message-box-top) {
  z-index: 10001 !important;
}
.custom-dialog-overlay {
@@ -1205,7 +1306,7 @@
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000; /* ä¿æŒä¸€ä¸ªåˆç†çš„ z-index */
  z-index: 2000;
}
.custom-dialog-wrapper {
@@ -1276,14 +1377,7 @@
    flex-direction: column;
    align-items: stretch;
  }
  /* ç¡®ä¿ç¡®è®¤å¯¹è¯æ¡†åœ¨æœ€å‰é¢ */
.el-message-box__wrapper {
  z-index: 10001 !important;
}
.el-message {
  z-index: 10002 !important;
}
  .scanner-form .el-input {
    width: 100%;
  }
ÏîÄ¿´úÂë/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_CheckService/ReCheckOrderService.cs
@@ -92,6 +92,11 @@
                {
                    return WebResponseContent.Instance.Error($"未找到单信息");
                }
                var isupdate = false;
                if (recheckOrder.SignSeq == model.SignSeq)
                {
                    isupdate = true;
                }
                recheckOrder.OrderNo = model.OrderNo;
                recheckOrder.MaterielCode = model.MaterielCode;
                recheckOrder.BatchNo = model.BatchNo;
@@ -107,14 +112,15 @@
                BaseDal.UpdateData(recheckOrder);
                if (isupdate)
                {
                _outboundService.OutboundOrderService.Db.Deleteable<Dt_OutboundOrder>().Where(x => x.OrderNo == model.OrderNo).ExecuteCommand();
                _outboundService.OutboundOrderDetailService.Db.Deleteable<Dt_OutboundOrderDetail>()
                 .Where(p => SqlFunc.Subqueryable<Dt_OutboundOrder>().Where(s => s.Id == p.OrderId && s.OrderNo == model.OrderNo).Any()).ExecuteCommand();
                var outboundOrders = ConvertToOutboundOrders(model);
                await _outboundService.OutboundOrderService.ReceiveOutboundOrder(outboundOrders, 1);
                }
                return WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Core/BaseRepository/RepositoryBase.cs
@@ -869,52 +869,235 @@
             .WhereIF(whereExpression != null, whereExpression).ToListAsync();
        }
        //public bool DeleteAndMoveIntoHty(TEntity entity, OperateTypeEnum operateType)
        //{
        //    Type type = entity.GetType();
        //    Assembly assembly = type.Assembly;
        //    Type? htyType = assembly.GetType(type.FullName + "_Hty");
        //    if (htyType != null)
        //    {
        //        object? obj = Activator.CreateInstance(htyType);
        //        PropertyInfo keyPro = typeof(TEntity).GetKeyProperty();
        //        PropertyInfo? operateTypePro = htyType.GetProperty(nameof(IBaseHistoryEntity.OperateType));
        //        PropertyInfo? sourceIdPro = htyType.GetProperty(nameof(IBaseHistoryEntity.SourceId));
        //        if (obj != null && keyPro != null && operateTypePro != null && sourceIdPro != null)
        //        {
        //            operateTypePro.SetValue(obj, operateType.ToString());
        //            sourceIdPro.SetValue(obj, keyPro.GetValue(entity));
        //            List<PropertyInfo> propertyInfos = htyType.GetProperties().Where(x => x.Name != operateTypePro.Name && x.Name != sourceIdPro.Name && x.Name != keyPro.Name).ToList();
        //            for (int i = 0; i < propertyInfos.Count; i++)
        //            {
        //                PropertyInfo propertyInfo = propertyInfos[i];
        //                PropertyInfo? property = type.GetProperty(propertyInfo.Name);
        //                if (property != null)
        //                {
        //                    if (propertyInfo.Name == nameof(BaseEntity.Modifier))
        //                    {
        //                        propertyInfo.SetValue(obj, App.User.UserId > 0 ? App.User.UserName : "System");
        //                    }
        //                    else if (propertyInfo.Name == nameof(BaseEntity.ModifyDate))
        //                    {
        //                        propertyInfo.SetValue(obj, DateTime.Now);
        //                    }
        //                    else
        //                    {
        //                        propertyInfo.SetValue(obj, property.GetValue(entity));
        //                    }
        //                }
        //            }
        //            if (obj != null)
        //                _db.InsertableByObject(obj).AS(type.Name + "_Hty").ExecuteCommand();
        //        }
        //    }
        //    return DeleteData(entity);
        //}
        public bool DeleteAndMoveIntoHty(TEntity entity, OperateTypeEnum operateType)
        {
            Type type = entity.GetType();
            Assembly assembly = type.Assembly;
            Type? htyType = assembly.GetType(type.FullName + "_Hty");
            if (htyType != null)
            {
                object? obj = Activator.CreateInstance(htyType);
                PropertyInfo keyPro = typeof(TEntity).GetKeyProperty();
                PropertyInfo? operateTypePro = htyType.GetProperty(nameof(IBaseHistoryEntity.OperateType));
                PropertyInfo? sourceIdPro = htyType.GetProperty(nameof(IBaseHistoryEntity.SourceId));
                if (obj != null && keyPro != null && operateTypePro != null && sourceIdPro != null)
                {
                    operateTypePro.SetValue(obj, operateType.ToString());
                    sourceIdPro.SetValue(obj, keyPro.GetValue(entity));
            // æ ¸å¿ƒé€»è¾‘:用事务保证原子性,异常捕获避免流程中断,日志辅助排查
            bool isSuccess = false;
            string entityTypeName = entity?.GetType().Name ?? "未知实体";
                    List<PropertyInfo> propertyInfos = htyType.GetProperties().Where(x => x.Name != operateTypePro.Name && x.Name != sourceIdPro.Name && x.Name != keyPro.Name).ToList();
                    for (int i = 0; i < propertyInfos.Count; i++)
            try
                    {
                        PropertyInfo propertyInfo = propertyInfos[i];
                        PropertyInfo? property = type.GetProperty(propertyInfo.Name);
                        if (property != null)
                // å‰ç½®æ ¡éªŒï¼šå®žä½“不能为空
                if (entity == null)
                        {
                            if (propertyInfo.Name == nameof(BaseEntity.Modifier))
                            {
                                propertyInfo.SetValue(obj, App.User.UserId > 0 ? App.User.UserName : "System");
                    return false;
                            }
                            else if (propertyInfo.Name == nameof(BaseEntity.ModifyDate))
                Type entityType = entity.GetType();
                Assembly assembly = entityType.Assembly;
                string htyTypeName = $"{entityType.FullName}_Hty";
                Type? htyType = assembly.GetType(htyTypeName);
                // 1. æ£€æŸ¥åŽ†å²è¡¨ç±»åž‹æ˜¯å¦å­˜åœ¨
                if (htyType == null)
                            {
                                propertyInfo.SetValue(obj, DateTime.Now);
                    return false;
                }
                // 2. åˆ›å»ºåŽ†å²è¡¨å®žä¾‹ï¼ˆå¤„ç†æ— å‚æž„é€ å‡½æ•°ä¸å­˜åœ¨çš„æƒ…å†µï¼‰
                object? htyObj;
                try
                {
                    htyObj = Activator.CreateInstance(htyType);
                }
                catch (Exception ex)
                {
                    // _logger.LogError(ex, "DeleteAndMoveIntoHty:创建历史表实例 {HtyTypeName} å¤±è´¥", htyTypeName);
                    return false;
                }
                if (htyObj == null)
                {
                    // _logger.LogWarning("DeleteAndMoveIntoHty:历史表实例 {HtyTypeName} åˆ›å»ºç»“果为null", htyTypeName);
                    return false;
                }
                // 3. èŽ·å–æ ¸å¿ƒå±žæ€§ï¼ˆæŒ‡å®šBindingFlags确保获取公共实例属性)
                BindingFlags propFlags = BindingFlags.Public | BindingFlags.Instance;
                PropertyInfo? keyPro = typeof(TEntity).GetKeyProperty(); // è‡ªå®šä¹‰æ–¹æ³•需确保返回非空,此处增加判空
                PropertyInfo? operateTypePro = htyType.GetProperty(nameof(IBaseHistoryEntity.OperateType), propFlags);
                PropertyInfo? sourceIdPro = htyType.GetProperty(nameof(IBaseHistoryEntity.SourceId), propFlags);
                // æ ¡éªŒæ ¸å¿ƒå±žæ€§æ˜¯å¦å­˜åœ¨
                if (keyPro == null)
                {
                    //_logger.LogError("DeleteAndMoveIntoHty:实体 {EntityType} æœªæ‰¾åˆ°ä¸»é”®å±žæ€§", entityType.FullName);
                    return false;
                }
                if (operateTypePro == null)
                {
                    //_logger.LogError("DeleteAndMoveIntoHty:历史表 {HtyTypeName} æœªæ‰¾åˆ°OperateType属性", htyTypeName);
                    return false;
                }
                if (sourceIdPro == null)
                {
                    // _logger.LogError("DeleteAndMoveIntoHty:历史表 {HtyTypeName} æœªæ‰¾åˆ°SourceId属性", htyTypeName);
                    return false;
                }
                // 4. èµ‹å€¼æ ¸å¿ƒå±žæ€§ï¼ˆæ ¡éªŒç±»åž‹åŒ¹é…ï¼Œé¿å…SetValue抛异常)
                try
                {
                    // å¤„理OperateType类型匹配:若历史表属性是枚举类型,直接传枚举而非字符串
                    if (operateTypePro.PropertyType == typeof(OperateTypeEnum))
                    {
                        operateTypePro.SetValue(htyObj, operateType);
                    }
                    else if (operateTypePro.PropertyType == typeof(string))
                    {
                        operateTypePro.SetValue(htyObj, operateType.ToString());
                            }                            
                            else
                            {
                                propertyInfo.SetValue(obj, property.GetValue(entity));
                        //_logger.LogError("DeleteAndMoveIntoHty:历史表 {HtyTypeName} çš„OperateType属性类型 {PropType} ä¸åŒ¹é…ï¼ˆä»…支持枚举/字符串)", htyTypeName, operateTypePro.PropertyType.FullName);
                        return false;
                            }
                        }
                    }
                    if (obj != null)
                        _db.InsertableByObject(obj).AS(type.Name + "_Hty").ExecuteCommand();
                }
            }
            return DeleteData(entity);
           
                    // èµ‹å€¼SourceId(校验类型匹配)
                    object sourceIdValue = keyPro.GetValue(entity)!;
                    if (sourceIdPro.PropertyType != sourceIdValue.GetType())
                    {
                        sourceIdValue = Convert.ChangeType(sourceIdValue, sourceIdPro.PropertyType); // ç±»åž‹è½¬æ¢
        }
                    sourceIdPro.SetValue(htyObj, sourceIdValue);
                }
                catch (Exception ex)
                {
                    // _logger.LogError(ex, "DeleteAndMoveIntoHty:历史表 {HtyTypeName} æ ¸å¿ƒå±žæ€§èµ‹å€¼å¤±è´¥", htyTypeName);
                    return false;
                }
                // 5. èµ‹å€¼å…¶ä»–属性(排除核心属性)
                List<PropertyInfo> htyProperties = htyType.GetProperties(propFlags)
                    .Where(x => x.Name != operateTypePro.Name
                             && x.Name != sourceIdPro.Name
                             && x.Name != keyPro.Name)
                    .ToList();
                foreach (PropertyInfo htyProp in htyProperties)
                {
                    PropertyInfo? entityProp = entityType.GetProperty(htyProp.Name, propFlags);
                    if (entityProp == null) continue; // å®žä½“无该属性则跳过
                    try
                    {
                        object propValue;
                        // å¤„理修改人:避免App.User空引用
                        if (htyProp.Name == nameof(BaseEntity.Modifier))
                        {
                            propValue = App.User?.UserId > 0 ? App.User?.UserName : "System";
                        }
                        // å¤„理修改时间
                        else if (htyProp.Name == nameof(BaseEntity.ModifyDate))
                        {
                            propValue = DateTime.Now;
                        }
                        // å…¶ä»–属性从原实体取值
                        else
                        {
                            propValue = entityProp.GetValue(entity) ?? DBNull.Value; // å¤„理null值
                        }
                        // ç±»åž‹è½¬æ¢åŽèµ‹å€¼ï¼ˆé¿å…ç±»åž‹ä¸åŒ¹é…ï¼‰
                        if (propValue != DBNull.Value && propValue != null)
                        {
                            propValue = Convert.ChangeType(propValue, htyProp.PropertyType);
                        }
                        htyProp.SetValue(htyObj, propValue);
                    }
                    catch (Exception ex)
                    {
                        // _logger.LogWarning(ex, "DeleteAndMoveIntoHty:历史表 {HtyTypeName} å±žæ€§ {PropName} èµ‹å€¼å¤±è´¥ï¼Œè·³è¿‡è¯¥å±žæ€§", htyTypeName, htyProp.Name);
                    }
                }
                try
                {
                    // æ‰§è¡Œæ’入历史表
                    int insertRows = _db.InsertableByObject(htyObj).AS(entityType.Name + "_Hty").ExecuteCommand();
                    if (insertRows <= 0)
                    {
                        // _logger.LogError("DeleteAndMoveIntoHty:历史表 {HtyTypeName} æ’入失败(影响行数0)", htyTypeName);
                        _db.InsertableByObject(htyObj).AS(entityType.Name + "_Hty").ExecuteCommand();
                        return false;
                    }
                    // æ’入成功后执行删除
                    bool deleteSuccess = DeleteData(entity);
                    if (!deleteSuccess)
                    {
                        //_logger.LogError("DeleteAndMoveIntoHty:实体 {EntityType} åˆ é™¤å¤±è´¥", entityType.FullName);
                        DeleteData(entity);
                        return false;
                    }
                    // æäº¤äº‹åŠ¡
                    isSuccess = true;
                    //_logger.LogInformation("DeleteAndMoveIntoHty:实体 {EntityType} å·²æˆåŠŸç§»å…¥åŽ†å²è¡¨å¹¶åˆ é™¤åŽŸæ•°æ®", entityType.FullName);
                }
                catch (Exception ex)
                {
                    // _logger.LogError(ex, "DeleteAndMoveIntoHty:事务执行失败(插入历史表/删除原数据)", entityType.FullName);
                    return false;
                }
            }
            catch (Exception ex)
            {
                //  _logger.LogError(ex, "DeleteAndMoveIntoHty:处理实体 {EntityTypeName} æ—¶å‘生未捕获异常", entityTypeName);
                return false;
            }
            return isSuccess;
        }
        public bool DeleteAndMoveIntoHty(List<TEntity> entities, OperateTypeEnum operateType)
        {
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -2093,8 +2093,7 @@
            {
                // 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()))
                    .Where(x => x.StockId == stockId && x.StockQuantity == 0)
                    .ExecuteCommandAsync();
                await _stockInfoService.Db.Deleteable<Dt_StockInfo>()
@@ -2978,6 +2977,8 @@
                    {
                        return content.Error("只有拿到重检结果才能入库!");
                    }
                }
                //  Dt_InboundOrder inboundOrder = GetInboundOrder(materielGroupDTO.OrderNo);
@@ -3046,7 +3047,7 @@
                        FactoryArea = item.FactoryArea,
                        Status = 0,
                        OrderNo = item.OrderNo,
                        BusinessType = InOrderTypeEnum.InternalAllocat.ObjToInt().ToString()
                        BusinessType = materielGroupDTO.orderTypes.ToString()
                    });
                    item.WarehouseCode = item.WarehouseCode;
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Inbound/InboundOrderController.cs
@@ -13,6 +13,8 @@
using WIDESEA_Core;
using WIDESEA_Core.Attributes;
using WIDESEA_Core.BaseController;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.Enums;
using WIDESEA_DTO.Allocate;
using WIDESEA_DTO.Inbound;
using WIDESEA_DTO.Mes;
@@ -42,8 +44,9 @@
        private readonly IMaterialUnitService _materialUnitService;
        private readonly IOutStockLockInfoService _outStockLockInfoService;
        private readonly IOutboundOrderDetailService _outboundOrderDetailService;
        private readonly IRepository<Dt_Task> _taskRepository;
        private readonly ILogger<InboundOrderController> _logger;
        public InboundOrderController(IInboundOrderService service, WIDESEA_IBasicService.IErpApiService erpApiService, WIDESEA_IBasicService.IInvokeMESService invokeMESService, IESSApiService eSSApiService, IDailySequenceService dailySequenceService, ILocationInfoService locationInfoService, ILogger<InboundOrderController> logger, IMaterialUnitService materialUnitService, IInboundService inboundService, IOutStockLockInfoService outStockLockInfoService, IOutboundOrderDetailService outboundOrderDetailService) : base(service)
        public InboundOrderController(IInboundOrderService service, WIDESEA_IBasicService.IErpApiService erpApiService, WIDESEA_IBasicService.IInvokeMESService invokeMESService, IESSApiService eSSApiService, IDailySequenceService dailySequenceService, ILocationInfoService locationInfoService, ILogger<InboundOrderController> logger, IMaterialUnitService materialUnitService, IInboundService inboundService, IOutStockLockInfoService outStockLockInfoService, IOutboundOrderDetailService outboundOrderDetailService, IRepository<Dt_Task> taskRepository) : base(service)
        {
            this.erpApiService = erpApiService;
            _invokeMESService = invokeMESService;
@@ -55,20 +58,21 @@
            _inboundService = inboundService;
            _outStockLockInfoService = outStockLockInfoService;
            _outboundOrderDetailService = outboundOrderDetailService;
            _taskRepository = taskRepository;
        }
        [HttpPost, Route("Test"), AllowAnonymous, MethodParamsValidate]
        public async Task<WebResponseContent> Test()
        {
            var originalTask = _taskRepository.Db.Queryable<Dt_Task>().First();
            _taskRepository.DeleteAndMoveIntoHty(originalTask, OperateTypeEnum.自动完成);
            // Service.Db.Deleteable<Dt_InboundOrder>().Where(x=>x.UpperOrderNo== "12020251100040").ExecuteCommand();
            //_inboundService.InboundOrderDetailService.Db.Deleteable<Dt_InboundOrderDetail>()
            // .Where(p => SqlFunc.Subqueryable<Dt_InboundOrder>().Where(s => s.Id == p.OrderId && s.UpperOrderNo == "12020251100040").Any()).ExecuteCommand();
            var purchaseToStockResult = await _materialUnitService.ConvertPurchaseToStockAsync("100513-00303", 1);
            //var purchaseToStockResult = await _materialUnitService.ConvertPurchaseToStockAsync("100513-00303", 1);
            var pdddurchaseToStockResult = await _materialUnitService.ConvertFromToStockAsync("100513-00303", "W013", 1);
            //var pdddurchaseToStockResult = await _materialUnitService.ConvertFromToStockAsync("100513-00303", "W013", 1);
            //var sddd = _locationInfoService.AssignLocation();
            //var code = sddd.LocationCode;