111
tjx
5 天以前 fbd1dae61bb8eeccd303341ff3b5290d805a8155
StandardPda/MES.Service/service/Warehouse/MesInvItemStocksManager.cs
@@ -4,6 +4,8 @@
using SqlSugar;
using Newtonsoft.Json;
using System.Text;
using OfficeOpenXml;
using OfficeOpenXml.Style;
namespace MES.Service.service.Warehouse;
@@ -17,32 +19,22 @@
    public PagedResult<ReturnableStockDto> GetReturnableStocks(
        ReturnableStockSearchDto searchDto)
    {
        // 参数校验
        if (searchDto.PageIndex < 1)
        {
            throw new Exception("页码必须大于0");
        }
        if (!new[] { 10, 20, 50 }.Contains(searchDto.PageSize))
        {
            throw new Exception("每页条数必须为10、20或50");
        }
        // 优化点1: 使用原生SQL ROW_NUMBER()在数据库端完成去重和排序
        var rackingTaskSql = @"
            SELECT ITEM_BARCODE AS ItemBarcode, PALLETCODE AS PalletCode, CODE AS Code, TASKTYPE AS TaskType
            FROM (
                SELECT ITEM_BARCODE, PALLETCODE, CODE, TASKTYPE,
                       ROW_NUMBER() OVER (PARTITION BY ITEM_BARCODE ORDER BY ID DESC) AS RN
                FROM XB_RACKING_TASK_SYXT_LOG
                WHERE ITEM_BARCODE IS NOT NULL AND (CODE IS NULL OR CODE != '500')
            ) WHERE RN = 1";
        // 1. 优化:使用原生SQL获取每个条码的最新记录(避免全表加载到内存)
        // 使用窗口函数ROW_NUMBER在数据库层面完成分组取最新记录
        var sql = @"
            SELECT ITEM_BARCODE, PalletCode, Code, Id
            FROM (SELECT ITEM_BARCODE,
                         PalletCode,
                         Code,
                         Id,
                         ROW_NUMBER() OVER (PARTITION BY ITEM_BARCODE ORDER BY Id DESC) as rn
                  FROM XB_RACKING_TASK_SYXT_LOG
                  WHERE ITEM_BARCODE IS NOT NULL
                    AND Code != '500') t
            WHERE rn = 1";
        var rackingTaskData = Db.Ado.SqlQuery<RackingTaskInfo>(sql);
        var rackingTaskData = Db.Ado.SqlQuery<RackingTaskDto>(rackingTaskSql);
        if (rackingTaskData == null || !rackingTaskData.Any())
        {
@@ -59,210 +51,202 @@
            };
        }
        // 1.1 提取去重后的条码列表用于查询
        var distinctBarcodes = rackingTaskData.Select(x => x.ItemBarcode)
            .Distinct().ToList();
        // 1.2 提取搜索条件(提升作用域)
        var conditions = searchDto.Conditions;
        // 2. 优化:分批处理条码列表(避免IN查询过大)
        const int batchSize = 500; // 每批处理500条
        var allQueryResults = new List<StockQueryResult>();
        // 优化点2: 过滤null值并使用字典提高查找效率
        var validRackingData = rackingTaskData.Where(x => !string.IsNullOrEmpty(x.ItemBarcode)).ToList();
        
        for (int i = 0; i < distinctBarcodes.Count; i += batchSize)
        if (!validRackingData.Any())
        {
            var batchBarcodes = distinctBarcodes.Skip(i).Take(batchSize).ToList();
            // 2.1 构建查询条件
            var query = Db.Queryable<MesInvItemStocks>()
                .LeftJoin<MesItems>((stock, item) => stock.ItemId == item.Id)
                .LeftJoin<MesDepots>((stock, item, depot) =>
                    stock.DepotsCode == depot.DepotCode)
                .LeftJoin<Organize>((stock, item, depot, org) =>
                    item.UseOrg == org.Id.ToString())
                .LeftJoin<MesUnit>((stock, item, depot, org, unit) =>
                    item.ItemUnit == unit.Id.ToString())
                .Where((stock, item, depot, org, unit) =>
                    (batchBarcodes.Contains(stock.ItemBarcode) ||
                     batchBarcodes.Contains(stock.StackCode)) &&
                    stock.Quantity > 0);
            // 2.2 应用搜索条件(在数据库层面过滤)
            if (conditions != null)
            return new PagedResult<ReturnableStockDto>
            {
                //当conditions.IqcStatus为1时查询的值就要是特采直接使用,已检,免检,1的值
                // 精确匹配条件
                if (!string.IsNullOrEmpty(conditions.IqcStatus))
                TbBillList = new List<ReturnableStockDto>(),
                Pagination = new PaginationInfo
                {
                    if (conditions.IqcStatus == "1")
                    {
                        // 当IqcStatus为"1"时,查询特采直接使用、已检、免检状态
                        query = query.Where((stock, item, depot, org, unit) =>
                            stock.IqcStatus == "特采直接使用" ||
                            stock.IqcStatus == "已检" ||
                            stock.IqcStatus == "免检");
                    }
                    else
                    {
                        // 其他情况按原值匹配
                        query = query.Where((stock, item, depot, org, unit) =>
                            stock.IqcStatus == conditions.IqcStatus);
                    }
                    CurrentPage = searchDto.PageIndex,
                    PageSize = searchDto.PageSize,
                    TotalRecords = 0,
                    TotalPages = 0
                }
            };
        }
        var rackingTaskDict = validRackingData.ToDictionary(x => x.ItemBarcode);
        var distinctBarcodes = validRackingData.Select(x => x.ItemBarcode).ToList();
                if (conditions.Quantity.HasValue)
        // 优化点3: 构建查询条件
        var query = Db.Queryable<MesInvItemStocks>()
            .LeftJoin<MesItems>((stock, item) => stock.ItemId == item.Id)
            .LeftJoin<MesDepots>((stock, item, depot) =>
                stock.DepotsCode == depot.DepotCode)
            .LeftJoin<Organize>((stock, item, depot, org) =>
                item.UseOrg == org.Id.ToString())
            .LeftJoin<MesUnit>((stock, item, depot, org, unit) =>
                item.ItemUnit == unit.Id.ToString())
            .Where((stock, item, depot, org, unit) =>
                (distinctBarcodes.Contains(stock.ItemBarcode) ||
                 distinctBarcodes.Contains(stock.StackCode)) &&
                stock.Quantity > 0);
        var conditions = searchDto.Conditions;
        if (conditions != null)
        {
            if (!string.IsNullOrEmpty(conditions.IqcStatus))
            {
                if (conditions.IqcStatus == "1")
                {
                    query = query.Where((stock, item, depot, org, unit) =>
                        stock.Quantity == conditions.Quantity.Value);
                        stock.IqcStatus == "特采直接使用" ||
                        stock.IqcStatus == "已检" ||
                        stock.IqcStatus == "免检");
                }
                // 模糊匹配条件
                if (!string.IsNullOrEmpty(conditions.DepotName))
                else
                {
                    query = query.Where((stock, item, depot, org, unit) =>
                        depot.DepotName != null &&
                        depot.DepotName.Contains(conditions.DepotName));
                }
                if (!string.IsNullOrEmpty(conditions.DepotSectionsCode))
                {
                    query = query.Where((stock, item, depot, org, unit) =>
                        stock.DepotSectionsCode != null &&
                        stock.DepotSectionsCode.Contains(conditions
                            .DepotSectionsCode));
                }
                if (!string.IsNullOrEmpty(conditions.ItemNo))
                {
                    query = query.Where((stock, item, depot, org, unit) =>
                        item.ItemNo != null &&
                        item.ItemNo.Contains(conditions.ItemNo));
                }
                if (!string.IsNullOrEmpty(conditions.ItemName))
                {
                    query = query.Where((stock, item, depot, org, unit) =>
                        item.ItemName != null &&
                        item.ItemName.Contains(conditions.ItemName));
                }
                if (!string.IsNullOrEmpty(conditions.ItemModel))
                {
                    query = query.Where((stock, item, depot, org, unit) =>
                        item.ItemModel != null &&
                        item.ItemModel.Contains(conditions.ItemModel));
                }
                if (!string.IsNullOrEmpty(conditions.ItemUnitName))
                {
                    query = query.Where((stock, item, depot, org, unit) =>
                        unit.Fname != null &&
                        unit.Fname.Contains(conditions.ItemUnitName));
                }
                if (!string.IsNullOrEmpty(conditions.OrgCode))
                {
                    query = query.Where((stock, item, depot, org, unit) =>
                        org.Fnumber != null &&
                        org.Fnumber.Contains(conditions.OrgCode));
                }
                if (!string.IsNullOrEmpty(conditions.OrgName))
                {
                    query = query.Where((stock, item, depot, org, unit) =>
                        org.Fname != null &&
                        org.Fname.Contains(conditions.OrgName));
                }
                if (!string.IsNullOrEmpty(conditions.ItemBarcode))
                {
                    query = query.Where((stock, item, depot, org, unit) =>
                        (stock.ItemBarcode != null &&
                         stock.ItemBarcode.Contains(conditions.ItemBarcode)) ||
                        (stock.StackCode != null &&
                         stock.StackCode.Contains(conditions.ItemBarcode)));
                }
                // 日期范围条件
                if (!string.IsNullOrEmpty(conditions.IndepDateStart))
                {
                    if (DateTime.TryParse(conditions.IndepDateStart,
                            out var startDate))
                    {
                        query = query.Where((stock, item, depot, org, unit) =>
                            stock.IndepDate >= startDate);
                    }
                }
                if (!string.IsNullOrEmpty(conditions.IndepDateEnd))
                {
                    if (DateTime.TryParse(conditions.IndepDateEnd, out var endDate))
                    {
                        query = query.Where((stock, item, depot, org, unit) =>
                            stock.IndepDate <= endDate);
                    }
                        stock.IqcStatus == conditions.IqcStatus);
                }
            }
            // 2.3 执行当前批次查询
            var batchQueryResult = query
                .OrderByDescending((stock, item, depot, org, unit) =>
                    stock.IndepDate)
                .Select((stock, item, depot, org, unit) => new StockQueryResult
            if (conditions.Quantity.HasValue)
            {
                query = query.Where((stock, item, depot, org, unit) =>
                    stock.Quantity == conditions.Quantity.Value);
            }
            if (!string.IsNullOrEmpty(conditions.DepotName))
            {
                query = query.Where((stock, item, depot, org, unit) =>
                    depot.DepotName != null &&
                    depot.DepotName.Contains(conditions.DepotName));
            }
            if (!string.IsNullOrEmpty(conditions.DepotSectionsCode))
            {
                query = query.Where((stock, item, depot, org, unit) =>
                    stock.DepotSectionsCode != null &&
                    stock.DepotSectionsCode.Contains(conditions
                        .DepotSectionsCode));
            }
            if (!string.IsNullOrEmpty(conditions.ItemNo))
            {
                query = query.Where((stock, item, depot, org, unit) =>
                    item.ItemNo != null &&
                    item.ItemNo.Contains(conditions.ItemNo));
            }
            if (!string.IsNullOrEmpty(conditions.ItemName))
            {
                query = query.Where((stock, item, depot, org, unit) =>
                    item.ItemName != null &&
                    item.ItemName.Contains(conditions.ItemName));
            }
            if (!string.IsNullOrEmpty(conditions.ItemModel))
            {
                query = query.Where((stock, item, depot, org, unit) =>
                    item.ItemModel != null &&
                    item.ItemModel.Contains(conditions.ItemModel));
            }
            if (!string.IsNullOrEmpty(conditions.ItemUnitName))
            {
                query = query.Where((stock, item, depot, org, unit) =>
                    unit.Fname != null &&
                    unit.Fname.Contains(conditions.ItemUnitName));
            }
            if (!string.IsNullOrEmpty(conditions.OrgCode))
            {
                query = query.Where((stock, item, depot, org, unit) =>
                    org.Fnumber != null &&
                    org.Fnumber.Contains(conditions.OrgCode));
            }
            if (!string.IsNullOrEmpty(conditions.OrgName))
            {
                query = query.Where((stock, item, depot, org, unit) =>
                    org.Fname != null &&
                    org.Fname.Contains(conditions.OrgName));
            }
            if (!string.IsNullOrEmpty(conditions.ItemBarcode))
            {
                query = query.Where((stock, item, depot, org, unit) =>
                    (stock.ItemBarcode != null &&
                     stock.ItemBarcode.Contains(conditions.ItemBarcode)) ||
                    (stock.StackCode != null &&
                     stock.StackCode.Contains(conditions.ItemBarcode)));
            }
            if (!string.IsNullOrEmpty(conditions.IndepDateStart))
            {
                if (DateTime.TryParse(conditions.IndepDateStart,
                        out var startDate))
                {
                    IqcStatus = stock.IqcStatus,
                    DepotCode = stock.DepotsCode,
                    DepotName = depot.DepotName,
                    DepotSectionsCode = stock.DepotSectionsCode,
                    ItemNo = item.ItemNo,
                    ItemName = item.ItemName,
                    ItemModel = item.ItemModel,
                    Quantity = stock.Quantity,
                    ItemUnit = item.ItemUnit,
                    ItemUnitName = unit.Fname,
                    IndepDate = stock.IndepDate,
                    OrgCode = org.Fnumber,
                    OrgName = org.Fname,
                    ItemBarcode = stock.ItemBarcode,
                    StockStackCode = stock.StackCode
                })
                .ToList();
            allQueryResults.AddRange(batchQueryResult);
                    query = query.Where((stock, item, depot, org, unit) =>
                        stock.IndepDate >= startDate);
                }
            }
            if (!string.IsNullOrEmpty(conditions.IndepDateEnd))
            {
                if (DateTime.TryParse(conditions.IndepDateEnd, out var endDate))
                {
                    query = query.Where((stock, item, depot, org, unit) =>
                        stock.IndepDate <= endDate);
                }
            }
        }
        // 3. 合并所有批次的查询结果
        var queryResult = allQueryResults;
        // 4. 优化:构建条码映射字典(提高查找效率)
        var rackingTaskDict = rackingTaskData
            .ToDictionary(x => x.ItemBarcode, x => x);
        // 优化点4: 查询数据
        var queryResult = query
            .OrderByDescending((stock, item, depot, org, unit) =>
                stock.IndepDate)
            .Select((stock, item, depot, org, unit) => new
            {
                stock.IqcStatus,
                DepotCode = stock.DepotsCode,
                depot.DepotName,
                stock.DepotSectionsCode,
                item.ItemNo,
                item.ItemName,
                item.ItemModel,
                stock.Quantity,
                item.ItemUnit,
                ItemUnitName = unit.Fname,
                stock.IndepDate,
                OrgCode = org.Fnumber,
                OrgName = org.Fname,
                stock.ItemBarcode,
                StockStackCode = stock.StackCode
            })
            .ToList();
        // 5. 在内存中转换为DTO,关联PalletCode并赋值ItemBarcode(优先使用箱条码StockStackCode)
        // 优化点5: 使用字典查找替代Where().FirstOrDefault()
        var tempDataList = queryResult.Select(x =>
        {
            // 优先使用StockStackCode,否则使用ItemBarcode去查找PalletCode
            var barcodeToMatch = !string.IsNullOrEmpty(x.StockStackCode)
                ? x.StockStackCode
                : x.ItemBarcode;
            
            // 使用字典查找,性能更优
            rackingTaskDict.TryGetValue(barcodeToMatch, out var rackingTask);
            // 根据Code值确定库存状态: null为立库入库中(0), 200为已在立库内(1)
            string? stockStatus = "进入立库的路上"; // 默认为立库入库中
            if (rackingTask?.Code != null)
            string stockStatus;
            if (rackingTask?.TaskType == "立库出库请求")
            {
                stockStatus = rackingTask.Code == "200" ? "已在立库中" : "进入立库的路上";
                // 出库请求:Code=200表示已出库,Code=null表示出库路上
                stockStatus = rackingTask.Code == "200" ? "已出立库" : "出立库路上";
            }
            else
            {
                // 回库请求(默认):Code=200表示已在立库中,Code=null表示进入立库的路上
                stockStatus = rackingTask?.Code == "200" ? "已在立库中" : "进入立库的路上";
            }
            return new
            {
                IqcStatus = x.IqcStatus == "已检" ? "1" : "0",
                ItemType = x.DepotName == "原材料仓" ? "0" : "1",
                StackCode = rackingTask?.PalletCode, // 使用PalletCode作为母托盘编号
                StackCode = rackingTask?.PalletCode,
                x.DepotCode,
                x.DepotName,
                x.DepotSectionsCode,
@@ -276,11 +260,10 @@
                x.OrgCode,
                x.OrgName,
                ItemBarcode = barcodeToMatch,
                StockStatus = stockStatus // 添加库存状态
                StockStatus = stockStatus
            };
        }).ToList();
        // 5.1 应用StackCode搜索条件(在内存中过滤PalletCode)
        if (conditions != null && !string.IsNullOrEmpty(conditions.StackCode))
        {
            tempDataList = tempDataList
@@ -290,7 +273,6 @@
                .ToList();
        }
        // 5.2 应用StockStatus搜索条件(在内存中过滤)
        if (conditions != null && !string.IsNullOrEmpty(conditions.StockStatus))
        {
            tempDataList = tempDataList
@@ -298,7 +280,6 @@
                .ToList();
        }
        // 5.3 分组并合计Quantity
        var dataList = tempDataList
            .GroupBy(x => new
            {
@@ -316,7 +297,7 @@
                x.OrgCode,
                x.OrgName,
                x.ItemBarcode,
                x.StockStatus // 添加库存状态到分组键中
                x.StockStatus
            })
            .Select(g => new ReturnableStockDto
            {
@@ -336,27 +317,23 @@
                OrgCode = g.Key.OrgCode,
                OrgName = g.Key.OrgName,
                ItemBarcode = g.Key.ItemBarcode,
                StockStatus = g.Key.StockStatus // 添加库存状态到DTO中
                StockStatus = g.Key.StockStatus
            }).ToList();
        // 6. 应用ItemType筛选(在内存中过滤)
        if (conditions?.ItemType != null)
        {
            dataList = dataList.Where(x => x.ItemType == conditions.ItemType)
                .ToList();
        }
        // 7. 计算总记录数和分页参数(基于最终结果)
        var totalRecords = dataList.Count;
        var totalPages =
            (int)Math.Ceiling((double)totalRecords / searchDto.PageSize);
        var skip = (searchDto.PageIndex - 1) * searchDto.PageSize;
        // 8. 对最终结果进行分页
        var pagedDataList =
            dataList.Skip(skip).Take(searchDto.PageSize).ToList();
        // 9. 返回分页结果
        return new PagedResult<ReturnableStockDto>
        {
            TbBillList = pagedDataList,
@@ -371,68 +348,35 @@
    }
    /// <summary>
    ///     辅助类:立库任务信息
    /// </summary>
    private class RackingTaskInfo
    {
        public string? ItemBarcode { get; set; }
        public string? PalletCode { get; set; }
        public string? Code { get; set; }
        public decimal Id { get; set; }
    }
    /// <summary>
    ///     辅助类:库存查询中间结果
    /// </summary>
    private class StockQueryResult
    {
        public string? IqcStatus { get; set; }
        public string? DepotCode { get; set; }
        public string? DepotName { get; set; }
        public string? DepotSectionsCode { get; set; }
        public string? ItemNo { get; set; }
        public string? ItemName { get; set; }
        public string? ItemModel { get; set; }
        public decimal? Quantity { get; set; }
        public string? ItemUnit { get; set; }
        public string? ItemUnitName { get; set; }
        public DateTime? IndepDate { get; set; }
        public string? OrgCode { get; set; }
        public string? OrgName { get; set; }
        public string? ItemBarcode { get; set; }
        public string? StockStackCode { get; set; }
    }
    /// <summary>
    ///     查询可以退货的物料(旧版本,保留兼容)
    /// </summary>
    /// <returns>可退货物料库存列表</returns>
    public List<ReturnableStockDto> GetReturnableStocks()
    {
        // 1. 查询XB_RACKING_TASK_SYXT_LOG中所有的条码并去重
        var distinctBarcodes = Db.Queryable<XbRackingTaskSyxtLog>()
            .Where(x => !string.IsNullOrEmpty(x.ItemBarcode))
            .Select(x => x.ItemBarcode)
            .Distinct()
            .ToList();
        // 优化点1: 使用原生SQL在数据库端完成去重和排序,避免全表加载到内存
        // Oracle 11g使用ROW_NUMBER()窗口函数获取每个条码的最新记录
        var rackingTaskSql = @"
            SELECT ITEM_BARCODE AS ItemBarcode, PALLETCODE AS PalletCode, CODE AS Code
            FROM (
                SELECT ITEM_BARCODE, PALLETCODE, CODE,
                       ROW_NUMBER() OVER (PARTITION BY ITEM_BARCODE ORDER BY ID DESC) AS RN
                FROM XB_RACKING_TASK_SYXT_LOG
                WHERE ITEM_BARCODE IS NOT NULL AND (CODE IS NULL OR CODE != '500')
            ) WHERE RN = 1";
        if (distinctBarcodes == null || !distinctBarcodes.Any())
        var rackingTaskData = Db.Ado.SqlQuery<RackingTaskDto>(rackingTaskSql);
        if (rackingTaskData == null || !rackingTaskData.Any())
        {
            return new List<ReturnableStockDto>();
        }
        // 1.1 查询XB_RACKING_TASK_SYXT_LOG中ItemBarcode和PalletCode、Code的映射关系
        var allRackingTaskData = Db.Queryable<XbRackingTaskSyxtLog>()
            .Where(x => !string.IsNullOrEmpty(x.ItemBarcode))
            .Select(x => new { x.ItemBarcode, x.PalletCode, x.Code, x.Id })
            .ToList();
        // 优化点2: 过滤null值并使用字典提高条码匹配效率,从O(n)降低到O(1)
        var validRackingData = rackingTaskData.Where(x => !string.IsNullOrEmpty(x.ItemBarcode)).ToList();
        var rackingTaskDict = validRackingData.ToDictionary(x => x.ItemBarcode);
        var distinctBarcodes = validRackingData.Select(x => x.ItemBarcode).ToList();
        var rackingTaskData = allRackingTaskData
            .GroupBy(x => x.ItemBarcode)
            .Select(g => g.OrderByDescending(x => x.Id).First())
            .ToList();
        // 2. 使用条码查询MES_INV_ITEM_STOCKS中的数据,关联MES_ITEMS、MES_DEPOTS、ORGANIZE、MES_UNIT表
        // 优化点3: 在数据库层面完成关联查询,一次性获取所有需要的数据
        var queryResult = Db.Queryable<MesInvItemStocks>()
            .LeftJoin<MesItems>((stock, item) => stock.ItemId == item.Id)
            .LeftJoin<MesDepots>((stock, item, depot) =>
@@ -464,22 +408,15 @@
            })
            .ToList();
        // 3. 在内存中进行数据转换
        // 优化点4: 使用字典查找替代Where().FirstOrDefault(),提高匹配性能
        var result = queryResult.Select(x =>
        {
            // 根据条码查找对应的立库任务信息
            var rackingTask = rackingTaskData
                .Where(r => r.ItemBarcode == x.ItemBarcode)
                .FirstOrDefault();
            rackingTaskDict.TryGetValue(x.ItemBarcode, out var rackingTask);
            // 根据Code值确定库存状态: null为立库入库中(0), 200为已在立库内(1)
            string? stockStatus = "0"; // 默认为立库入库中
            string stockStatus = "0";
            if (rackingTask?.Code != null)
            {
                stockStatus =
                    rackingTask.Code == "200"
                        ? "1"
                        : "2"; // 200对应已在立库中(1),其他非500值为进入立库的路上(2)
                stockStatus = rackingTask.Code == "200" ? "1" : "2";
            }
            return new ReturnableStockDto
@@ -500,11 +437,19 @@
                OrgCode = x.OrgCode,
                OrgName = x.OrgName,
                ItemBarcode = x.ItemBarcode,
                StockStatus = stockStatus // 添加库存状态
                StockStatus = stockStatus
            };
        }).ToList();
        return result;
    }
    private class RackingTaskDto
    {
        public string ItemBarcode { get; set; }
        public string PalletCode { get; set; }
        public string Code { get; set; }
        public string TaskType { get; set; }
    }
    /// <summary>
