pan
2025-11-21 29f01b0f46e056212c83513ca59be8c3b70d6b41
提交
已添加1个文件
已修改17个文件
1352 ■■■■ 文件已修改
项目代码/WIDESEA_WMSClient/src/extension/outbound/extend/printView.vue 588 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/views/outbound/PickingConfirm.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_BasicService/InvokeMESService.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_BasicService/MaterielToMesService.cs 53 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/OutboundOrderGetDTO.cs 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_IBasicService/IMaterielToMesService.cs 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutStockLockInfoService.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutboundOrderDetailService.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_IStockService/IStockInfoService.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Model/Models/Basic/Dt_MaterielToMes.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutStockLockInfoService.cs 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs 117 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/SplitPackageService.cs 203 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_StockService/StockInfoService.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_Outbound.cs 199 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/printView.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,588 @@
<template>
  <div>
    <vol-box v-model="showDetialBox" :lazy="true" width="500px" :padding="15" title="">
      <!-- æ‰“印专用容器 -->
      <div id="printContainer" style="position: absolute; left: -9999px;">
        <div class="print-page" v-for="(item, index) in printData" :key="index">
          <div class="material-card">
            <!-- <div class="header">卓力能物料标识卡(小包)</div> -->
            <div class="dual-column preview-card-header-qrcode">
              <div class="preview-card-header">物料卡 {{ idx + 1 }}</div>
              <VueQrcode :value="generateQr(item)" :size="20" id="qrcode" />
            </div>
            <div class="content">
              <!-- äºŒç»´ç æ”¾åœ¨å³ä¸Šè§’ -->
              <!-- <div class="qr-section"> -->
              <!-- <VueQrcode :value="generateQr(item)" id="qrcode" /> -->
              <!-- </div> -->
              <div class="row dual-column">
                <div class="column">
                  <span class="label">料号</span>
                  <span class="value code-value">{{ item.materialCode }}</span>
                </div>
                <div class="column">
                  <span class="label">供应商编码</span>
                  <span class="value">{{ item.supplierCode }}</span>
                </div>
              </div>
              <div class="row dual-column">
                <div class="column">
                  <span class="label">品名</span>
                  <span class="value">{{ item.materialName }}</span>
                </div>
                <div class="column">
                  <span class="label">采购单号</span>
                  <span class="value">{{ item.purchaseOrderNo }}</span>
                </div>
              </div>
              <div class="row dual-column">
                <div class="column">
                  <span class="label">规格</span>
                  <span class="value full-width">{{ item.specification }}</span>
                </div>
                <div class="column">
                  <span class="label">数量/总数</span>
                  <span class="value">{{ item.quantityTotal }}</span>
                </div>
              </div>
              <div class="row dual-column">
                <div class="column">
                  <span class="label">批号</span>
                  <span class="value">{{ item.batchNumber }}</span>
                </div>
                <div class="column">
                  <span class="label">批次</span>
                  <span class="value">{{ item.batch }}</span>
                </div>
              </div>
              <div class="row dual-column">
                <div class="column">
                  <span class="label">厂区</span>
                  <span class="value">{{ item.factory }}</span>
                </div>
                <div class="column">
                  <span class="label">日期</span>
                  <span class="value">{{ item.date }}</span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <!-- é¢„览区域 -->
      <div id="previewContent" class="preview-container">
        <div class="preview-header">卓力能物料标识卡(小包) - é¢„览 (共{{ printData.length }}个)</div>
        <div class="preview-scroll">
          <div v-for="(item, idx) in printData" :key="idx" class="preview-card">
            <div class="dual-column preview-card-header-qrcode">
              <div class="preview-card-header">物料卡 {{ idx + 1 }}</div>
              <VueQrcode :value="generateQr(item)" :size="20" id="qrcode" />
            </div>
            <div class="preview-wrapper">
              <div class="content-preview">
                <div class="row-preview dual-column">
                  <div class="column-preview">
                    <span class="label-preview">料号</span>
                    <span class="value-preview code-value">{{ item.materialCode }}</span>
                  </div>
                  <div class="column-preview">
                    <span class="label-preview">供应商编码</span>
                    <span class="value-preview">{{ item.supplierCode }}</span>
                  </div>
                </div>
                <div class="row-preview dual-column">
                  <div class="column-preview">
                    <span class="label-preview">品名</span>
                    <span class="value-preview">{{ item.materialName }}</span>
                  </div>
                  <div class="column-preview">
                    <span class="label-preview">采购单号</span>
                    <span class="value-preview">{{ item.purchaseOrderNo }}</span>
                  </div>
                </div>
                <div class="row-preview dual-column">
                  <div class="column-preview">
                    <span class="label-preview">规格</span>
                    <span class="value-preview full-width">{{ item.specification }}</span>
                  </div>
                  <div class="column-preview">
                    <span class="label-preview">数量/总数</span>
                    <span class="value-preview">{{ item.quantityTotal }}</span>
                  </div>
                </div>
                <div class="row-preview dual-column">
                  <div class="column-preview">
                    <span class="label-preview">批号</span>
                    <span class="value-preview">{{ item.batchNumber }}</span>
                  </div>
                  <div class="column-preview">
                    <span class="label-preview">批次</span>
                    <span class="value-preview">{{ item.batch }}</span>
                  </div>
                </div>
                <div class="row-preview dual-column">
                  <div class="column-preview">
                    <span class="label-preview">厂区</span>
                    <span class="value-preview">{{ item.factory }}</span>
                  </div>
                  <div class="column-preview">
                    <span class="label-preview">日期</span>
                    <span class="value-preview">{{ item.date }}</span>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <template #footer>
        <div class="footer-actions">
          <span class="print-count">共 {{ printData.length }} ä¸ªç‰©æ–™å¡å¾…打印</span>
          <div>
            <el-button type="primary" size="small" @click="print">打印全部</el-button>
            <el-button type="danger" size="small" @click="showDetialBox = false">关闭</el-button>
          </div>
        </div>
      </template>
    </vol-box>
  </div>
