Commit 65e1ea9f1c805734dfb2964db4c4a45b43d81d38

Authored by “wangming”
1 parent b08c5340

fix: 修复员工业绩统计和人次统计逻辑

主要变更:
1. 修复人次统计逻辑,改为使用客户ID和日期的组合去重(COUNT(DISTINCT CONCAT(hy, '-', DATE(hksj))))
2. 新增员工业绩统计接口GetEmployeePerformanceStatistics,支持查询员工在指定月份的完整业绩数据
3. 修复品项统计的门店过滤问题,使用SqlFunc.Subqueryable避免别名冲突
4. 修复门店顾客详情SQL字段错误(F_Status改为yysj,F_CreateTime改为kdrq/hksj)
5. 新增员工业绩统计输入输出DTO类

功能特性:
- 支持查询员工的拓客、邀约、预约、开单、消耗、退卡、人头、人次等完整统计
- 所有SQL改为字符串拼接方式,确保参数正确传递
- 分步统计设计,便于维护和优化
antis-ncc-admin/.env.development
@@ -2,6 +2,6 @@ @@ -2,6 +2,6 @@
2 2
3 VUE_CLI_BABEL_TRANSPILE_MODULES = true 3 VUE_CLI_BABEL_TRANSPILE_MODULES = true
4 # VUE_APP_BASE_API = 'http://lvqian.antissoft.com' 4 # VUE_APP_BASE_API = 'http://lvqian.antissoft.com'
5 -VUE_APP_BASE_API = 'http://erp_test.lvqianmeiye.com'  
6 -# VUE_APP_BASE_API = 'http://localhost:2011' 5 +# VUE_APP_BASE_API = 'http://erp_test.lvqianmeiye.com'
  6 +VUE_APP_BASE_API = 'http://localhost:2011'