@@ -542,7 +487,7 @@
                }
                decimal messageId = 0;
                string? taskCode = "";
                string taskCode = "";
                // 根据条码查询XB_RACKING_TASK_SYXT_LOG表,查询max(PALLETCODE)和对应的widthType
                var rackingTaskInfo = Db.Queryable<XbRackingTaskSyxtLog>()
@@ -550,6 +495,20 @@
                    .OrderByDescending(x => x.Id)
                    .Select(x => new { x.PalletCode, x.WidthType })
                    .First();
                // 检查是否存在未完成的任务(基于PalletCode,Code为null)
                if (!string.IsNullOrEmpty(rackingTaskInfo?.PalletCode))
                {
                    var pendingTask = Db.Queryable<XbRackingTaskSyxtLog>()
                        .Where(x => x.PalletCode == rackingTaskInfo.PalletCode && x.Code == null)
                        .OrderByDescending(x => x.Id)
                        .First();
                    if (pendingTask != null)
                    {
                        throw new Exception($"托盘编号 {rackingTaskInfo.PalletCode} 已存在未完成的立库任务,请等待任务完成后再操作。");
                    }
                }
                try
                {
@@ -647,8 +606,8 @@
                        throw new Exception($"解析响应失败: {responseStr}");
                    }
                    var code = responseJson?.Code?.ToString()();
                    var jsonMessage = responseJson?.JsonMessage?.ToString()();
                    var code = responseJson?.Code?.ToString();
                    var jsonMessage = responseJson?.JsonMessage?.ToString();
                    // 7. 根据Code判断成功或失败
                    if (code == "200")
