111
tjx
5 天以前 f1b5c366456c042b2cfa380d4c63d900dfeec4f8
111
已修改1个文件
151 ■■■■ 文件已修改
StandardPda/MES.Service/service/Warehouse/MesInvItemStocksManager.cs 151 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
StandardPda/MES.Service/service/Warehouse/MesInvItemStocksManager.cs
@@ -19,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
            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";
        // 1. 查询XB_RACKING_TASK_SYXT_LOG中ItemBarcode和PalletCode的映射关系
        var allRackingTaskData = Db.Queryable<XbRackingTaskSyxtLog>()
            .Where(x => !string.IsNullOrEmpty(x.ItemBarcode))
            .Select(x => new { x.ItemBarcode, x.PalletCode, x.Code, x.Id })
            .ToList();
        // ReturnableStockDto增加一个库存状态的字段
        // 当allRackingTaskData中的Code为null时,库存状态为立库入库中
        // 当allRackingTaskData中的Code为200时,库存状态为已经在立库内
        // 对每个条码,取最新ID的记录,并过滤掉Code为500(表示失败)的记录
        var rackingTaskData = allRackingTaskData
            .GroupBy(x => x.ItemBarcode) // 按条码分组
            .Select(g => g.OrderByDescending(x => x.Id).First()) // 取每个条码最新的一条记录
            .Where(x => x.Code != "500") // 过滤掉Code为500的失败记录
            .ToList();
        var rackingTaskData = Db.Ado.SqlQuery<RackingTaskDto>(rackingTaskSql);
        if (rackingTaskData == null || !rackingTaskData.Any())
        {
@@ -61,11 +51,28 @@
            };
        }
        // 1.1 提取去重后的条码列表用于查询
        var distinctBarcodes = rackingTaskData.Select(x => x.ItemBarcode)
            .Distinct().ToList();
        // 优化点2: 过滤null值并使用字典提高查找效率
        var validRackingData = rackingTaskData.Where(x => !string.IsNullOrEmpty(x.ItemBarcode)).ToList();
        if (!validRackingData.Any())
        {
            return new PagedResult<ReturnableStockDto>
            {
                TbBillList = new List<ReturnableStockDto>(),
                Pagination = new PaginationInfo
                {
                    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();
        // 2. 构建查询条件
        // 优化点3: 构建查询条件
        var query = Db.Queryable<MesInvItemStocks>()
            .LeftJoin<MesItems>((stock, item) => stock.ItemId == item.Id)
            .LeftJoin<MesDepots>((stock, item, depot) =>
@@ -79,17 +86,13 @@
                 distinctBarcodes.Contains(stock.StackCode)) &&
                stock.Quantity > 0);
        // 3. 应用搜索条件
        var conditions = searchDto.Conditions;
        if (conditions != null)
        {
            //当conditions.IqcStatus为1时查询的值就要是特采直接使用,已检,免检,1的值
            // 精确匹配条件
            if (!string.IsNullOrEmpty(conditions.IqcStatus))
            {
                if (conditions.IqcStatus == "1")
                {
                    // 当IqcStatus为"1"时,查询特采直接使用、已检、免检状态
                    query = query.Where((stock, item, depot, org, unit) =>
                        stock.IqcStatus == "特采直接使用" ||
                        stock.IqcStatus == "已检" ||
@@ -97,7 +100,6 @@
                }
                else
                {
                    // 其他情况按原值匹配
                    query = query.Where((stock, item, depot, org, unit) =>
                        stock.IqcStatus == conditions.IqcStatus);
                }
@@ -108,8 +110,6 @@
                query = query.Where((stock, item, depot, org, unit) =>
                    stock.Quantity == conditions.Quantity.Value);
            }
            // 模糊匹配条件
            if (!string.IsNullOrEmpty(conditions.DepotName))
            {
@@ -177,7 +177,6 @@
                     stock.StackCode.Contains(conditions.ItemBarcode)));
            }
            // 日期范围条件
            if (!string.IsNullOrEmpty(conditions.IndepDateStart))
            {
                if (DateTime.TryParse(conditions.IndepDateStart,
@@ -198,7 +197,7 @@
            }
        }
        // 4. 查询所有符合条件的数据(不分页)
        // 优化点4: 查询数据
        var queryResult = query
            .OrderByDescending((stock, item, depot, org, unit) =>
                stock.IndepDate)
@@ -222,19 +221,16 @@
            })
            .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;
            var rackingTask = rackingTaskData
                .Where(r => r.ItemBarcode == barcodeToMatch)
                .FirstOrDefault();
            rackingTaskDict.TryGetValue(barcodeToMatch, out var rackingTask);
            // 根据Code值确定库存状态: null为立库入库中(0), 200为已在立库内(1)
            string stockStatus = "进入立库的路上"; // 默认为立库入库中
            string stockStatus = "进入立库的路上";
            if (rackingTask?.Code != null)
            {
                stockStatus = rackingTask.Code == "200" ? "已在立库中" : "进入立库的路上";
@@ -244,7 +240,7 @@
            {
                IqcStatus = x.IqcStatus == "已检" ? "1" : "0",
                ItemType = x.DepotName == "原材料仓" ? "0" : "1",
                StackCode = rackingTask?.PalletCode, // 使用PalletCode作为母托盘编号
                StackCode = rackingTask?.PalletCode,
                x.DepotCode,
                x.DepotName,
                x.DepotSectionsCode,
@@ -258,11 +254,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
@@ -272,7 +267,6 @@
                .ToList();
        }
        // 5.2 应用StockStatus搜索条件(在内存中过滤)
        if (conditions != null && !string.IsNullOrEmpty(conditions.StockStatus))
        {
            tempDataList = tempDataList
@@ -280,7 +274,6 @@
                .ToList();
        }
        // 5.3 分组并合计Quantity
        var dataList = tempDataList
            .GroupBy(x => new
            {
@@ -298,7 +291,7 @@
                x.OrgCode,
                x.OrgName,
                x.ItemBarcode,
                x.StockStatus // 添加库存状态到分组键中
                x.StockStatus
            })
            .Select(g => new ReturnableStockDto
            {
@@ -318,27 +311,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,
@@ -358,30 +347,30 @@
    /// <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) =>
@@ -413,22 +402,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
@@ -449,13 +431,20 @@
                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; }
    }
    /// <summary>
    ///     根据用户编码和字符串生成退料请求单
    /// </summary>