7 VUE_APP_BASE_WSS = 'ws://192.168.110.45:2011/websocket' 7 VUE_APP_BASE_WSS = 'ws://192.168.110.45:2011/websocket'
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListOutput.cs
@@ -10,91 +10,91 @@ namespace NCC.Extend.Entitys.Dto.LqInventoryUsage @@ -10,91 +10,91 @@ namespace NCC.Extend.Entitys.Dto.LqInventoryUsage
10 /// <summary> 10 /// <summary>
11 /// 使用记录ID 11 /// 使用记录ID
12 /// </summary> 12 /// </summary>
13 - public string Id { get; set; } 13 + public string id { get; set; }
14 14
15 /// <summary> 15 /// <summary>
16 /// 产品ID 16 /// 产品ID
17 /// </summary> 17 /// </summary>
18 - public string ProductId { get; set; } 18 + public string productId { get; set; }
19 19
20 /// <summary> 20 /// <summary>
21 /// 产品名称 21 /// 产品名称
22 /// </summary> 22 /// </summary>
23 - public string ProductName { get; set; } 23 + public string productName { get; set; }
24 24
25 /// <summary> 25 /// <summary>
26 /// 产品类别 26 /// 产品类别
27 /// </summary> 27 /// </summary>
28 - public string ProductCategory { get; set; } 28 + public string productCategory { get; set; }
29 29
30 /// <summary> 30 /// <summary>
31 /// 产品价格 31 /// 产品价格
32 /// </summary> 32 /// </summary>
33 - public decimal ProductPrice { get; set; } 33 + public decimal productPrice { get; set; }
34 34
35 /// <summary> 35 /// <summary>
36 /// 门店ID 36 /// 门店ID
37 /// </summary> 37 /// </summary>
38 - public string StoreId { get; set; } 38 + public string storeId { get; set; }
39 39
40 /// <summary> 40 /// <summary>
41 /// 门店名称 41 /// 门店名称
42 /// </summary> 42 /// </summary>
43 - public string StoreName { get; set; } 43 + public string storeName { get; set; }
44 44
45 /// <summary> 45 /// <summary>
46 /// 使用时间 46 /// 使用时间
47 /// </summary> 47 /// </summary>
48 - public DateTime UsageTime { get; set; } 48 + public DateTime usageTime { get; set; }
49 49
50 /// <summary> 50 /// <summary>
51 /// 使用数量 51 /// 使用数量
52 /// </summary> 52 /// </summary>
53 - public int UsageQuantity { get; set; } 53 + public int usageQuantity { get; set; }
54 54
55 /// <summary> 55 /// <summary>
56 /// 关联消耗ID 56 /// 关联消耗ID
57 /// </summary> 57 /// </summary>
58 - public string RelatedConsumeId { get; set; } 58 + public string relatedConsumeId { get; set; }
59 59
60 /// <summary> 60 /// <summary>
61 /// 创建人ID 61 /// 创建人ID
62 /// </summary> 62 /// </summary>
63 - public string CreateUser { get; set; } 63 + public string createUser { get; set; }
64 64
65 /// <summary> 65 /// <summary>
66 /// 创建人姓名 66 /// 创建人姓名
67 /// </summary> 67 /// </summary>
68 - public string CreateUserName { get; set; } 68 + public string createUserName { get; set; }
69 69
70 /// <summary> 70 /// <summary>
71 /// 创建时间 71 /// 创建时间
72 /// </summary> 72 /// </summary>
73 - public DateTime CreateTime { get; set; } 73 + public DateTime createTime { get; set; }
74 74
75 /// <summary> 75 /// <summary>
76 /// 更新人ID 76 /// 更新人ID
77 /// </summary> 77 /// </summary>
78 - public string UpdateUser { get; set; } 78 + public string updateUser { get; set; }
79 79
80 /// <summary> 80 /// <summary>
81 /// 更新人姓名 81 /// 更新人姓名
82 /// </summary> 82 /// </summary>
83 - public string UpdateUserName { get; set; } 83 + public string updateUserName { get; set; }
84 84
85 /// <summary> 85 /// <summary>
86 /// 更新时间 86 /// 更新时间
87 /// </summary> 87 /// </summary>
88 - public DateTime? UpdateTime { get; set; } 88 + public DateTime? updateTime { get; set; }
89 89
90 /// <summary> 90 /// <summary>
91 /// 是否有效(1:有效 0:无效) 91 /// 是否有效(1:有效 0:无效)
92 /// </summary> 92 /// </summary>
93 - public int IsEffective { get; set; } 93 + public int isEffective { get; set; }
94 94
95 /// <summary> 95 /// <summary>
96 /// 使用总价值 96 /// 使用总价值
97 /// </summary> 97 /// </summary>
98 - public decimal UsageTotalValue { get; set; } 98 + public decimal usageTotalValue { get; set; }
99 } 99 }
100 } 100 }
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/EmployeePerformanceStatisticsInput.cs 0 → 100644
  1 +using System.ComponentModel.DataAnnotations;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.LqStatistics
  4 +{
  5 + /// <summary>
  6 + /// 员工业绩统计查询输入参数
  7 + /// </summary>
  8 + public class EmployeePerformanceStatisticsInput
  9 + {
  10 + /// <summary>
  11 + /// 员工ID(必填)
  12 + /// </summary>
  13 + [Required(ErrorMessage = "员工ID不能为空")]
  14 + public string UserId { get; set; }
  15 +
  16 + /// <summary>
  17 + /// 统计月份(格式:YYYYMM,如202510)
  18 + /// </summary>
  19 + [Required(ErrorMessage = "统计月份不能为空")]
  20 + public string StatisticsMonth { get; set; }
  21 + }
  22 +}
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/EmployeePerformanceStatisticsOutput.cs 0 → 100644
  1 +namespace NCC.Extend.Entitys.Dto.LqStatistics
  2 +{
  3 + /// <summary>
  4 + /// 员工业绩统计数据输出
  5 + /// </summary>
  6 + public class EmployeePerformanceStatisticsOutput
  7 + {
  8 + /// <summary>
  9 + /// 员工ID
  10 + /// </summary>
  11 + public string UserId { get; set; }
  12 +
  13 + /// <summary>
  14 + /// 统计月份
  15 + /// </summary>
  16 + public string StatisticsMonth { get; set; }
  17 +
  18 + /// <summary>
  19 + /// 拓客人数
  20 + /// </summary>
  21 + public int InvitationCount { get; set; }
  22 +
  23 + /// <summary>
  24 + /// 邀约人数
  25 + /// </summary>
  26 + public int InviteCount { get; set; }
  27 +
  28 + /// <summary>
  29 + /// 预约人数
  30 + /// </summary>
  31 + public int AppointmentCount { get; set; }
  32 +
  33 + /// <summary>
  34 + /// 开单数量
  35 + /// </summary>
  36 + public int BillingCount { get; set; }
  37 +
  38 + /// <summary>
  39 + /// 开单金额
  40 + /// </summary>
  41 + public decimal BillingAmount { get; set; }
  42 +
  43 + /// <summary>
  44 + /// 消耗数量
  45 + /// </summary>
  46 + public int ConsumeCount { get; set; }
  47 +
  48 + /// <summary>
  49 + /// 消耗金额
  50 + /// </summary>
  51 + public decimal ConsumeAmount { get; set; }
  52 +
  53 + /// <summary>
  54 + /// 退卡数量
  55 + /// </summary>
  56 + public int RefundCount { get; set; }
  57 +
  58 + /// <summary>
  59 + /// 退卡金额
  60 + /// </summary>
  61 + public decimal RefundAmount { get; set; }
  62 +
  63 + /// <summary>
  64 + /// 人头(月度去重客户数)
  65 + /// </summary>
  66 + public int HeadCount { get; set; }
  67 +
  68 + /// <summary>
  69 + /// 人次(日度去重客户数)
  70 + /// </summary>
  71 + public int PersonCount { get; set; }
  72 + }
  73 +}
netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs
@@ -12,6 +12,7 @@ using NCC.Extend.Entitys.Dto.LqInventoryUsage; @@ -12,6 +12,7 @@ using NCC.Extend.Entitys.Dto.LqInventoryUsage;
12 using NCC.Extend.Entitys.Enum; 12 using NCC.Extend.Entitys.Enum;
13 using NCC.Extend.Entitys.lq_inventory; 13 using NCC.Extend.Entitys.lq_inventory;
14 using NCC.Extend.Entitys.lq_inventory_usage; 14 using NCC.Extend.Entitys.lq_inventory_usage;
  15 +using NCC.Extend.Entitys.lq_mdxx;
15 using NCC.Extend.Interfaces.LqInventoryUsage; 16 using NCC.Extend.Interfaces.LqInventoryUsage;
16 using NCC.FriendlyException; 17 using NCC.FriendlyException;
17 using NCC.System.Entitys.Permission; 18 using NCC.System.Entitys.Permission;
@@ -184,23 +185,23 @@ namespace NCC.Extend @@ -184,23 +185,23 @@ namespace NCC.Extend
184 .WhereIF(input.IsEffective.HasValue, x => x.IsEffective == input.IsEffective.Value) 185 .WhereIF(input.IsEffective.HasValue, x => x.IsEffective == input.IsEffective.Value)
185 .Select(x => new LqInventoryUsageListOutput 186 .Select(x => new LqInventoryUsageListOutput
186 { 187 {
187 - Id = x.Id,  
188 - ProductId = x.ProductId,  
189 - ProductName = "",  
190 - ProductCategory = "",  
191 - ProductPrice = 0,  
192 - StoreId = x.StoreId,  
193 - StoreName = "",  
194 - UsageTime = x.UsageTime,  
195 - UsageQuantity = x.UsageQuantity,  
196 - RelatedConsumeId = x.RelatedConsumeId,  
197 - CreateUser = x.CreateUser,  
198 - CreateUserName = "",  
199 - CreateTime = x.CreateTime,  
200 - UpdateUser = x.UpdateUser,  
201 - UpdateUserName = "",  
202 - UpdateTime = x.UpdateTime,  
203 - IsEffective = x.IsEffective 188 + id = x.Id,
  189 + productId = x.ProductId,
  190 + productName = "",
  191 + productCategory = "",
  192 + productPrice = 0,
  193 + storeId = x.StoreId,
  194 + storeName = SqlFunc.Subqueryable<LqMdxxEntity>().Where(u => u.Id == x.StoreId).Select(u => u.Dm),
  195 + usageTime = x.UsageTime,
  196 + usageQuantity = x.UsageQuantity,
  197 + relatedConsumeId = x.RelatedConsumeId,
  198 + createUser = x.CreateUser,
  199 + createUserName = "",
  200 + createTime = x.CreateTime,
  201 + updateUser = x.UpdateUser,
  202 + updateUserName = "",
  203 + updateTime = x.UpdateTime,
  204 + isEffective = x.IsEffective
204 }) 205 })
205 .MergeTable() 206 .MergeTable()
206 .OrderBy(sidx + " " + input.sort) 207 .OrderBy(sidx + " " + input.sort)
@@ -209,30 +210,30 @@ namespace NCC.Extend @@ -209,30 +210,30 @@ namespace NCC.Extend
209 // 补充产品信息和用户信息 210 // 补充产品信息和用户信息
210 foreach (var item in data.list) 211 foreach (var item in data.list)
211 { 212 {
212 - if (!string.IsNullOrEmpty(item.ProductId)) 213 + if (!string.IsNullOrEmpty(item.productId))
213 { 214 {
214 - var product = await _db.Queryable<LqInventoryEntity>().Where(p => p.Id == item.ProductId).FirstAsync(); 215 + var product = await _db.Queryable<LqInventoryEntity>().Where(p => p.Id == item.productId).FirstAsync();
215 if (product != null) 216 if (product != null)
216 { 217 {
217 - item.ProductName = product.ProductName;  
218 - item.ProductCategory = product.ProductCategory;  
219 - item.ProductPrice = product.Price; 218 + item.productName = product.ProductName;
  219 + item.productCategory = product.ProductCategory;
  220 + item.productPrice = product.Price;
220 } 221 }
221 } 222 }
222 - if (!string.IsNullOrEmpty(item.StoreId)) 223 + if (!string.IsNullOrEmpty(item.storeId))
223 { 224 {
224 - var store = await _db.Queryable<UserEntity>().Where(u => u.Id == item.StoreId).FirstAsync();  
225 - item.StoreName = store?.RealName ?? ""; 225 + var store = await _db.Queryable<UserEntity>().Where(u => u.Id == item.storeId).FirstAsync();
  226 + item.storeName = store?.RealName ?? "";
226 } 227 }
227 - if (!string.IsNullOrEmpty(item.CreateUser)) 228 + if (!string.IsNullOrEmpty(item.createUser))
228 { 229 {
229 - var createUser = await _db.Queryable<UserEntity>().Where(u => u.Id == item.CreateUser).FirstAsync();  
230 - item.CreateUserName = createUser?.RealName ?? ""; 230 + var createUser = await _db.Queryable<UserEntity>().Where(u => u.Id == item.createUser).FirstAsync();
  231 + item.createUserName = createUser?.RealName ?? "";
231 } 232 }
232 - if (!string.IsNullOrEmpty(item.UpdateUser)) 233 + if (!string.IsNullOrEmpty(item.updateUser))
233 { 234 {
234 - var updateUser = await _db.Queryable<UserEntity>().Where(u => u.Id == item.UpdateUser).FirstAsync();  
235 - item.UpdateUserName = updateUser?.RealName ?? ""; 235 + var updateUser = await _db.Queryable<UserEntity>().Where(u => u.Id == item.updateUser).FirstAsync();
  236 + item.updateUserName = updateUser?.RealName ?? "";
236 } 237 }
237 } 238 }
238 239
@@ -240,15 +241,15 @@ namespace NCC.Extend @@ -240,15 +241,15 @@ namespace NCC.Extend
240 if (!string.IsNullOrWhiteSpace(input.ProductName) || !string.IsNullOrWhiteSpace(input.ProductCategory)) 241 if (!string.IsNullOrWhiteSpace(input.ProductName) || !string.IsNullOrWhiteSpace(input.ProductCategory))
241 { 242 {
242 data.list = data.list.Where(x => 243 data.list = data.list.Where(x =>
243 - (string.IsNullOrWhiteSpace(input.ProductName) || x.ProductName.Contains(input.ProductName)) &&  
244 - (string.IsNullOrWhiteSpace(input.ProductCategory) || x.ProductCategory.Contains(input.ProductCategory)) 244 + (string.IsNullOrWhiteSpace(input.ProductName) || x.productName.Contains(input.ProductName)) &&
  245 + (string.IsNullOrWhiteSpace(input.ProductCategory) || x.productCategory.Contains(input.ProductCategory))
245 ).ToList(); 246 ).ToList();
246 } 247 }
247 248
248 // 应用门店名称的过滤条件 249 // 应用门店名称的过滤条件
249 if (!string.IsNullOrWhiteSpace(input.StoreName)) 250 if (!string.IsNullOrWhiteSpace(input.StoreName))
250 { 251 {
251 - data.list = data.list.Where(x => x.StoreName.Contains(input.StoreName)).ToList(); 252 + data.list = data.list.Where(x => x.storeName.Contains(input.StoreName)).ToList();
252 } 253 }
253 return PageResult<LqInventoryUsageListOutput>.SqlSugarPageResult(data); 254 return PageResult<LqInventoryUsageListOutput>.SqlSugarPageResult(data);
254 } 255 }
netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs
@@ -2247,11 +2247,11 @@ namespace NCC.Extend.LqStatistics @@ -2247,11 +2247,11 @@ namespace NCC.Extend.LqStatistics
2247 GROUP BY jksyj.jkszh, hyhk.md 2247 GROUP BY jksyj.jkszh, hyhk.md
2248 ) headcount_stats ON jksyj.jkszh = headcount_stats.jkszh AND hyhk.md = headcount_stats.md 2248 ) headcount_stats ON jksyj.jkszh = headcount_stats.jkszh AND hyhk.md = headcount_stats.md
2249 LEFT JOIN ( 2249 LEFT JOIN (
2250 - -- 人次统计:日度去重到店数 2250 + -- 人次统计:日度去重客户数(每天同一个客户只算一次)
2251 SELECT 2251 SELECT
2252 jksyj.jkszh, 2252 jksyj.jkszh,
2253 hyhk.md, 2253 hyhk.md,
2254 - COUNT(DISTINCT DATE(hyhk.hksj)) as F_PersonCount 2254 + COUNT(DISTINCT CONCAT(hyhk.hy, '-', DATE(hyhk.hksj))) as F_PersonCount
2255 FROM lq_xh_jksyj jksyj 2255 FROM lq_xh_jksyj jksyj
2256 INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id AND hyhk.F_IsEffective = 1 2256 INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id AND hyhk.F_IsEffective = 1
2257 WHERE jksyj.F_IsEffective = 1 2257 WHERE jksyj.F_IsEffective = 1
@@ -3382,5 +3382,250 @@ namespace NCC.Extend.LqStatistics @@ -3382,5 +3382,250 @@ namespace NCC.Extend.LqStatistics
3382 3382
3383 #endregion 3383 #endregion
3384 3384
  3385 + #region 员工业绩统计
  3386 +
  3387 + /// <summary>
  3388 + /// 获取员工业绩统计数据
  3389 + /// </summary>
  3390 + /// <remarks>
  3391 + /// 根据员工ID和月份统计员工的完整业绩数据
  3392 + /// 包括:拓客人数、邀约人数、预约人数、开单、消耗、退卡、人头、人次
  3393 + ///
  3394 + /// 示例请求:
  3395 + /// ```json
  3396 + /// {
  3397 + /// "userId": "员工ID",
  3398 + /// "statisticsMonth": "202510"
  3399 + /// }
  3400 + /// ```
  3401 + ///
  3402 + /// 参数说明:
  3403 + /// - userId: 员工ID(必填)
  3404 + /// - statisticsMonth: 统计月份,格式YYYYMM(必填)
  3405 + ///
  3406 + /// 返回字段说明:
  3407 + /// - UserId: 员工ID
  3408 + /// - StatisticsMonth: 统计月份
  3409 + /// - InvitationCount: 拓客人数
  3410 + /// - InviteCount: 邀约人数
  3411 + /// - AppointmentCount: 预约人数
  3412 + /// - BillingCount: 开单数量
  3413 + /// - BillingAmount: 开单金额
  3414 + /// - ConsumeCount: 消耗数量
  3415 + /// - ConsumeAmount: 消耗金额
  3416 + /// - RefundCount: 退卡数量
  3417 + /// - RefundAmount: 退卡金额
  3418 + /// - HeadCount: 人头(月度去重客户数)
  3419 + /// - PersonCount: 人次(日度去重客户数)
  3420 + /// </remarks>
  3421 + /// <param name="input">查询参数</param>
  3422 + /// <returns>员工业绩统计数据</returns>
  3423 + /// <response code="200">成功返回统计数据</response>
  3424 + /// <response code="400">参数错误</response>
  3425 + /// <response code="500">服务器错误</response>
  3426 + [HttpPost("get-employee-performance-statistics")]
  3427 + public async Task<object> GetEmployeePerformanceStatistics(EmployeePerformanceStatisticsInput input)
  3428 + {
  3429 + try
  3430 + {
  3431 + if (input == null || string.IsNullOrEmpty(input.StatisticsMonth) || input.StatisticsMonth.Length != 6)
  3432 + {
  3433 + throw NCCException.Oh("统计月份格式错误,请使用YYYYMM格式");
  3434 + }
  3435 +
  3436 + var statisticsMonth = input.StatisticsMonth;
  3437 +
  3438 + // 分步统计,确保效率和可维护性
  3439 +
  3440 + // 1. 拓客人数统计
  3441 + var invitationCount = await GetInvitationCount(input.UserId, statisticsMonth);
  3442 +
  3443 + // 2. 邀约人数统计
  3444 + var inviteCount = await GetInviteCount(input.UserId, statisticsMonth);
  3445 +
  3446 + // 3. 预约人数统计
  3447 + var appointmentCount = await GetAppointmentCount(input.UserId, statisticsMonth);
  3448 +
  3449 + // 4. 开单统计(数量、金额)
  3450 + var billingStats = await GetBillingStats(input.UserId, statisticsMonth);
  3451 +
  3452 + // 5. 消耗统计(数量、金额)
  3453 + var consumeStats = await GetConsumeStats(input.UserId, statisticsMonth);
  3454 +
  3455 + // 6. 退卡统计(数量、金额)
  3456 + var refundStats = await GetRefundStats(input.UserId, statisticsMonth);
  3457 +
  3458 + // 7. 人头统计
  3459 + var headCount = await GetHeadCount(input.UserId, statisticsMonth);
  3460 +
  3461 + // 8. 人次统计
  3462 + var personCount = await GetPersonCount(input.UserId, statisticsMonth);
  3463 +
  3464 + return new EmployeePerformanceStatisticsOutput
  3465 + {
  3466 + UserId = input.UserId,
  3467 + StatisticsMonth = statisticsMonth,
  3468 + InvitationCount = invitationCount,
  3469 + InviteCount = inviteCount,
  3470 + AppointmentCount = appointmentCount,
  3471 + BillingCount = billingStats.Count,
  3472 + BillingAmount = billingStats.Amount,
  3473 + ConsumeCount = consumeStats.Count,
  3474 + ConsumeAmount = consumeStats.Amount,
  3475 + RefundCount = refundStats.Count,
  3476 + RefundAmount = refundStats.Amount,
  3477 + HeadCount = headCount,
  3478 + PersonCount = personCount
  3479 + };
  3480 + }
  3481 + catch (Exception ex)
  3482 + {
  3483 + _logger.LogError(ex, $"获取员工业绩统计数据失败 - 员工ID: {input?.UserId}, 月份: {input?.StatisticsMonth}");
  3484 + throw NCCException.Oh($"获取员工业绩统计数据失败: {ex.Message}");
  3485 + }
  3486 + }
  3487 +
  3488 + /// <summary>
  3489 + /// 统计拓客人数
  3490 + /// </summary>
  3491 + private async Task<int> GetInvitationCount(string userId, string month)
  3492 + {
  3493 + var sql = $@"
  3494 + SELECT COUNT(*) as Count
  3495 + FROM lq_tkjlb
  3496 + WHERE F_ExpansionUserId = '{userId}'
  3497 + AND DATE_FORMAT(F_ExpansionTime, '%Y%m') = '{month}'";
  3498 +
  3499 + var result = await _db.Ado.SqlQueryAsync<dynamic>(sql);
  3500 + return Convert.ToInt32(result.FirstOrDefault()?.Count ?? 0);
  3501 + }
  3502 +
  3503 + /// <summary>
  3504 + /// 统计邀约人数
  3505 + /// </summary>
  3506 + private async Task<int> GetInviteCount(string userId, string month)
  3507 + {
  3508 + var sql = $@"
  3509 + SELECT COUNT(DISTINCT yykh) as Count
  3510 + FROM lq_yaoyjl
  3511 + WHERE yyr = '{userId}'
  3512 + AND DATE_FORMAT(yysj, '%Y%m') = '{month}'";
  3513 +
  3514 + var result = await _db.Ado.SqlQueryAsync<dynamic>(sql);
  3515 + return Convert.ToInt32(result.FirstOrDefault()?.Count ?? 0);
  3516 + }
  3517 +
  3518 + /// <summary>
  3519 + /// 统计预约人数
  3520 + /// </summary>
  3521 + private async Task<int> GetAppointmentCount(string userId, string month)
  3522 + {
  3523 + var sql = $@"
  3524 + SELECT COUNT(DISTINCT gk) as Count
  3525 + FROM lq_yyjl
  3526 + WHERE yyr = '{userId}'
  3527 + AND DATE_FORMAT(F_CreateTime, '%Y%m') = '{month}'";
  3528 +
  3529 + var result = await _db.Ado.SqlQueryAsync<dynamic>(sql);
  3530 + return Convert.ToInt32(result.FirstOrDefault()?.Count ?? 0);
  3531 + }
  3532 +
  3533 + /// <summary>
  3534 + /// 统计开单(数量和金额)
  3535 + /// </summary>
  3536 + private async Task<(int Count, decimal Amount)> GetBillingStats(string userId, string month)
  3537 + {
  3538 + var sql = $@"
  3539 + SELECT
  3540 + COUNT(*) as Count,
  3541 + COALESCE(SUM(jksyj), 0) as Amount
  3542 + FROM lq_kd_jksyj
  3543 + WHERE jkszh = '{userId}'
  3544 + AND F_IsEffective = 1
  3545 + AND DATE_FORMAT(yjsj, '%Y%m') = '{month}'";
  3546 +
  3547 + var result = await _db.Ado.SqlQueryAsync<dynamic>(sql);
  3548 + var data = result.FirstOrDefault();
  3549 + return (Convert.ToInt32(data?.Count ?? 0), Convert.ToDecimal(data?.Amount ?? 0));
  3550 + }
  3551 +
  3552 + /// <summary>
  3553 + /// 统计消耗(数量和金额)
  3554 + /// </summary>
  3555 + private async Task<(int Count, decimal Amount)> GetConsumeStats(string userId, string month)
  3556 + {
  3557 + var sql = $@"
  3558 + SELECT
  3559 + COUNT(*) as Count,
  3560 + COALESCE(SUM(jksyj.jksyj), 0) as Amount
  3561 + FROM lq_xh_jksyj jksyj
  3562 + INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
  3563 + WHERE jksyj.jkszh = '{userId}'
  3564 + AND jksyj.F_IsEffective = 1
  3565 + AND hyhk.F_IsEffective = 1
  3566 + AND DATE_FORMAT(hyhk.hksj, '%Y%m') = '{month}'";
  3567 +
  3568 + var result = await _db.Ado.SqlQueryAsync<dynamic>(sql);
  3569 + var data = result.FirstOrDefault();
  3570 + return (Convert.ToInt32(data?.Count ?? 0), Convert.ToDecimal(data?.Amount ?? 0));
  3571 + }
  3572 +
  3573 + /// <summary>
  3574 + /// 统计退卡(数量和金额)
  3575 + /// </summary>
  3576 + private async Task<(int Count, decimal Amount)> GetRefundStats(string userId, string month)
  3577 + {
  3578 + var sql = $@"
  3579 + SELECT
  3580 + COUNT(*) as Count,
  3581 + COALESCE(SUM(jksyj), 0) as Amount
  3582 + FROM lq_hytk_jksyj
  3583 + WHERE jkszh = '{userId}'
  3584 + AND F_IsEffective = 1
  3585 + AND DATE_FORMAT(tksj, '%Y%m') = '{month}'";
  3586 +
  3587 + var result = await _db.Ado.SqlQueryAsync<dynamic>(sql);
  3588 + var data = result.FirstOrDefault();
  3589 + return (Convert.ToInt32(data?.Count ?? 0), Convert.ToDecimal(data?.Amount ?? 0));
  3590 + }
  3591 +
  3592 + /// <summary>
  3593 + /// 统计人头(月度去重客户数)
  3594 + /// </summary>
  3595 + private async Task<int> GetHeadCount(string userId, string month)
  3596 + {
  3597 + var sql = $@"
  3598 + SELECT COUNT(DISTINCT hyhk.hy) as Count
  3599 + FROM lq_xh_jksyj jksyj
  3600 + INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
  3601 + WHERE jksyj.jkszh = '{userId}'
  3602 + AND jksyj.F_IsEffective = 1
  3603 + AND hyhk.F_IsEffective = 1
  3604 + AND DATE_FORMAT(hyhk.hksj, '%Y%m') = '{month}'";
  3605 +
  3606 + var result = await _db.Ado.SqlQueryAsync<dynamic>(sql);
  3607 + return Convert.ToInt32(result.FirstOrDefault()?.Count ?? 0);
  3608 + }
  3609 +
  3610 + /// <summary>
  3611 + /// 统计人次(日度去重客户数)
  3612 + /// </summary>
  3613 + private async Task<int> GetPersonCount(string userId, string month)
  3614 + {
  3615 + var sql = $@"
  3616 + SELECT COUNT(DISTINCT CONCAT(hyhk.hy, '-', DATE(hyhk.hksj))) as Count
  3617 + FROM lq_xh_jksyj jksyj
  3618 + INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
  3619 + WHERE jksyj.jkszh = '{userId}'
  3620 + AND jksyj.F_IsEffective = 1
  3621 + AND hyhk.F_IsEffective = 1
  3622 + AND DATE_FORMAT(hyhk.hksj, '%Y%m') = '{month}'";
  3623 +
  3624 + var result = await _db.Ado.SqlQueryAsync<dynamic>(sql);
  3625 + return Convert.ToInt32(result.FirstOrDefault()?.Count ?? 0);
  3626 + }
  3627 +
  3628 + #endregion
  3629 +
3385 } 3630 }
3386 } 3631 }
netcore/src/Modularity/Extend/NCC.Extend/LqXmzlService.cs
@@ -536,8 +536,10 @@ namespace NCC.Extend.LqXmzl @@ -536,8 +536,10 @@ namespace NCC.Extend.LqXmzl
536 // 门店过滤(通过开单记录关联) 536 // 门店过滤(通过开单记录关联)
537 if (!string.IsNullOrEmpty(input.StoreId)) 537 if (!string.IsNullOrEmpty(input.StoreId))
538 { 538 {
539 - query = query.InnerJoin<LqKdKdjlbEntity>((px, kd) => px.Glkdbh == kd.Id)  
540 - .Where((px, kd) => kd.Djmd == input.StoreId && kd.IsEffective == 1); 539 + // 使用子查询过滤门店 - 在SQL层面过滤,避免别名问题
  540 + query = query.Where(x => SqlFunc.Subqueryable<LqKdKdjlbEntity>()
  541 + .Where(kd => kd.Id == x.Glkdbh && kd.Djmd == input.StoreId && kd.IsEffective == 1)
  542 + .Any());
541 } 543 }
542 544
543 var result = await query 545 var result = await query
@@ -568,8 +570,10 @@ namespace NCC.Extend.LqXmzl @@ -568,8 +570,10 @@ namespace NCC.Extend.LqXmzl
568 570
569 if (!string.IsNullOrEmpty(input.StoreId)) 571 if (!string.IsNullOrEmpty(input.StoreId))
570 { 572 {
571 - memberCountQuery = memberCountQuery.InnerJoin<LqKdKdjlbEntity>((px, kd) => px.Glkdbh == kd.Id)  
572 - .Where((px, kd) => kd.Djmd == input.StoreId && kd.IsEffective == 1); 573 + // 使用子查询过滤门店 - 在SQL层面过滤,避免别名问题
  574 + memberCountQuery = memberCountQuery.Where(x => SqlFunc.Subqueryable<LqKdKdjlbEntity>()
  575 + .Where(kd => kd.Id == x.Glkdbh && kd.Djmd == input.StoreId && kd.IsEffective == 1)
  576 + .Any());
573 } 577 }
574 578
575 var memberStats = await memberCountQuery 579 var memberStats = await memberCountQuery
@@ -605,8 +609,10 @@ namespace NCC.Extend.LqXmzl @@ -605,8 +609,10 @@ namespace NCC.Extend.LqXmzl
605 // 门店过滤(通过耗卡记录关联) 609 // 门店过滤(通过耗卡记录关联)
606 if (!string.IsNullOrEmpty(input.StoreId)) 610 if (!string.IsNullOrEmpty(input.StoreId))
607 { 611 {
608 - query = query.InnerJoin<LqXhHyhkEntity>((px, xh) => px.ConsumeInfoId == xh.Id)  
609 - .Where((px, xh) => xh.Md == input.StoreId && xh.IsEffective == 1); 612 + // 使用子查询过滤门店 - 在SQL层面过滤,避免别名问题
  613 + query = query.Where(x => SqlFunc.Subqueryable<LqXhHyhkEntity>()
  614 + .Where(xh => xh.Id == x.ConsumeInfoId && xh.Md == input.StoreId && xh.IsEffective == 1)
  615 + .Any());
610 } 616 }
611 617
612 var result = await query 618 var result = await query
@@ -645,8 +651,10 @@ namespace NCC.Extend.LqXmzl @@ -645,8 +651,10 @@ namespace NCC.Extend.LqXmzl
645 // 门店过滤(通过退卡记录关联) 651 // 门店过滤(通过退卡记录关联)
646 if (!string.IsNullOrEmpty(input.StoreId)) 652 if (!string.IsNullOrEmpty(input.StoreId))
647 { 653 {
648 - query = query.InnerJoin<LqHytkHytkEntity>((mx, hytk) => mx.RefundInfoId == hytk.Id)  
649 - .Where((mx, hytk) => hytk.Md == input.StoreId && hytk.IsEffective == 1); 654 + // 使用子查询过滤门店 - 在SQL层面过滤,避免别名问题
  655 + query = query.Where(x => SqlFunc.Subqueryable<LqHytkHytkEntity>()
  656 + .Where(hytk => hytk.Id == x.RefundInfoId && hytk.Md == input.StoreId && hytk.IsEffective == 1)
  657 + .Any());
650 } 658 }
651 659
652 var result = await query 660 var result = await query