@@ -688,7 +647,7 @@
                            ? "任务请求失败"
                            : jsonMessage;
                        var failureMessage =
                            (string?)("立库任务下发失败: " + errorMessage);
                            (string)("立库任务下发失败: " + errorMessage);
                        Db.Updateable<MessageCenter>()
                            .SetColumns(it => it.Result == 0)
@@ -707,7 +666,7 @@
                    if (messageId > 0)
                    {
                        var exceptionMessage =
                            (string?)("立库任务异常: " + ex.Message);
                            (string)("立库任务异常: " + ex.Message);
                        Db.Updateable<MessageCenter>()
                            .SetColumns(it => it.Result == 0)
                            .SetColumns(it =>
@@ -731,4 +690,97 @@
            throw;
        }
    }
    /// <summary>
    ///     导出可退货物料库存为Excel
    /// </summary>
    /// <param name="searchDto">搜索请求参数</param>
    /// <returns>Excel文件字节数组</returns>
    public byte[] ExportReturnableStocksToExcel(
        ReturnableStockSearchDto searchDto)
    {
        // 设置 EPPlus 许可证上下文(非商业用途)
        ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
        // 获取所有数据(不分页)
        var tempSearchDto = new ReturnableStockSearchDto
        {
            PageIndex = 1,
            PageSize = int.MaxValue, // 获取所有数据
            Conditions = searchDto.Conditions
        };
        // 调用查询方法获取数据
        var result = GetReturnableStocks(tempSearchDto);
        var dataList = result.TbBillList;
        // 创建 Excel 文件
        using var package = new ExcelPackage();
        var worksheet = package.Workbook.Worksheets.Add("可退货物料库存");
        // 设置表头
        var headers = new[]
        {
            "良品状态",
            "是否成品",
            "母托盘编号",
            "仓库编码",
            "仓库名称",
            "虚拟库位",
            "物料编号",
            "物料名称",
            "物料规格",
            "物料数量",
            "物料单位",
            "入库时间",
            "组织编码",
            "组织名称",
            "物料条码",
            "库存状态"
        };
        // 写入表头
        for (int i = 0; i < headers.Length; i++)
        {
            worksheet.Cells[1, i + 1].Value = headers[i];
            worksheet.Cells[1, i + 1].Style.Font.Bold = true;
            worksheet.Cells[1, i + 1].Style.Fill.PatternType =
                ExcelFillStyle.Solid;
            worksheet.Cells[1, i + 1].Style.Fill.BackgroundColor
                .SetColor(System.Drawing.Color.LightGray);
            worksheet.Cells[1, i + 1].Style.HorizontalAlignment =
                ExcelHorizontalAlignment.Center;
        }
        // 写入数据
        int row = 2;
        foreach (var item in dataList)
        {
            worksheet.Cells[row, 1].Value =
                item.IqcStatus == "1" ? "良品" : "不良品";
            worksheet.Cells[row, 2].Value = item.ItemType == "1" ? "成品" : "非成品";
            worksheet.Cells[row, 3].Value = item.StackCode;
            worksheet.Cells[row, 4].Value = item.DepotCode;
            worksheet.Cells[row, 5].Value = item.DepotName;
            worksheet.Cells[row, 6].Value = item.DepotSectionsCode;
            worksheet.Cells[row, 7].Value = item.ItemNo;
            worksheet.Cells[row, 8].Value = item.ItemName;
            worksheet.Cells[row, 9].Value = item.ItemModel;
            worksheet.Cells[row, 10].Value = item.Quantity;
            worksheet.Cells[row, 11].Value = item.ItemUnitName;
            worksheet.Cells[row, 12].Value =
                item.IndepDate?.ToString("yyyy-MM-dd HH:mm:ss");
            worksheet.Cells[row, 13].Value = item.OrgCode;
            worksheet.Cells[row, 14].Value = item.OrgName;
            worksheet.Cells[row, 15].Value = item.ItemBarcode;
            worksheet.Cells[row, 16].Value = item.StockStatus;
            row++;
        }
        // 自动调整列宽
        worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
        // 返回 Excel 文件字节数组
        return package.GetAsByteArray();
    }
}