diff --git a/antis-ncc-admin/.env.development b/antis-ncc-admin/.env.development index 0eaf86c..6462393 100644 --- a/antis-ncc-admin/.env.development +++ b/antis-ncc-admin/.env.development @@ -1,9 +1,9 @@ # 开发 VUE_CLI_BABEL_TRANSPILE_MODULES = true -VUE_APP_BASE_API = 'https://erp.lvqianmeiye.com' +# VUE_APP_BASE_API = 'https://erp.lvqianmeiye.com' # VUE_APP_BASE_API = 'http://erp_test.lvqianmeiye.com' -# VUE_APP_BASE_API = 'http://localhost:2011' +VUE_APP_BASE_API = 'http://localhost:2011' # VUE_APP_BASE_API = 'http://localhost:2011' VUE_APP_IMG_API = '' VUE_APP_BASE_WSS = 'ws://192.168.110.45:2011/websocket' diff --git a/antis-ncc-admin/src/components/kpi-drill/tk-analysis.vue b/antis-ncc-admin/src/components/kpi-drill/tk-analysis.vue index 89dc234..b96ad97 100644 --- a/antis-ncc-admin/src/components/kpi-drill/tk-analysis.vue +++ b/antis-ncc-admin/src/components/kpi-drill/tk-analysis.vue @@ -43,7 +43,15 @@ diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StoreDailyStatisticsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StoreDailyStatisticsOutput.cs index 4868c35..fc7e684 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StoreDailyStatisticsOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StoreDailyStatisticsOutput.cs @@ -19,6 +19,11 @@ namespace NCC.Extend.Entitys.Dto.LqDailyReport public string StoreName { get; set; } /// + /// 在职人数 + /// + public int EmployeeCount { get; set; } + + /// /// 人头数(去重后的消费会员数) /// public int HeadCount { get; set; } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/BillingItemDetailListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/BillingItemDetailListQueryInput.cs index f9955be..c4334a8 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/BillingItemDetailListQueryInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/BillingItemDetailListQueryInput.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using NCC.Common.Filter; namespace NCC.Extend.Entitys.Dto.LqKdKdjlb @@ -78,9 +79,14 @@ namespace NCC.Extend.Entitys.Dto.LqKdKdjlb public string SourceType { get; set; } /// - /// 门店ID + /// 门店ID(单门店,兼容旧版本) /// public string StoreId { get; set; } + + /// + /// 门店ID列表(多门店筛选) + /// + public List StoreIds { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/HealthCoachStatisticsQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/HealthCoachStatisticsQueryInput.cs index 4dc317d..c1022bd 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/HealthCoachStatisticsQueryInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/HealthCoachStatisticsQueryInput.cs @@ -1,5 +1,6 @@ -using NCC.Common.Filter; using System; +using System.Collections.Generic; +using NCC.Common.Filter; namespace NCC.Extend.Entitys.Dto.LqKdKdjlb { @@ -24,11 +25,16 @@ namespace NCC.Extend.Entitys.Dto.LqKdKdjlb public string DepartmentId { get; set; } /// - /// 门店ID + /// 门店ID(单门店,兼容旧版本) /// public string StoreId { get; set; } /// + /// 门店ID列表(多门店筛选) + /// + public List StoreIds { get; set; } + + /// /// 健康师姓名 /// public string EmployeeName { get; set; } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKhxx/MemberItemInfoQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKhxx/MemberItemInfoQueryInput.cs index 2fa2ac7..13af103 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKhxx/MemberItemInfoQueryInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKhxx/MemberItemInfoQueryInput.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using NCC.Common.Filter; namespace NCC.Extend.Entitys.Dto.LqKhxx @@ -19,11 +20,16 @@ namespace NCC.Extend.Entitys.Dto.LqKhxx public string BelongStoreId { get; set; } /// - /// 开单门店ID + /// 开单门店ID(单门店,兼容旧版本) /// public string BillingStoreId { get; set; } /// + /// 开单门店ID列表(多门店筛选) + /// + public List BillingStoreIds { get; set; } + + /// /// 会员类型 /// public int MemberType { get; set; } = -1; diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/MemberUpgradeStatisticsListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/MemberUpgradeStatisticsListQueryInput.cs index 5e4f55b..e730eec 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/MemberUpgradeStatisticsListQueryInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/MemberUpgradeStatisticsListQueryInput.cs @@ -37,6 +37,11 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics /// 是否升生美(true-是,false-否,null-不筛选) /// public bool? HasUpgradeLifeBeauty { get; set; } + + /// + /// 门店ID列表(多门店筛选) + /// + public List StoreIds { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTkjlb/LqTkjlbListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTkjlb/LqTkjlbListOutput.cs index be0f45b..1d51b9a 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTkjlb/LqTkjlbListOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTkjlb/LqTkjlbListOutput.cs @@ -117,5 +117,10 @@ namespace NCC.Extend.Entitys.Dto.LqTkjlb /// 是否开卡(是/否) /// public string hasBilling { get; set; } + + /// + /// 会员ID(内部使用,不返回给前端) + /// + public string memberId { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhPxmx/ConsumeItemDetailListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhPxmx/ConsumeItemDetailListQueryInput.cs index 43db838..818a9ac 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhPxmx/ConsumeItemDetailListQueryInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhPxmx/ConsumeItemDetailListQueryInput.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using NCC.Common.Filter; namespace NCC.Extend.Entitys.Dto.LqXhPxmx @@ -73,9 +74,14 @@ namespace NCC.Extend.Entitys.Dto.LqXhPxmx public string SourceType { get; set; } /// - /// 门店ID + /// 门店ID(单门店,兼容旧版本) /// public string StoreId { get; set; } + + /// + /// 门店ID列表(多门店筛选) + /// + public List StoreIds { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs index dd3945d..fc116f1 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs @@ -99,6 +99,7 @@ namespace NCC.Extend /// 返回说明: /// - StoreId: 门店ID /// - StoreName: 门店名称 + /// - EmployeeCount: 在职人数 /// - HeadCount: 人头数(去重后的消费会员数) /// - PersonCount: 人次(日度去重客户数,同一天同一客户只算一次) /// - ProjectCount: 项目数(消耗的项目总数,从品项明细表统计) @@ -134,6 +135,8 @@ namespace NCC.Extend SELECT consume.Md as StoreId, MAX(store.dm) as StoreName, + -- 在职人数(从门店表获取) + MAX(COALESCE(store.zzrs, 0)) as EmployeeCount, -- 人头数(去重后的消费会员数) COALESCE(COUNT(DISTINCT consume.Hy), 0) as HeadCount, -- 人次(日度去重客户数) @@ -185,6 +188,7 @@ namespace NCC.Extend { StoreId = item.StoreId, StoreName = item.StoreName, + EmployeeCount = Convert.ToInt32(item.EmployeeCount ?? 0), HeadCount = Convert.ToInt32(item.HeadCount), PersonCount = Convert.ToInt32(item.PersonCount), ProjectCount = Convert.ToInt32(item.ProjectCount), diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs index 83e31e8..a8e9a82 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs @@ -3635,10 +3635,25 @@ namespace NCC.Extend.LqKdKdjlb parameters.Add(new SugarParameter("@departmentId", input.DepartmentId)); } - if (!string.IsNullOrEmpty(input.StoreId)) + // 处理多门店筛选:优先使用StoreIds,如果没有则使用StoreId + var storeIds = new List(); + if (input.StoreIds != null && input.StoreIds.Any()) { - conditions.Add("u.F_MDID = @storeId"); - parameters.Add(new SugarParameter("@storeId", input.StoreId)); + storeIds = input.StoreIds.Where(x => !string.IsNullOrEmpty(x)).ToList(); + } + else if (!string.IsNullOrEmpty(input.StoreId)) + { + storeIds = new List { input.StoreId }; + } + + if (storeIds.Any()) + { + var storeIdParams = string.Join(",", storeIds.Select((_, i) => $"@storeId{i}")); + conditions.Add($"u.F_MDID IN ({storeIdParams})"); + for (int i = 0; i < storeIds.Count; i++) + { + parameters.Add(new SugarParameter($"@storeId{i}", storeIds[i])); + } } if (!string.IsNullOrEmpty(input.EmployeeName)) @@ -3839,9 +3854,20 @@ namespace NCC.Extend.LqKdKdjlb .WhereIF(!string.IsNullOrEmpty(input.ItemType), pxmx => pxmx.ItemCategory == input.ItemType); // 2. 通过 EXISTS 子查询筛选关联字段(在分页前筛选,确保分页准确) + // 处理多门店筛选:优先使用StoreIds,如果没有则使用StoreId + var filterStoreIds = new List(); + if (input.StoreIds != null && input.StoreIds.Any()) + { + filterStoreIds = input.StoreIds.Where(x => !string.IsNullOrEmpty(x)).ToList(); + } + else if (!string.IsNullOrEmpty(input.StoreId)) + { + filterStoreIds = new List { input.StoreId }; + } + baseQuery = baseQuery.WhereIF(!string.IsNullOrEmpty(input.MemberName), pxmx => SqlFunc.Subqueryable().Where(x => x.Id == pxmx.MemberId && x.Khmc != null && x.Khmc.Contains(input.MemberName)).Any()) .WhereIF(!string.IsNullOrEmpty(input.MemberPhone), pxmx => SqlFunc.Subqueryable().Where(x => x.Id == pxmx.MemberId && x.Sjh == input.MemberPhone).Any()) - .WhereIF(!string.IsNullOrEmpty(input.StoreId), pxmx => SqlFunc.Subqueryable().Where(x => x.Id == pxmx.Glkdbh && x.Djmd == input.StoreId).Any()); + .WhereIF(filterStoreIds.Any(), pxmx => SqlFunc.Subqueryable().Where(x => x.Id == pxmx.Glkdbh && filterStoreIds.Contains(x.Djmd)).Any()); // 3. 先分页查询主表数据(查询实体类,提高性能) var pagedData = await baseQuery.OrderBy(sidx + " " + sort).ToPagedListAsync(input.currentPage, input.pageSize); diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs index 9fba079..6fbeb1a 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs @@ -1145,7 +1145,18 @@ namespace NCC.Extend.LqKhxx } // 如果指定了开单门店、开单人、品项ID等条件,需要通过开单表进行筛选 - if (!string.IsNullOrEmpty(input.BillingStoreId) || + // 处理多门店筛选:优先使用BillingStoreIds,如果没有则使用BillingStoreId + var billingStoreIds = new List(); + if (input.BillingStoreIds != null && input.BillingStoreIds.Any()) + { + billingStoreIds = input.BillingStoreIds.Where(x => !string.IsNullOrEmpty(x)).ToList(); + } + else if (!string.IsNullOrEmpty(input.BillingStoreId)) + { + billingStoreIds = new List { input.BillingStoreId }; + } + + if (billingStoreIds.Any() || !string.IsNullOrEmpty(input.BillingUserId) || !string.IsNullOrEmpty(input.PurchaseItemId) || !string.IsNullOrEmpty(input.GiftItemId) || @@ -1155,9 +1166,9 @@ namespace NCC.Extend.LqKhxx var billingQuery = _db.Queryable() .Where(x => x.IsEffective == StatusEnum.有效.GetHashCode()); - if (!string.IsNullOrEmpty(input.BillingStoreId)) + if (billingStoreIds.Any()) { - billingQuery = billingQuery.Where(x => x.Djmd == input.BillingStoreId); + billingQuery = billingQuery.Where(x => billingStoreIds.Contains(x.Djmd)); } if (!string.IsNullOrEmpty(input.BillingUserId)) diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqReportService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqReportService.cs index 7b0bdad..e5e9391 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqReportService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqReportService.cs @@ -503,7 +503,7 @@ namespace NCC.Extend /// - TopAmountMemberName: 开单金额最高会员姓名 /// - TopAmountValue: 该会员整月实付金额 /// - TopTimesMemberName: 开单次数最多会员姓名 - /// - TopTimesCount: 该会员整月开单次数 + /// - TopTimesCount: 该会员整月开单次数(按天去重,同一天多次开单只算一次) /// - DebtTotal: 整月欠款总额(sfyj+ck金额以外的qk累加) /// - TopDebtMemberName: 欠款最多会员姓名 /// - TopDebtValue: 欠款最多会员的欠款金额 @@ -598,15 +598,16 @@ namespace NCC.Extend .OrderBy(x => x.Date) .ToList(); - // 3. 会员极值:按会员聚合金额和次数 + // 3. 会员极值:按会员聚合金额和次数(开单次数按天去重) var memberAgg = rawList - .Where(x => !string.IsNullOrEmpty(x.MemberId)) - .GroupBy(x => x.MemberId) + .Where(x => !string.IsNullOrEmpty(x.MemberId) && x.BillingDate.HasValue) + .GroupBy(x => new { x.MemberId, Date = x.BillingDate.Value.Date }) + .GroupBy(g => g.Key.MemberId) .Select(g => new { MemberId = g.Key, - Amount = g.Sum(x => x.Amount), - Times = g.Count() + Amount = g.SelectMany(dayGroup => dayGroup).Sum(x => x.Amount), + Times = g.Count() // 按天去重后的开单天数 }) .ToList(); diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs index 4fc9207..852f32f 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs @@ -4898,6 +4898,7 @@ namespace NCC.Extend.LqStatistics ) xh_stats ON xh_stats.member_id = tk.F_MemberId -- 开单统计子查询(只统计通过预约产生的开单,包含金额和品项) -- 通过会员ID关联:线索池 -> 邀约 -> 预约 -> 开单(通过预约ID,且会员ID匹配) + -- 注意:剔除品项ID是61且金额是0的记录 LEFT JOIN ( SELECT tk_inner.F_MemberId as member_id, @@ -4908,7 +4909,14 @@ namespace NCC.Extend.LqStatistics INNER JOIN lq_yaoyjl yaoy ON yaoy.yykh = tk_inner.F_MemberId INNER JOIN lq_yyjl yy ON yy.F_InviteId = yaoy.F_Id AND yy.gk = tk_inner.F_MemberId INNER JOIN lq_kd_kdjlb kd ON kd.F_AppointmentId = yy.F_Id AND kd.kdhy = tk_inner.F_MemberId AND kd.F_IsEffective = 1 + INNER JOIN ( + SELECT DISTINCT glkdbh + FROM lq_kd_pxmx + WHERE F_IsEffective = 1 + AND NOT (px = '61' AND (COALESCE(F_ActualPrice, 0) = 0 AND COALESCE(F_TotalPrice, 0) = 0)) + ) valid_px ON valid_px.glkdbh = kd.F_Id LEFT JOIN lq_kd_pxmx kdpx ON kdpx.glkdbh = kd.F_Id AND kdpx.F_IsEffective = 1 + AND NOT (kdpx.px = '61' AND (COALESCE(kdpx.F_ActualPrice, 0) = 0 AND COALESCE(kdpx.F_TotalPrice, 0) = 0)) GROUP BY tk_inner.F_MemberId ) kd_stats ON kd_stats.member_id = tk.F_MemberId -- 实际预约记录数统计(不管是否通过邀约产生) @@ -5229,6 +5237,7 @@ namespace NCC.Extend.LqStatistics ) xh_stats ON xh_stats.member_id = tk.F_MemberId -- 开单统计子查询(只统计通过预约产生的开单,包含金额和品项) -- 通过会员ID关联:线索池 -> 邀约 -> 预约 -> 开单(通过预约ID,且会员ID匹配) + -- 注意:剔除品项ID是61且金额是0的记录 LEFT JOIN ( SELECT tk_inner.F_MemberId as member_id, @@ -5239,7 +5248,14 @@ namespace NCC.Extend.LqStatistics INNER JOIN lq_yaoyjl yaoy ON yaoy.yykh = tk_inner.F_MemberId INNER JOIN lq_yyjl yy ON yy.F_InviteId = yaoy.F_Id AND yy.gk = tk_inner.F_MemberId INNER JOIN lq_kd_kdjlb kd ON kd.F_AppointmentId = yy.F_Id AND kd.kdhy = tk_inner.F_MemberId AND kd.F_IsEffective = 1 + INNER JOIN ( + SELECT DISTINCT glkdbh + FROM lq_kd_pxmx + WHERE F_IsEffective = 1 + AND NOT (px = '61' AND (COALESCE(F_ActualPrice, 0) = 0 AND COALESCE(F_TotalPrice, 0) = 0)) + ) valid_px ON valid_px.glkdbh = kd.F_Id LEFT JOIN lq_kd_pxmx kdpx ON kdpx.glkdbh = kd.F_Id AND kdpx.F_IsEffective = 1 + AND NOT (kdpx.px = '61' AND (COALESCE(kdpx.F_ActualPrice, 0) = 0 AND COALESCE(kdpx.F_TotalPrice, 0) = 0)) GROUP BY tk_inner.F_MemberId ) kd_stats ON kd_stats.member_id = tk.F_MemberId -- 实际预约记录数统计(不管是否通过邀约产生) @@ -5703,6 +5719,17 @@ namespace NCC.Extend.LqStatistics } } + // 添加多门店筛选 + if (input.StoreIds != null && input.StoreIds.Any()) + { + var storeIdParams = string.Join(",", input.StoreIds.Select((_, i) => $"@StoreId{i}")); + whereConditions.Add($"kd.Djmd IN ({storeIdParams})"); + for (int i = 0; i < input.StoreIds.Count; i++) + { + parameters.Add(new SugarParameter($"@StoreId{i}", input.StoreIds[i])); + } + } + var whereClause = whereConditions.Any() ? "AND " + string.Join(" AND ", whereConditions) : ""; // 构建HAVING条件(用于筛选升单条件) diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs index 4b7e68b..b1a80b6 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs @@ -147,12 +147,70 @@ namespace NCC.Extend.LqTkjlb hasAppointment = SqlFunc.Subqueryable().Where(y => y.Gk == it.MemberId).Any() ? "是" : "否", // 是否消耗:通过会员ID关联耗卡表(hy字段存储的是会员ID) hasConsume = SqlFunc.Subqueryable().Where(x => x.Hy == it.MemberId).Any() ? "是" : "否", - // 是否开卡:通过会员ID关联开单表(kdhy字段存储的是会员ID) - hasBilling = SqlFunc.Subqueryable().Where(k => k.Kdhy == it.MemberId).Any() ? "是" : "否" + // 是否开卡:通过会员ID关联开单表(kdhy字段存储的是会员ID),剔除品项ID是61(女神卡)且金额是0的记录 + // 先设置为否,后面在内存中处理 + hasBilling = "否" }) .MergeTable() .OrderBy(sidx + " " + input.sort) .ToPagedListAsync(input.currentPage, input.pageSize); + + // 批量查询有有效开单的会员ID(剔除品项ID是61且金额是0的记录) + // 先查询所有拓客记录的会员ID + var tkIds = data.list?.Select(x => x.id).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList() ?? new List(); + var memberIdDict = new Dictionary(); // tkId -> MemberId + + if (tkIds.Any()) + { + // 查询拓客记录的会员ID + var tkMembers = await _db.Queryable() + .Where(x => tkIds.Contains(x.Id)) + .Select(x => new { x.Id, x.MemberId }) + .ToListAsync(); + memberIdDict = tkMembers?.Where(x => !string.IsNullOrEmpty(x.MemberId)) + .ToDictionary(x => x.Id, x => x.MemberId) ?? new Dictionary(); + } + + var memberIds = memberIdDict.Values.Distinct().ToList(); + var hasBillingMemberIds = new HashSet(); + + if (memberIds.Any()) + { + var sql = $@" + SELECT DISTINCT kd.kdhy as MemberId + FROM lq_kd_kdjlb kd + INNER JOIN ( + SELECT DISTINCT glkdbh + FROM lq_kd_pxmx + WHERE F_IsEffective = 1 + AND NOT (px = '61' AND (COALESCE(F_ActualPrice, 0) = 0 AND COALESCE(F_TotalPrice, 0) = 0)) + ) valid_px ON valid_px.glkdbh = kd.F_Id + WHERE kd.F_IsEffective = 1 + AND kd.kdhy IN ('{string.Join("','", memberIds)}')"; + var billingMembers = await _db.Ado.SqlQueryAsync(sql); + if (billingMembers != null) + { + var memberIdList = billingMembers.Select(x => x.MemberId?.ToString()).Where(x => !string.IsNullOrEmpty(x)).Cast().ToList(); + hasBillingMemberIds = new HashSet(memberIdList); + } + } + + // 更新hasBilling字段 + if (data.list != null) + { + foreach (var item in data.list) + { + if (memberIdDict.TryGetValue(item.id, out var memberId) && !string.IsNullOrEmpty(memberId)) + { + item.hasBilling = hasBillingMemberIds.Contains(memberId) ? "是" : "否"; + } + else + { + item.hasBilling = "否"; + } + } + } + return PageResult.SqlSugarPageResult(data); } #endregion diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs index 8554c6d..5c86c91 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs @@ -2036,9 +2036,20 @@ namespace NCC.Extend.LqXhHyhk .WhereIF(!string.IsNullOrEmpty(input.ItemType), pxmx => pxmx.ItemCategory == input.ItemType); // 2. 通过 EXISTS 子查询筛选关联字段(在分页前筛选,确保分页准确) + // 处理多门店筛选:优先使用StoreIds,如果没有则使用StoreId + var filterStoreIds = new List(); + if (input.StoreIds != null && input.StoreIds.Any()) + { + filterStoreIds = input.StoreIds.Where(x => !string.IsNullOrEmpty(x)).ToList(); + } + else if (!string.IsNullOrEmpty(input.StoreId)) + { + filterStoreIds = new List { input.StoreId }; + } + baseQuery = baseQuery.WhereIF(!string.IsNullOrEmpty(input.MemberName), pxmx => SqlFunc.Subqueryable().Where(x => x.Id == pxmx.MemberId && x.Khmc != null && x.Khmc.Contains(input.MemberName)).Any()) .WhereIF(!string.IsNullOrEmpty(input.MemberPhone), pxmx => SqlFunc.Subqueryable().Where(x => x.Id == pxmx.MemberId && x.Sjh == input.MemberPhone).Any()) - .WhereIF(!string.IsNullOrEmpty(input.StoreId), pxmx => SqlFunc.Subqueryable().Where(x => x.Id == pxmx.ConsumeInfoId && x.Md == input.StoreId).Any()); + .WhereIF(filterStoreIds.Any(), pxmx => SqlFunc.Subqueryable().Where(x => x.Id == pxmx.ConsumeInfoId && filterStoreIds.Contains(x.Md)).Any()); // 3. 先分页查询主表数据(查询实体类,提高性能) var pagedData = await baseQuery.OrderBy(sidx + " " + sort).ToPagedListAsync(input.currentPage, input.pageSize);