</template>
<script>
import VolBox from "@/components/basic/VolBox.vue";
import VueQrcode from "vue-qrcode";
export default {
  components: { VolBox, VueQrcode },
  data() {
    return {
      showDetialBox: false,
      printData: [], // å­˜å‚¨æ‰“印数据集合
    };
  },
  methods: {
    generateQr(item) {
      return `${item.materialCode}_${item.supplierCode}_${item.purchaseOrderNo}_${item.materialName}_${item.batch}_${item.batchNumber}_${item.factory}_${item.date}`;
    },
    open(rows) {
      this.showDetialBox = true;
      this.printData = Array.isArray(rows) ? rows : [rows];
      console.log('打印数据:', this.printData);
    },
    async print() {
      if (this.printData.length === 0) {
        this.$message.warning('没有可打印的数据');
        return;
      }
      this.$nextTick(() => {
        try {
          const printContent = document.getElementById("printContainer").innerHTML;
          const printWindow = window.open("", "_blank", "width=800,height=600,scrollbars=yes");
          if (!printWindow) {
            this.$message.error('无法打开打印窗口,请检查浏览器弹窗设置');
            return;
          }
          printWindow.document.write(`
            <!DOCTYPE html>
            <html>
            <head>
              <meta charset="UTF-8">
              <title>物料标识卡打印 - å…±${this.printData.length}个</title>
              <style>
                /* é‡ç½®æ‰€æœ‰æ ·å¼ */
                * {
                  margin: 0;
                  padding: 0;
                  box-sizing: border-box;
                }
                body {
                  font-family: SimSun, "宋体", sans-serif;
                  -webkit-print-color-adjust: exact !important;
                  print-color-adjust: exact !important;
                  color-adjust: exact !important;
                }
                #qrcode {
                  width: 60px;
                  height: 60px;
                  display: block;
                  margin: 0, 15px
                }
                @media print {
                  @page {
                    size: 80mm 60mm;
                    margin: 0;
                    padding: 0;
                  }
                  body {
                    margin: 0 !important;
                    padding: 0 !important;
                    width: 80mm !important;
                    background: white !important;
                  }
                  .print-page {
                    width: 80mm !important;
                    height: 60mm !important;
                    page-break-after: always !important;
                    break-after: page !important;
                    margin: 0 !important;
                    padding: 2mm !important;
                    display: block !important;
                  }
                  .print-page:last-child {
                    page-break-after: auto !important;
                  }
                  .material-card {
                    width: 80mm !important;
                    height: 56mm !important;
                    border: 0.3mm solid #000 !important;
                    padding: 1mm !important;
                    box-sizing: border-box !important;
                    position: relative !important;
                    background: white !important;
                  }
                  .header {
                    font-size: 3.5mm !important;
                    font-weight: bold !important;
                    text-align: center !important;
                    margin-bottom: 1mm !important;
                    padding-bottom: 0.5mm !important;
                    border-bottom: 0.2mm solid #000 !important;
                  }
                  .content {
                    height: calc(100% - 6mm) !important;
                    position: relative !important;
                  }
                  .row {
                    display: flex !important;
                    margin-bottom: 0.8mm !important;
                    min-height: 6mm !important;
                  }
                  .dual-column {
                    display: flex !important;
                    justify-content: space-between !important;
                  }
                  .column {
                    flex: 1 !important;
                    display: flex !important;
                    align-items: center !important;
                  }
                  .column:first-child {
                    margin-right: 2mm !important;
                  }
                  .label {
                    font-weight: bold !important;
                    flex: 0 0 15mm !important;
                    white-space: nowrap !important;
                    font-size: 2.2mm !important;
                  }
                  .value {
                    flex: 1 !important;
                    overflow: hidden !important;
                    text-overflow: ellipsis !important;
                    white-space: nowrap !important;
                    border-bottom: 0.1mm dashed #666 !important;
                    padding-bottom: 0.2mm !important;
                    min-height: 2.5mm !important;
                    font-size: 2.2mm !important;
                  }
                  .code-value {
                    font-weight: bold !important;
                  }
                  .full-width {
                    white-space: normal !important;
                    word-break: break-all !important;
                    line-height: 1.2 !important;
                  }
                  /* äºŒç»´ç æ ·å¼ */
                  .qr-section {
                    width: 10mm !important;
                    height: 12mm !important;
                    font-siz:10px;
                  }
                  .qr-section canvas {
                    width: 10mm !important;
                    height: 10mm !important;
                    max-width: 100% !important;
                    max-height: 100% !important;
                  }
                }
                /* å±å¹•预览样式 */
                @media screen {
                  body {
                    background: #f5f5f5;
                    padding: 10px;
                    display: flex;
                    flex-direction: column;
                    align-items: center;
                  }
                  .print-page {
                    width: 80mm;
                    height: 60mm;
                    margin: 10px 0;
                    padding: 2mm;
                    background: white;
                    box-shadow: 0 2px 10px rgba(0,0,0,0.1);
                    border: 1px dashed #ccc;
                  }
                  .material-card {
                    width: 80mm;
                    height: 60mm;
                    border: 0.3mm solid #000;
                    padding: 1.5mm;
                    background: white;
                    position: relative;
                  }
                  .qr-section {
                    position: absolute;
                    top: 4mm;
                    right: 2mm;
                    width: 12mm;
                    height: 12mm;
                    border: 0.2mm solid #ccc;
                    padding: 0.5mm;
                    background: white;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                  }
                  .qr-section canvas {
                    width: 10mm !important;
                    height: 10mm !important;
                  }
                }
              </style>
            </head>
            <body>
              ${printContent}
              <script>
                window.onload = function() {
                  console.log('打印页面加载完成,共${this.printData.length}个物料卡');
                  // ç­‰å¾…二维码渲染完成
                  setTimeout(() => {
                    // å¼ºåˆ¶è®¾ç½®äºŒç»´ç canvas尺寸
                    const canvases = document.querySelectorAll('canvas');
                    canvases.forEach(canvas => {
                      canvas.style.width = '10mm !important';
                      canvas.style.height = '10mm !important';
                    });
                    window.print();
                  }, 800);
                };
                window.onafterprint = function() {
                  setTimeout(() => {
                    window.close();
                  }, 500);
                };
              <\/script>
            </body>
            </html>
          `);
          printWindow.document.close();
        } catch (error) {
          console.error('打印错误:', error);
          this.$message.error('打印失败: ' + error.message);
        }
      });
    }
  }
};
</script>
<style scoped>
#qrcode {
  width: 60px;
  height: 60px;
  display: block;
  margin: 0, 15px
}
.preview-container {
  max-height: 500px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.preview-header {
  text-align: center;
  font-size: 16px;
  font-weight: bold;
  margin-bottom: 10px;
  padding: 8px;
  background: #f0f0f0;
  border-radius: 4px;
}
.preview-scroll {
  max-height: 400px;
  overflow-y: auto;
  padding: 10px;
  border: 1px solid #e0e0e0;
  border-radius: 4px;
  background: #f9f9f9;
}
.preview-card {
  width: 320px;
  height: 240px;
  margin: 0 auto 15px auto;
  padding: 8px;
  border: 1px solid #ccc;
  font-family: SimSun;
  box-sizing: border-box;
  border: 2px solid #000;
  background: white;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
  position: relative;
}
.preview-card:last-child {
  margin-bottom: 0;
}
.preview-card-header {
  text-align: center;
  font-size: 14px;
  /* font-weight: bold;
  margin-bottom: 8px;
  padding-bottom: 4px;
  border-bottom: 1px solid #000;
  background: #f5f5f5;
  padding: 4px; */
  height: 60px;
  width: 60px;
}
.preview-wrapper {
  position: relative;
  height: calc(100% - 40px);
}
.content-preview {
  width: 100%;
  height: 100%;
}
.row-preview {
  /* margin-bottom: px; */
  min-height: 32px;
}
.dual-column {
  display: flex;
  justify-content: space-between;
}
.column-preview {
  flex: 1;
  display: flex;
  align-items: center;
}
.column-preview:first-child {
  margin-right: 10px;
}
.label-preview {
  font-weight: bold;
  flex: 0 0 60px;
  white-space: nowrap;
  font-size: 12px;
}
.value-preview {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12px;
  border-bottom: 1px dashed #666;
  padding-bottom: 2px;
}
.code-value {
  font-weight: bold;
}
.full-width {
  display: block;
  margin-top: 2px;
  white-space: normal;
  word-break: break-all;
  line-height: 1.2;
  font-size: 12px;
}
/* é¢„览区域二维码样式 */
.qr-section-preview {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 150px;
  height: 175px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid #ddd;
  background: white;
  padding: 2px;
}
.qr-section-preview canvas {
  width: 56px !important;
  height: 56px !important;
}
.footer-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
}
.print-count {
  font-size: 14px;
  color: #409EFF;
  font-weight: bold;
}
</style>
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/outbound/PickingConfirm.vue
@@ -291,6 +291,7 @@
      </div>
    </div>
  </div>
  <print-view ref="childs" @parentcall="parentcall"></print-view>
