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 2  
3 3 VUE_CLI_BABEL_TRANSPILE_MODULES = true
4 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 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 10 /// <summary>
11 11 /// 使用记录ID
12 12 /// </summary>
13   - public string Id { get; set; }
  13 + public string id { get; set; }
14 14  
15 15 /// <summary>
16 16 /// 产品ID
17 17 /// </summary>
18   - public string ProductId { get; set; }
  18 + public string productId { get; set; }
19 19  
20 20 /// <summary>
21 21 /// 产品名称
22 22 /// </summary>
23   - public string ProductName { get; set; }
  23 + public string productName { get; set; }
24 24  
25 25 /// <summary>
26 26 /// 产品类别
27 27 /// </summary>
28   - public string ProductCategory { get; set; }
  28 + public string productCategory { get; set; }
29 29  
30 30 /// <summary>
31 31 /// 产品价格
32 32 /// </summary>
33   - public decimal ProductPrice { get; set; }
  33 + public decimal productPrice { get; set; }
34 34  
35 35 /// <summary>
36 36 /// 门店ID
37 37 /// </summary>
38   - public string StoreId { get; set; }
  38 + public string storeId { get; set; }
39 39  
40 40 /// <summary>
41 41 /// 门店名称
42 42 /// </summary>
43   - public string StoreName { get; set; }
  43 + public string storeName { get; set; }
44 44  
45 45 /// <summary>
46 46 /// 使用时间
47 47 /// </summary>
48   - public DateTime UsageTime { get; set; }
  48 + public DateTime usageTime { get; set; }
49 49  
50 50 /// <summary>
51 51 /// 使用数量
52 52 /// </summary>
53   - public int UsageQuantity { get; set; }
  53 + public int usageQuantity { get; set; }
54 54  
55 55 /// <summary>
56 56 /// 关联消耗ID
57 57 /// </summary>
58   - public string RelatedConsumeId { get; set; }
  58 + public string relatedConsumeId { get; set; }
59 59  
60 60 /// <summary>
61 61 /// 创建人ID
62 62 /// </summary>
63   - public string CreateUser { get; set; }
  63 + public string createUser { get; set; }
64 64  
65 65 /// <summary>
66 66 /// 创建人姓名
67 67 /// </summary>
68   - public string CreateUserName { get; set; }
  68 + public string createUserName { get; set; }
69 69  
70 70 /// <summary>
71 71 /// 创建时间
72 72 /// </summary>
73   - public DateTime CreateTime { get; set; }
  73 + public DateTime createTime { get; set; }
74 74  
75 75 /// <summary>
76 76 /// 更新人ID
77 77 /// </summary>
78   - public string UpdateUser { get; set; }
  78 + public string updateUser { get; set; }
79 79  
80 80 /// <summary>
81 81 /// 更新人姓名
82 82 /// </summary>
83   - public string UpdateUserName { get; set; }
  83 + public string updateUserName { get; set; }
84 84  
85 85 /// <summary>
86 86 /// 更新时间
87 87 /// </summary>
88   - public DateTime? UpdateTime { get; set; }
  88 + public DateTime? updateTime { get; set; }
89 89  
90 90 /// <summary>
91 91 /// 是否有效(1:有效 0:无效)
92 92 /// </summary>
93   - public int IsEffective { get; set; }
  93 + public int isEffective { get; set; }
94 94  
95 95 /// <summary>
96 96 /// 使用总价值
97 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 12 using NCC.Extend.Entitys.Enum;
13 13 using NCC.Extend.Entitys.lq_inventory;
14 14 using NCC.Extend.Entitys.lq_inventory_usage;
  15 +using NCC.Extend.Entitys.lq_mdxx;
15 16 using NCC.Extend.Interfaces.LqInventoryUsage;
16 17 using NCC.FriendlyException;
17 18 using NCC.System.Entitys.Permission;
... ... @@ -184,23 +185,23 @@ namespace NCC.Extend
184 185 .WhereIF(input.IsEffective.HasValue, x => x.IsEffective == input.IsEffective.Value)
185 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 206 .MergeTable()
206 207 .OrderBy(sidx + " " + input.sort)
... ... @@ -209,30 +210,30 @@ namespace NCC.Extend
209 210 // 补充产品信息和用户信息
210 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 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 241 if (!string.IsNullOrWhiteSpace(input.ProductName) || !string.IsNullOrWhiteSpace(input.ProductCategory))
241 242 {
242 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 246 ).ToList();
246 247 }
247 248  
248 249 // 应用门店名称的过滤条件
249 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 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 2247 GROUP BY jksyj.jkszh, hyhk.md
2248 2248 ) headcount_stats ON jksyj.jkszh = headcount_stats.jkszh AND hyhk.md = headcount_stats.md
2249 2249 LEFT JOIN (
2250   - -- 人次统计:日度去重到店数
  2250 + -- 人次统计:日度去重客户数(每天同一个客户只算一次)
2251 2251 SELECT
2252 2252 jksyj.jkszh,
2253 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 2255 FROM lq_xh_jksyj jksyj
2256 2256 INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id AND hyhk.F_IsEffective = 1
2257 2257 WHERE jksyj.F_IsEffective = 1
... ... @@ -3382,5 +3382,250 @@ namespace NCC.Extend.LqStatistics
3382 3382  
3383 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 536 // 门店过滤(通过开单记录关联)
537 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 545 var result = await query
... ... @@ -568,8 +570,10 @@ namespace NCC.Extend.LqXmzl
568 570  
569 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 579 var memberStats = await memberCountQuery
... ... @@ -605,8 +609,10 @@ namespace NCC.Extend.LqXmzl
605 609 // 门店过滤(通过耗卡记录关联)
606 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 618 var result = await query
... ... @@ -645,8 +651,10 @@ namespace NCC.Extend.LqXmzl
645 651 // 门店过滤(通过退卡记录关联)
646 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 660 var result = await query
... ...