</template>
<script>
@@ -298,12 +299,11 @@
import { ref, defineComponent } from "vue";
import { ElMessage } from 'element-plus' 
import { useRoute } from 'vue-router'
import printView from "@/extension/outbound/extend/printView.vue"
export default defineComponent({
  name: 'PickingConfirm',
  components: {
  },
  components: {printView},
  props: {
    orderNo: {
      type: String,
@@ -844,7 +844,12 @@
          this.$message.success('拣选确认成功');
          this.scanData.barcode = ''; // æ¸…空物料条码
          this.loadData();
          console.log(res.data.splitResults)
          if(res.data && res.data.splitResults.length>0){
            // è°ƒç”¨å­ç»„件打印方法
            this.$refs.childs.open(res.data.splitResults);
            //this.$refs.childs.printSplitLabel(res.data.splitResults);
          }
          // æˆåŠŸåŽç»§ç»­èšç„¦åˆ°ç‰©æ–™æ¡ç è¾“å…¥æ¡†ï¼Œå‡†å¤‡ä¸‹ä¸€ä¸ªæ‰«ç 
          this.$nextTick(() => {
            this.$refs.barcodeInput.focus();
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_BasicService/InvokeMESService.cs
@@ -116,10 +116,11 @@
            var content = new StringContent(json, Encoding.UTF8, "application/json");
            _logger.LogInformation("InvokeMESService  FeedbackInbound :  " + json);
            _logger.LogInformation("InvokeMESService  NewMaterielToMes :  " + json);
            using var response = await client.PostAsync("AldBarcodeInformation/BarcodeInformation", content);
            var responseText = await response.Content.ReadAsStringAsync();
            _logger.LogInformation("InvokeMESService  NewMaterielToMes  body:  " + responseText);
            if (!response.IsSuccessStatusCode)
            {
                throw new HttpRequestException(responseText);
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_BasicService/MaterielToMesService.cs
@@ -1,4 +1,6 @@
using Newtonsoft.Json;
using Dm.filter;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
@@ -9,6 +11,7 @@
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
using WIDESEA_Core.Helper;
using WIDESEA_DTO.Basic;
using WIDESEA_DTO.Outbound;
using WIDESEA_IBasicService;
using WIDESEA_Model.Models;
@@ -19,10 +22,11 @@
    internal class MaterielToMesService : ServiceBase<Dt_MaterielToMes, IRepository<Dt_MaterielToMes>>, IMaterielToMesService
    {
        private readonly IInvokeMESService _invokeMESService;
        public MaterielToMesService(IRepository<Dt_MaterielToMes> BaseDal, IInvokeMESService invokeMESService) : base(BaseDal)
        private readonly ILogger<MaterielToMesService> _logger;
        public MaterielToMesService(IRepository<Dt_MaterielToMes> BaseDal, IInvokeMESService invokeMESService, ILogger<MaterielToMesService> logger) : base(BaseDal)
        {
            _invokeMESService = invokeMESService;
            _logger = logger;
        }
        // åˆ›å»ºä¸€ä¸ªä½¿ç”¨å°é©¼å³°å‘½åæ³•的序列化设置
        JsonSerializerSettings settings = new JsonSerializerSettings
@@ -31,29 +35,50 @@
        };
        public IRepository<Dt_MaterielToMes> Repository => BaseDal;
        public override WebResponseContent AddData(Dt_MaterielToMes saveModel)
        public async Task<WebResponseContent> AddMaterielToMes(Dt_MaterielToMes saveModel,int operationtype)
        {
            WebResponseContent content = base.AddData(saveModel);
            if (content.Status)
            try
            {
                base.AddData(saveModel);
                string request = JsonConvert.SerializeObject(saveModel, settings);
                MaterielToMesDTO dto = new MaterielToMesDTO
                {
                    batchNo = saveModel.BatchNo,
                    factoryArea = saveModel.factoryArea,
                    materialCode = saveModel.MaterielCode,
                    newmaterialCode = saveModel.NewMaterialBarCode,
                    oldmaterialCode = saveModel.OldMaterialBarCode,
                    operationType = 1,
                    qty = saveModel.Qty,
                    supplyCode = saveModel.supplyCode,
                    unit = saveModel.Unit,
                    warehouseCode = saveModel.warehouseCode,
                    reqCode = Guid.NewGuid().ToString(),
                    reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
                };
                var result = await _invokeMESService.NewMaterielToMes(dto);
                if (result != null && result.code == 200)
                {
                    await Db.Updateable<Dt_MaterielToMes>()
                      .SetColumns(it => it.ReturnToMESStatus ==1)
                      .Where(it => it.Id == saveModel.Id)
                      .ExecuteCommandAsync();
                }
                return WebResponseContent.Instance.OK();
            }
            else
            catch (Exception ex)
            {
                return content;
                _logger.LogError("MaterielToMesService  add Dt_MaterielToMes:  " + ex.Message);
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/OutboundOrderGetDTO.cs
@@ -52,7 +52,7 @@
    public class SummaryPickingDto
    {
       public string PalletCode { get; set; }
        public string PalletCode { get; set; }
        public string MaterielCode { get; set; }
        public int UnpickedCount { get; set; }
        public decimal UnpickedQuantity { get; set; }
@@ -180,7 +180,7 @@
        public string OrderNo { get; set; } = string.Empty; // å‡ºåº“单号
    }
    public class PickingConfirmReq
    {
@@ -189,7 +189,7 @@
        public string MaterielBarcode { get; set; } = string.Empty; // ç‰©æ–™æ¡ç 
    }
    public class SplitPackageReq
    {
@@ -198,7 +198,7 @@
        public decimal SplitQty { get; set; } // æ–°æ¡ç åˆ†é…æ•°é‡
    }
    public class StockReturnReq
    {
@@ -206,14 +206,14 @@
        public string TaskNum { get; set; } = string.Empty; // ä»»åŠ¡å·ï¼ˆå¯é€‰ï¼‰
    }
    public class OutStockLockDetailReq
    {
        public long OutStockLockId { get; set; } // å‡ºåº“详情ID
    }
    public class MaterielBarcodeValidateResp
    {
@@ -222,7 +222,7 @@
        public decimal PackageQty { get; set; } // æ•´åŒ…数量(分配数量)
        public string Message { get; set; } = string.Empty;
    }
    public class OutStockLockDetailResp
    {
@@ -230,7 +230,7 @@
        public decimal AssignQuantity { get; set; }
    }
    public class OutStockLockListResp
    {
@@ -244,7 +244,7 @@
        public bool IsSplitted { get; set; }
    }
    public class PickedRecordListResp
    {
@@ -278,9 +278,21 @@
    // æ‹†åŒ…结果类
    public class SplitResult
    {
        public string OriginalBarcode { get; set; }
        public string NewBarcode { get; set; }
        public decimal SplitQuantity { get; set; }
        public decimal RemainQuantity { get; set; }
        public string materialCode { get; set; }
        public string supplierCode { get; set; }
        public string quantityTotal { get; set; }
        public string batchNumber { get; set; }
        public string  batch { get; set; }
        public string factory { get; set; }
        public string date { get; set; }
       // public string OriginalBarcode { get; set; }
       // public string NewBarcode { get; set; }
        //public decimal SplitQuantity { get; set; }
        //public decimal RemainQuantity { get; set; }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IBasicService/IMaterielToMesService.cs
@@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
using WIDESEA_Model.Models;
@@ -13,5 +14,7 @@
    public interface IMaterielToMesService : IService<Dt_MaterielToMes>
    {
        IRepository<Dt_MaterielToMes> Repository { get; }
        Task<WebResponseContent> AddMaterielToMes(Dt_MaterielToMes saveModel, int operationtype);
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutStockLockInfoService.cs
@@ -27,6 +27,8 @@
        Task<LockInfoDetailDto> GetLockInfoDetail(int lockInfoId);
        Dt_OutStockLockInfo GetOutStockLockInfo(Dt_OutboundOrder outboundOrder,Dt_OutboundOrderDetail outboundOrderDetail,Dt_StockInfo outStock, decimal assignQuantity, string barcode = null);
        List<Dt_OutStockLockInfo> GetOutStockLockInfos(Dt_OutboundOrder outboundOrder, Dt_OutboundOrderDetail outboundOrderDetail, List<Dt_StockInfo> outStocks, int? taskNum = null);
        Task<List<Dt_OutStockLockInfo>> GetPalletLockInfos(string palletCode);
        Task<WebResponseContent> UpdateLockInfoBarcode(int lockInfoId, string newBarcode);
    }
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutboundOrderDetailService.cs
@@ -21,7 +21,7 @@
        public (List<Dt_StockInfo>, List<Dt_OutboundOrderDetail>, List<Dt_OutStockLockInfo>, List<Dt_LocationInfo>) AssignStockOutbound(List<Dt_OutboundOrderDetail> outboundOrderDetails);
        WebResponseContent LockOutboundStockDataUpdate(List<Dt_StockInfo> stockInfos, List<Dt_OutboundOrderDetail> outboundOrderDetails, List<Dt_OutStockLockInfo> outStockLockInfos, List<Dt_LocationInfo> locationInfos, LocationStatusEnum locationStatus = LocationStatusEnum.Lock, List<Dt_Task>? tasks = null);
        (List<Dt_StockInfo>, Dt_OutboundOrderDetail, List<Dt_OutStockLockInfo>, List<Dt_LocationInfo>) AssignStockOutbound(Dt_OutboundOrderDetail outboundOrderDetail, List<StockSelectViewDTO> stockSelectViews);
        //List<Dt_OutboundOrderDetail> GetOutboundStockDataById(int id);
    }
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IStockService/IStockInfoService.cs
@@ -9,7 +9,7 @@
    {
        IRepository<Dt_StockInfo> Repository { get; }
        Dt_StockInfo? GetStockByPalletCode(string palletCode);
        List<Dt_StockInfo> GetStockInfosByPalletCodes(List<string> palletCodes);
        List<Dt_StockInfo> GetStockInfos(string materielCode, string lotNo, string supplyCode, List<string> locationCodes);
        List<Dt_StockInfo> GetUseableStocks(string materielCode, string batchNo,string supplyCode);
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs
@@ -45,6 +45,9 @@
        Task<WebResponseContent> TaskCompleted(string taskNum);
        Task<WebResponseContent> GenerateOutboundTasksAsync(int[] keys, string outStation);
        WebResponseContent GenerateOutboundTask(int orderDetailId, List<StockSelectViewDTO> stockSelectViews);
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Basic/Dt_MaterielToMes.cs
@@ -87,7 +87,7 @@
        public string MaterielCode { get; set; } = null!;
         
        public int ReturnToMESStatus { get; set; }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutStockLockInfoService.cs
@@ -111,6 +111,38 @@
                IsSplitted = 0
            };
        }
        public List<Dt_OutStockLockInfo> GetOutStockLockInfos(Dt_OutboundOrder outboundOrder, Dt_OutboundOrderDetail outboundOrderDetail, List<Dt_StockInfo> outStocks, int? taskNum = null)
        {
            List<Dt_OutStockLockInfo> outStockLockInfos = new List<Dt_OutStockLockInfo>();
            foreach (var item in outStocks)
            {
                Dt_OutStockLockInfo outStockLockInfo = new Dt_OutStockLockInfo()
                {
                    PalletCode = item.PalletCode,
                    AssignQuantity = item.Details.Where(x => x.MaterielCode == outboundOrderDetail.MaterielCode).Sum(x => x.OutboundQuantity),
                    MaterielCode = outboundOrderDetail.MaterielCode,
                    BatchNo = outboundOrderDetail.BatchNo,
                    LocationCode = item.LocationCode,
                    MaterielName = outboundOrderDetail.MaterielName,
                    OrderDetailId = outboundOrderDetail.Id,
                    OrderNo = outboundOrder.OrderNo,
                    OrderType = outboundOrder.OrderType,
                    OriginalQuantity = item.Details.Where(x => x.MaterielCode == outboundOrderDetail.MaterielCode).Sum(x => x.StockQuantity),
                    Status = taskNum == null ? OutLockStockStatusEnum.已分配.ObjToInt() : OutLockStockStatusEnum.出库中.ObjToInt(),
                    StockId = item.Id,
                    TaskNum = taskNum,
                };
                outStockLockInfos.Add(outStockLockInfo);
            }
            return outStockLockInfos;
        }
        /// <summary>
        /// æ ¹æ®è®¢å•明细ID获取出库锁定信息
        /// </summary>
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs
@@ -1,6 +1,7 @@
using Microsoft.Extensions.Logging;
using SqlSugar;
using WIDESEA_Common.LocationEnum;
using WIDESEA_Common.OrderEnum;
using WIDESEA_Common.StockEnum;
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
@@ -22,6 +23,7 @@
   
        private readonly IStockService _stockService;
        private readonly IOutStockLockInfoService _outStockLockInfoService;
        private readonly ILocationInfoService _locationInfoService;
        private readonly IBasicService _basicService;
@@ -40,6 +42,7 @@
            _locationStatusChangeRecordService = locationStatusChangeRecordService;
            _outboundOrderService = outboundOrderService;
            _logger = logger;
        }
@@ -153,7 +156,7 @@
                    if (remainingAllocate <= 0) break;
                    // è®¡ç®—这个明细还需要分配的数量
                    var detailNeed = detail.OrderQuantity - detail.OverOutQuantity - detail.LockQuantity;
                    var detailNeed = detail.OrderQuantity - detail.OverOutQuantity - detail.LockQuantity-detail.MoveQty;
                    if (detailNeed <= 0) continue;
                    // åˆ†é…æ•°é‡
@@ -289,5 +292,72 @@
            return new PageGridData<Dt_OutboundOrderDetail> ();
        }
        public (List<Dt_StockInfo>, Dt_OutboundOrderDetail, List<Dt_OutStockLockInfo>, List<Dt_LocationInfo>) AssignStockOutbound(Dt_OutboundOrderDetail outboundOrderDetail, List<StockSelectViewDTO> stockSelectViews)
        {
            (bool, string) checkResult = CheckSelectStockDeital(outboundOrderDetail, stockSelectViews);
            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 needQuantity = originalNeedQuantity;
            List<Dt_StockInfo> outStocks = _stockService.StockInfoService.GetStockInfosByPalletCodes(stockSelectViews.Select(x => x.PalletCode).ToList());
            var assignQuantity =0m;
            outStocks.ForEach(x =>
            {
                x.Details.ForEach(v =>
                {
                    assignQuantity += v.StockQuantity - v.OutboundQuantity;
                });
            });
            outboundOrderDetail.LockQuantity += assignQuantity;
            outStocks.ForEach(x =>
            {
                x.Details.ForEach(v =>
                {
                    v.OutboundQuantity = v.StockQuantity;
                });
            });
            needQuantity -= assignQuantity;
            if (outboundOrderDetail.OrderQuantity > outboundOrderDetail.LockQuantity)
            {
                List<Dt_StockInfo> stockInfos = _stockService.StockInfoService.GetUseableStocks(outboundOrderDetail.MaterielCode, outboundOrderDetail.BatchNo,"");
                stockInfos = stockInfos.Where(x => !stockSelectViews.Select(v => v.PalletCode).Contains(x.PalletCode)).ToList();
                var (autoAssignStocks, stockAllocations)   = _stockService.StockInfoService.GetOutboundStocks(stockInfos, outboundOrderDetail.MaterielCode, needQuantity, out decimal residueQuantity);
                outboundOrderDetail.LockQuantity += needQuantity - residueQuantity;
                outStocks.AddRange(autoAssignStocks);
                outboundOrderDetail.OrderDetailStatus = OrderDetailStatusEnum.AssignOver.ObjToInt();
                if (residueQuantity > 0)
                {
                    outboundOrderDetail.OrderDetailStatus = OrderDetailStatusEnum.AssignOverPartial.ObjToInt();
                }
            }
            List<Dt_OutStockLockInfo> outStockLockInfos = _outStockLockInfoService.GetOutStockLockInfos(outboundOrder, outboundOrderDetail, outStocks);
            List<Dt_LocationInfo> locationInfos = _locationInfoService.GetLocationInfos(outStocks.Select(x => x.LocationCode).ToList());
            return (outStocks, outboundOrderDetail, outStockLockInfos, locationInfos);
        }
        private (bool, string) CheckSelectStockDeital(Dt_OutboundOrderDetail outboundOrderDetail, List<StockSelectViewDTO> stockSelectViews)
        {
            if (outboundOrderDetail == null)
            {
                return (false, "未找到出库单明细信息");
            }
            if (outboundOrderDetail.OrderDetailStatus != OrderDetailStatusEnum.New.ObjToInt() && outboundOrderDetail.OrderDetailStatus != OrderDetailStatusEnum.AssignOverPartial.ObjToInt())
            {
                return (false, "该明细不可操作");
            }
            if (stockSelectViews.Sum(x => x.UseableQuantity) > outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity)
            {
                return (false, "选择数量超出单据数量");
            }
            return (true, "成功");
        }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -1,6 +1,7 @@
using Dm.filter;
using MailKit.Search;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SqlSugar;
using System;
@@ -230,8 +231,16 @@
                               }).ToList();
                            feedmodel.details = groupedData;
                            _invokeMESService.FeedbackOutbound(feedmodel);
                            var result = await _invokeMESService.FeedbackOutbound(feedmodel);
                            if (result != null && result.code == 200)
                            {
                                await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>().SetColumns(x => x.ReturnToMESStatus == 1) // å·²å®Œæˆ
                                            .Where(x => x.OrderId == outboundOrder.Id).ExecuteCommandAsync();
                                await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() .SetColumns(x => x.ReturnToMESStatus == 1) // å·²å®Œæˆ
                                              .Where(x => x.OrderNo == orderNo) .ExecuteCommandAsync();
                            }
                        }
                    }
                }
                catch (Exception ex)
@@ -244,6 +253,32 @@
        public async Task<WebResponseContent> ConfirmPicking(string orderNo, string palletCode, string barcode)
        {
            #region "测试打印"
            // var splitResults=new List<SplitResult>();
            //  splitResults.Add(new SplitResult
            //{
            //    materialCode = "AAAAbbb",
            //    supplierCode = "CVBG",
            //    quantityTotal = "1234",
            //    batchNumber = "WMLOT25111900032",
            //    batch = "A234re",
            //    factory = "01",
            //    date = DateTime.Now.ToString("yyyy-MM-dd"),
            //});
            //splitResults.Add(new SplitResult
            //{
            //    materialCode = "CCDF",
            //    supplierCode = "QWCVBG",
            //    quantityTotal = "1234",
            //    batchNumber = "WMLOT25111900032",
            //    batch = "A234re",
            //    factory = "01",
            //    date = DateTime.Now.ToString("yyyy-MM-dd"),
            //});
            // return WebResponseContent.Instance.OK("拣选确认成功,已自动拆包", new { SplitResults = splitResults });
            #endregion
            try
            {
                _unitOfWorkManage.BeginTran();
@@ -287,6 +322,9 @@
                decimal stockQuantity = stockDetail.StockQuantity;
                List<SplitResult> splitResults = new List<SplitResult>();
                Dt_OutStockLockInfo finalLockInfo = lockInfo;
                var finalBarcode = barcode;
                var finalStockId = stockDetail.Id;
                if (actualQty < stockQuantity)
                {
@@ -328,7 +366,9 @@
                        IsSplitted = 1,
                        ParentLockId = lockInfo.Id
                    };
                    await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync();
                    // æ’入新锁定信息并获取ID
                    var newLockId = await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteReturnIdentityAsync();
                    newLockInfo.Id = newLockId; // ç¡®ä¿ID被正确设置
                    // è®°å½•拆包历史(用于追踪)
                    var splitHistory = new Dt_SplitPackageRecord
@@ -353,21 +393,37 @@
                    // æ›´æ–°åŽŸé”å®šä¿¡æ¯ä¸ºå‰©ä½™åº“å­˜æ•°é‡
                    lockInfo.AssignQuantity = remainingStockQty;
                    lockInfo.PickedQty = 0;
                    lockInfo.PickedQty = 0;
                    await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
                    splitResults.Add(new SplitResult
                    {
                        OriginalBarcode = barcode,
                        NewBarcode = newBarcode,
                        SplitQuantity = actualQty,
                        RemainQuantity = remainingStockQty
                    });
                        materialCode = lockInfo.MaterielCode,
                        supplierCode = lockInfo.SupplyCode,
                        quantityTotal = actualQty.ToString("F2"),
                        batchNumber = newBarcode,
                        batch = lockInfo.BatchNo,
                        factory = lockInfo.FactoryArea,
                        date = DateTime.Now.ToString("yyyy-MM-dd"),
                    });
                    splitResults.Add(new SplitResult
                    {
                        materialCode = lockInfo.MaterielCode,
                        supplierCode = lockInfo.SupplyCode,
                        quantityTotal = remainingStockQty.ToString("F2"),
                        batchNumber = barcode,
                        batch = lockInfo.BatchNo,
                        factory = lockInfo.FactoryArea,
                        date = DateTime.Now.ToString("yyyy-MM-dd"),
                    });
                    // æ›´æ–°æ‹£é€‰è®°å½•中的条码为新条码
                    barcode = newBarcode;
                    lockInfo = newLockInfo;
                    finalLockInfo = newLockInfo;
                    finalBarcode = newBarcode;
                    finalStockId = stockDetail.Id; // ä½¿ç”¨åŽŸåº“å­˜ID
                }
                else if (actualQty == stockQuantity)
                {
@@ -379,6 +435,9 @@
                    lockInfo.PickedQty += actualQty;
                    lockInfo.Status = (int)OutLockStockStatusEnum.拣选完成;
                    await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
                    finalLockInfo = lockInfo;
                    finalBarcode = barcode;
                    finalStockId = stockDetail.Id;
                }
                else
                {
@@ -399,18 +458,21 @@
                    await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
                    var _relatedSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
        .Where(it => it.OriginalBarcode == barcode || it.NewBarcode == barcode)
        .Where(it => !it.IsReverted)
        .ToListAsync();
                                                .Where(it => it.OriginalBarcode == barcode || it.NewBarcode == barcode)
                                                .Where(it => !it.IsReverted)
                                                .ToListAsync();
                    foreach (var record in _relatedSplitRecords)
                    {
                        record.Status = (int)SplitPackageStatusEnum.已拣选;
                        await _splitPackageService.Db.Updateable(record).ExecuteCommandAsync();
                    }
                    finalLockInfo = lockInfo;
                    finalBarcode = barcode;
                    finalStockId = stockDetail.Id;
                }
                await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                    .SetColumns(it => it.PickedQty == it.PickedQty + actualQty)
@@ -421,23 +483,26 @@
                // æŸ¥è¯¢ä»»åŠ¡è¡¨ 
                var task = _taskRepository.QueryData(x => x.OrderNo == orderNo && x.PalletCode == palletCode).FirstOrDefault();
                if (finalLockInfo.Id <= 0)
                {
                    throw new Exception($"锁定信息ID无效: {finalLockInfo.Id},无法记录拣选历史");
                }
                // è®°å½•拣选历史
                var pickingHistory = new Dt_PickingRecord
                {
                    FactoryArea = lockInfo.FactoryArea,
                    FactoryArea = finalLockInfo.FactoryArea,
                    TaskNo = task?.TaskNum ?? 0,
                    LocationCode = task?.SourceAddress ?? "",
                    StockId = stockDetail.Id,
                    StockId = finalStockId,
                    OrderNo = orderNo,
                    OrderDetailId = lockInfo.OrderDetailId,
                    OrderDetailId = finalLockInfo.OrderDetailId,
                    PalletCode = palletCode,
                    Barcode = barcode,
                    MaterielCode = lockInfo.MaterielCode,
                    Barcode = finalBarcode,
                    MaterielCode = finalLockInfo.MaterielCode,
                    PickQuantity = actualQty,
                    PickTime = DateTime.Now,
                    Operator = App.User.UserName,
                    OutStockLockId = lockInfo.Id
                    OutStockLockId = finalLockInfo.Id
                };
                await Db.Insertable(pickingHistory).ExecuteCommandAsync();
@@ -449,7 +514,7 @@
                    return WebResponseContent.Instance.OK("拣选确认成功,已自动拆包", new { SplitResults = splitResults });
                }
                return WebResponseContent.Instance.OK("拣选确认成功");
                return WebResponseContent.Instance.OK("拣选确认成功", new { SplitResults = splitResults });
            }
            catch (Exception ex)
@@ -458,7 +523,7 @@
                return WebResponseContent.Instance.Error($"拣选确认失败:{ex.Message}");
            }
        }
        /// <summary>
        /// å›žåº“操作  
        /// </summary>
@@ -566,7 +631,7 @@
                            .Where(it => lockIds.Contains(it.Id))
                            .ExecuteCommandAsync();
                        // å¤„理库存记录
                        foreach (var lockInfo in palletLocks)
@@ -664,9 +729,9 @@
                        CreateReturnTask(tasks, task, palletCode, newLocation);
                    }
                }
                var allSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
                    .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && !it.IsReverted)
                    .ToListAsync();
@@ -1082,7 +1147,7 @@
        private async Task RecordCancelHistory(string orderNo, string palletCode, string barcode,
            decimal cancelQty, int pickingRecordId, string materielCode, string reason)
        {
            //var cancelHistory = new Dt_PickingCancelRecord
            //{
            //    OrderNo = orderNo,
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/SplitPackageService.cs
@@ -17,6 +17,7 @@
using WIDESEA_IOutboundService;
using WIDESEA_IStockService;
using WIDESEA_Model.Models;
using WIDESEA_Model.Models.Basic;
namespace WIDESEA_OutboundService
{
@@ -30,9 +31,9 @@
        private readonly IOutStockLockInfoService _outStockLockInfoService;
        private readonly IDailySequenceService _dailySequenceService;
        private readonly IInvokeMESService _invokeMESService;
        private readonly IMaterielToMesService _materielToMesService;
        private readonly ILogger<SplitPackageService> _logger;
        public SplitPackageService(IRepository<Dt_SplitPackageRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, IOutStockLockInfoService outStockLockInfoService, IStockInfoDetailService stockInfoDetailService, IDailySequenceService dailySequenceService, IInvokeMESService invokeMESService, ILogger<SplitPackageService> logger) : base(BaseDal)
        public SplitPackageService(IRepository<Dt_SplitPackageRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, IOutStockLockInfoService outStockLockInfoService, IStockInfoDetailService stockInfoDetailService, IDailySequenceService dailySequenceService, IInvokeMESService invokeMESService, ILogger<SplitPackageService> logger, IMaterielToMesService materielToMesService) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _stockInfoService = stockInfoService;
@@ -41,172 +42,8 @@
            _dailySequenceService = dailySequenceService;
            _invokeMESService = invokeMESService;
            _logger = logger;
            _materielToMesService = materielToMesService;
        }
        /// <summary>
        /// æ‹†åŒ…拆箱操作
        /// </summary>
        //public async Task<WebResponseContent> SplitPackage(SplitPackageDto request)
        //{
        //    try
        //    {
        //        _unitOfWorkManage.BeginTran();
        //        // 1. éªŒè¯å‡ºåº“锁定信息
        //        var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
        //                  .Where(x => x.OrderNo == request.OrderNo &&
        //                   x.PalletCode == request.PalletCode &&
        //                   x.CurrentBarcode == request.OriginalBarcode &&
        //                   x.Status == 1)
        //            .FirstAsync();
        //        if (lockInfo == null)
        //            return WebResponseContent.Instance.Error("未找到有效的出库锁定信息");
        //        // 2. æ£€æŸ¥å‰©ä½™é”å®šæ•°é‡
        //        decimal remainingLockQuantity = lockInfo.OriginalQuantity - lockInfo.PickedQty;
        //        if (request.SplitQuantity > remainingLockQuantity)
        //            return WebResponseContent.Instance.Error($"拆包数量不能大于剩余锁定数量,剩余:{remainingLockQuantity}");
        //        var baseStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
        //       .Where(x => x.Barcode == request.OriginalBarcode && x.StockId == lockInfo.StockId)
        //       .FirstAsync();
        //        if (baseStockDetail == null)
        //            throw new Exception($"未找到条码{request.OriginalBarcode}对应的库存记录");
        //        // 4. è®¡ç®—拆分后的数量
        //        decimal remainingQty = baseStockDetail.StockQuantity - request.SplitQuantity;
        //        // æ›´æ–°åŸºç¡€æ¡ç çš„库存数量为剩余数量
        //        baseStockDetail.StockQuantity = remainingQty;
        //        baseStockDetail.OutboundQuantity = remainingQty;
        //        await _stockInfoDetailService.Db.Updateable(baseStockDetail).ExecuteCommandAsync();
        //        var seq = await _dailySequenceService.GetNextSequenceAsync();
        //        // 3. ç”Ÿæˆæ–°æ¡ç 
        //        string newBarcode = "WSLOT" + DateTime.Now.ToString("yyyyMMdd") + seq.ToString()?.PadLeft(5, '0');
        //        // ä¸ºæ‹†åŒ…产生的新条码创建库存记录
        //        var newStockDetail = new Dt_StockInfoDetail
        //        {
        //            SupplyCode = baseStockDetail.SupplyCode,
        //            WarehouseCode = baseStockDetail.WarehouseCode,
        //            BarcodeQty = baseStockDetail.BarcodeQty,
        //            BarcodeUnit = baseStockDetail.BarcodeUnit,
        //            BusinessType = baseStockDetail.BusinessType,
        //            Unit = baseStockDetail.Unit,
        //            StockId = lockInfo.StockId,
        //            MaterielCode = baseStockDetail.MaterielCode,
        //            OrderNo = baseStockDetail.OrderNo,
        //            BatchNo = baseStockDetail.BatchNo,
        //            StockQuantity = request.SplitQuantity, // æ–°æ¡ç èŽ·å¾—æ‹†åˆ†æ•°é‡
        //            OutboundQuantity = request.SplitQuantity,
        //            Barcode = newBarcode,
        //            InboundOrderRowNo = baseStockDetail.InboundOrderRowNo,
        //        };
        //        await _outStockLockInfoService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
        //        // 4. åˆ›å»ºæ–°çš„出库锁定信息(新条码)
        //        var newLockInfo = new Dt_OutStockLockInfo
        //        {
        //            OrderNo = lockInfo.OrderNo,
        //            OrderDetailId = lockInfo.OrderDetailId,
        //            BatchNo = lockInfo.BatchNo,
        //            MaterielCode = lockInfo.MaterielCode,
        //            MaterielName = lockInfo.MaterielName,
        //            StockId = lockInfo.StockId,
        //            OrderQuantity = request.SplitQuantity,
        //            OriginalQuantity = request.SplitQuantity,
        //            AssignQuantity = request.SplitQuantity, // æ–°æ¡ç åˆ†é…æ•°é‡
        //            PickedQty = 0, // æ–°æ¡ç æœªæ‹£é€‰
        //            LocationCode = lockInfo.LocationCode,
        //            PalletCode = lockInfo.PalletCode,
        //            TaskNum = lockInfo.TaskNum,
        //            Status = (int)OutLockStockStatusEnum.出库中,
        //            Unit = lockInfo.Unit,
        //            SupplyCode = lockInfo.SupplyCode,
        //            OrderType = lockInfo.OrderType,
        //            CurrentBarcode = newBarcode, // æ–°æ¡ç 
        //            OriginalLockQuantity = request.SplitQuantity,
        //            IsSplitted = 1,
        //            ParentLockId = lockInfo.Id // è®°å½•父级锁定ID
        //        };
        //        await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync();
        //        lockInfo.AssignQuantity = remainingQty;
        //        lockInfo.IsSplitted = 1; // æ ‡è®°ä¸ºå·²æ‹†åŒ…
        //        await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
        //        var previousSplitRecord = await Db.Queryable<Dt_SplitPackageRecord>()
        //      .Where(x => x.OriginalBarcode == request.OriginalBarcode && !x.IsReverted)
        //      .OrderByDescending(x => x.SplitTime)
        //      .FirstAsync();
        //        // 6. è®°å½•拆包历史(用于追踪)
        //        var splitHistory = new Dt_SplitPackageRecord
        //        {
        //            FactoryArea = lockInfo.FactoryArea,
        //            TaskNum = lockInfo.TaskNum,
        //            OutStockLockInfoId = lockInfo.Id,
        //            StockId = baseStockDetail.StockId,
        //            Operator = App.User.UserName,
        //            IsReverted = false,
        //            OriginalBarcode = request.OriginalBarcode,
        //            NewBarcode = newBarcode,
        //            SplitQty = request.SplitQuantity,
        //            RemainQuantity = remainingQty, // è®°å½•拆分后的剩余数量
        //            MaterielCode = lockInfo.MaterielCode,
        //            SplitTime = DateTime.Now,
        //            OrderNo = request.OrderNo,
        //            PalletCode = request.PalletCode,
        //            Status = (int)SplitPackageStatusEnum.已拆包,
        //            PreviousSplitRecordId = previousSplitRecord?.Id??0 // è®°å½•前一次拆包ID,建立拆包链
        //        };
        //        await Db.Insertable(splitHistory).ExecuteCommandAsync();
        //        _unitOfWorkManage.CommitTran();
        //        try
        //        {
        //            MaterielToMesDTO dto = new MaterielToMesDTO
        //            {
        //                batchNo = baseStockDetail.BatchNo,
        //                factoryArea = baseStockDetail.FactoryArea,
        //                materialCode = baseStockDetail.MaterielCode,
        //                newmaterialCode = newBarcode,
        //                oldmaterialCode = request.OriginalBarcode,
        //                operationType = 1,
        //                qty = remainingQty,
        //                supplyCode = baseStockDetail.SupplyCode,
        //                unit = baseStockDetail.BarcodeUnit,
        //                warehouseCode = baseStockDetail.WarehouseCode,
        //                reqCode = Guid.NewGuid().ToString(),
        //                reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
        //            };
        //            _invokeMESService.NewMaterielToMes(dto);
        //        }
        //        catch(Exception ex)
        //        {
        //            _logger.LogError("SplitPackage å›žä¼ MES:  " + ex.Message);
        //        }
        //        return WebResponseContent.Instance.OK("拆包成功", new
        //        {
        //            NewBarcode = newBarcode,
        //            NewLockInfoId = newLockInfo.Id
        //        });
        //    }
        //    catch (Exception ex)
        //    {
        //        _unitOfWorkManage.RollbackTran();
        //        return WebResponseContent.Instance.Error($"拆包失败: {ex.Message}");
        //    }
        //}
        // èŽ·å–æ¡ç çš„æ‹†åŒ…åŽ†å²é“¾
        public async Task<WebResponseContent> SplitPackage(SplitPackageDto request)
        {
@@ -331,6 +168,30 @@
                _unitOfWorkManage.CommitTran();
                try
                {
                    var dt_MaterielToMes = new Dt_MaterielToMes
                    {
                        OldMaterialBarCode = request.OriginalBarcode,
                        NewMaterialBarCode = newBarcode,
                        Unit = baseStockDetail.BarcodeUnit,
                        factoryArea = baseStockDetail.FactoryArea,
                        Qty = remainingQty,
                        supplyCode = baseStockDetail.SupplyCode,
                        warehouseCode = baseStockDetail.WarehouseCode,
                        BatchNo = baseStockDetail.BatchNo,
                        MaterielCode = baseStockDetail.MaterielCode,
                    };
                    _materielToMesService.AddData(dt_MaterielToMes);
                }
                catch (Exception ex)
                {
                    _logger.LogError("SplitPackage å›žä¼ MES:  " + ex.Message);
                }
                return WebResponseContent.Instance.OK("拆包成功", new SplitPackageChainDto
                {
                    NewBarcode = newBarcode,
@@ -418,7 +279,7 @@
                {
                    record.IsReverted = true;
                    record.RevertTime = DateTime.Now;
                    record.Status = (int)SplitPackageStatusEnum.已撤销;
                }
                await Db.Updateable(splitRecords).ExecuteCommandAsync();
@@ -526,14 +387,14 @@
        // èŽ·å–å¯æ’¤é”€çš„æ‹†åŒ…è®°å½•åˆ—è¡¨
        public Dt_SplitPackageRecord GetRevertableSplitRecords(string originalBarcode)
        {
            var revertableRecords =   Db.Queryable<Dt_SplitPackageRecord>()
            var revertableRecords = Db.Queryable<Dt_SplitPackageRecord>()
                    .Where(x => x.OriginalBarcode == originalBarcode && !x.IsReverted)
                    .OrderBy(x => x.SplitTime)
                   .First();
            return   revertableRecords ;
            return revertableRecords;
        }
        // èŽ·å–æ‹†åŒ…ä¿¡æ¯
        public async Task<WebResponseContent> GetSplitPackageInfo(string orderNo, string palletCode, string barcode)
        {
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_StockService/StockInfoService.cs
@@ -225,6 +225,12 @@
            return Db.Queryable<Dt_StockInfo>().Where(x => x.StockStatus == StockStatusEmun.入库完成.ObjToInt() && SqlFunc.Subqueryable<Dt_LocationInfo>().Where(v => v.LocationCode == x.LocationCode && v.LocationType == locationType && v.LocationStatus == LocationStatusEnum.Pallet.ObjToInt() && (v.EnableStatus == EnableStatusEnum.OnlyOut.ObjToInt() || EnableStatusEnum.Normal.ObjToInt() == v.EnableStatus)).Any()).OrderBy(x => x.ModifyDate).First();
        }
        public List<Dt_StockInfo> GetStockInfosByPalletCodes(List<string> palletCodes)
        {
            return Db.Queryable<Dt_StockInfo>().Where(x => palletCodes.Contains(x.PalletCode)).Includes(x => x.Details).ToList();
        }
        /// <summary>
        /// 
        /// </summary>
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_Outbound.cs
@@ -335,6 +335,51 @@
            return tasks;
        }
        public List<Dt_Task> GetTasks(List<Dt_StockInfo> stockInfos, TaskTypeEnum taskType)
        {
            List<Dt_Task> tasks = new List<Dt_Task>();
            List<Dt_LocationInfo> locationInfos = _locationInfoService.Repository.QueryData(x => stockInfos.Select(x => x.LocationCode).Contains(x.LocationCode));
            for (int i = 0; i < stockInfos.Count; i++)
            {
                Dt_StockInfo stockInfo = stockInfos[i];
                if (stockInfo != null)
                {
                    Dt_LocationInfo? locationInfo = locationInfos.FirstOrDefault(x => x.LocationCode == stockInfo.LocationCode);
                    if (!tasks.Exists(x => x.PalletCode == stockInfo.PalletCode))
                    {
                        Dt_Task task = new()
                        {
                            CurrentAddress = stockInfo.LocationCode,
                            Grade = 0,
                            PalletCode = stockInfo.PalletCode,
                            NextAddress = "",
                            Roadway = locationInfo.RoadwayNo,
                            SourceAddress = stockInfo.LocationCode,
                            TargetAddress = "",
                            TaskStatus = TaskStatusEnum.New.ObjToInt(),
                            TaskType = taskType.ObjToInt(),
                            //TaskNum = BaseDal.GetTaskNum(nameof(SequenceEnum.SeqTaskNum)),
                            PalletType = stockInfo.PalletType,
                            WarehouseId = stockInfo.WarehouseId,
                        };
                        //if (taskType != TaskTypeEnum.OutEmpty)
                        //{
                        //    task.MaterielCode = stockInfo.Details?.Where(x => x.StockId == stockInfo.Id).FirstOrDefault()?.MaterielCode;
                        //    task.Quantity = (float)stockInfo.Details?.Where(x => x.StockId == stockInfo.Id).Sum(x => x.StockQuantity);
                        //    task.BatchNo = stockInfo.Details?.Where(x => x.StockId == stockInfo.Id).FirstOrDefault()?.BatchNo;
                        //}
                        //if (stockInfo.StockLength > 0)
                        //{
                        //    task.TaskLength = stockInfo.StockLength;
                        //}
                        tasks.Add(task);
                    }
                }
            }
            return tasks;
        }
        /// <summary>
        /// ç”Ÿæˆå‡ºåº“任务
@@ -385,5 +430,159 @@
        }
        /// <summary>
        /// ç”Ÿæˆå‡ºåº“任务
        /// </summary>
        /// <param name="orderDetailId"></param>
        /// <param name="stockSelectViews"></param>
        /// <returns></returns>
        public WebResponseContent GenerateOutboundTask(int orderDetailId, List<StockSelectViewDTO> stockSelectViews)
        {
            try
            {
                (List<Dt_Task>, List<Dt_StockInfo>?, List<Dt_OutboundOrderDetail>?, List<Dt_OutStockLockInfo>?, List<Dt_LocationInfo>?) result = OutboundTaskDataHandle(orderDetailId, stockSelectViews);
                WebResponseContent content = GenerateOutboundTaskDataUpdate(result.Item1, result.Item2, result.Item3, result.Item4, result.Item5);
                return content;
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// å‡ºåº“任务数据处理
        /// </summary>
        /// <param name="orderDetailId"></param>
        /// <param name="stockSelectViews"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public (List<Dt_Task>, List<Dt_StockInfo>?, List<Dt_OutboundOrderDetail>?, List<Dt_OutStockLockInfo>?, List<Dt_LocationInfo>?) OutboundTaskDataHandle(int orderDetailId, List<StockSelectViewDTO> stockSelectViews)
        {
            List<Dt_Task> tasks = new List<Dt_Task>();
            Dt_OutboundOrderDetail outboundOrderDetail = _outboundOrderDetailService.Repository.QueryFirst(x => x.Id == orderDetailId);
            if (outboundOrderDetail == null)
            {
                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;
            List<Dt_LocationInfo>? locationInfos = null;
            if (outboundOrderDetail.OrderDetailStatus == OrderDetailStatusEnum.New.ObjToInt())
            {
                (List<Dt_StockInfo>, Dt_OutboundOrderDetail, List<Dt_OutStockLockInfo>, List<Dt_LocationInfo>) result = _outboundOrderDetailService.AssignStockOutbound(outboundOrderDetail, stockSelectViews);
                if (result.Item1 != null && result.Item1.Count > 0)
                {
                    Dt_OutboundOrder outboundOrder = _outboundOrderService .Repository.QueryFirst(x => x.Id == outboundOrderDetail.OrderId);
                    TaskTypeEnum typeEnum = outboundOrder.OrderType switch
                    {
                        (int)OutOrderTypeEnum.Issue => TaskTypeEnum.Outbound,
                        (int)OutOrderTypeEnum.Allocate => TaskTypeEnum.OutAllocate,
                        (int)OutOrderTypeEnum.Quality => TaskTypeEnum.OutQuality,
                        _ => new TaskTypeEnum()
                    };
                    tasks = GetTasks(result.Item1, typeEnum);
                    result.Item2.OrderDetailStatus = OrderDetailStatusEnum.Outbound.ObjToInt();
                    result.Item3.ForEach(x =>
                    {
                        x.Status = OutLockStockStatusEnum.出库中.ObjToInt();
                    });
                    stockInfos = result.Item1;
                    orderDetail = result.Item2;
                    outStockLockInfos = result.Item3;
                    locationInfos = result.Item4;
                }
                else
                {
                    throw new Exception("无库存");
                }
            }
            else
            {
                List<Dt_OutStockLockInfo> stockLockInfos = _outStockLockInfoService.GetByOrderDetailId(outboundOrderDetail.OrderId, OutLockStockStatusEnum.已分配);
                if (stockLockInfos != null && stockLockInfos.Count > 0)
                {
                    List<Dt_StockInfo> stocks = _stockService.StockInfoService.GetStockInfosByPalletCodes(stockLockInfos.Select(x => x.PalletCode).Distinct().ToList());
                    tasks = GetTasks(stocks, TaskTypeEnum.Outbound);
                }
            }
            return (tasks, stockInfos, orderDetail == null ? null : new List<Dt_OutboundOrderDetail> { orderDetail }, outStockLockInfos, locationInfos);
        }
        /// <summary>
        /// ç”Ÿæˆå‡ºåº“任务后数据更新到数据库
        /// </summary>
        /// <param name="tasks"></param>
        /// <param name="stockInfos"></param>
        /// <param name="outboundOrderDetails"></param>
        /// <param name="outStockLockInfos"></param>
        /// <param name="locationInfos"></param>
        /// <returns></returns>
        public WebResponseContent GenerateOutboundTaskDataUpdate(List<Dt_Task> tasks, List<Dt_StockInfo>? stockInfos = null, List<Dt_OutboundOrderDetail>? outboundOrderDetails = null, List<Dt_OutStockLockInfo>? outStockLockInfos = null, List<Dt_LocationInfo>? locationInfos = null)
        {
            try
            {
                _unitOfWorkManage.BeginTran();
                BaseDal.AddData(tasks);
                if (stockInfos != null && stockInfos.Count > 0 && outboundOrderDetails != null && outboundOrderDetails.Count > 0 && outStockLockInfos != null && outStockLockInfos.Count > 0 && locationInfos != null && locationInfos.Count > 0)
                {
                    stockInfos.ForEach(x =>
                    {
                        x.StockStatus = StockStatusEmun.出库锁定.ObjToInt();
                    });
                    outboundOrderDetails.ForEach(x =>
                    {
                        x.OrderDetailStatus = OrderDetailStatusEnum.Outbound.ObjToInt();
                    });
                    Dt_OutboundOrder outboundOrder = _outboundOrderService.Repository.QueryFirst(x => x.Id == outboundOrderDetails.FirstOrDefault().OrderId);
                    if (outboundOrder.OrderStatus != OutOrderStatusEnum.出库中.ObjToInt())
                    {
                        _outboundOrderService.Repository.UpdateData(outboundOrder);
                    }
                    WebResponseContent content = _outboundOrderDetailService.LockOutboundStockDataUpdate(stockInfos, outboundOrderDetails, outStockLockInfos, locationInfos, tasks: tasks);
                    if (!content.Status)
                    {
                        _unitOfWorkManage.RollbackTran();
                        return content;
                    }
                }
                else if (outboundOrderDetails != null && outboundOrderDetails.Count > 0)
                {
                    outboundOrderDetails.ForEach(x =>
                    {
                        x.OrderDetailStatus = OrderDetailStatusEnum.Outbound.ObjToInt();
                    });
                    Dt_OutboundOrder outboundOrder = _outboundOrderService.Repository.QueryFirst(x => x.Id == outboundOrderDetails.FirstOrDefault().OrderId);
                    if (outboundOrder.OrderStatus != OutOrderStatusEnum.出库中.ObjToInt())
                    {
                        _outboundOrderService.Repository.UpdateData(outboundOrder);
                    }
                    _outboundOrderDetailService.Repository.UpdateData(outboundOrderDetails);
                }
                _unitOfWorkManage.CommitTran();
                //PushTasksToWCS(tasks);
                return WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs
@@ -47,5 +47,17 @@
            return await Service.GenerateOutboundTasksAsync(data.taskIds,data.outboundPlatform);
        }
        /// <summary>
        /// ç”Ÿæˆå‡ºåº“任务
        /// </summary>
        /// <param name="orderDetailId"></param>
        /// <param name="stockSelectViews"></param>
        /// <returns></returns>
        [HttpPost, HttpGet, Route("GenerateOutboundTask"), AllowAnonymous]
        public WebResponseContent GenerateOutboundTask(int orderDetailId, [FromBody] List<StockSelectViewDTO> stockSelectViews)
        {
            return Service.GenerateOutboundTask(orderDetailId, stockSelectViews);
        }
    }
}