Commit 15ec2754380f2e7727326806c3aa795559826c40

Authored by “wangming”
1 parent 9790054f

feat: 优化统计功能

- 修复GetStoreDailyStatistics和GetStorePerformanceCompletion,只统计zxzt为'开店'的门店
- 为GetBusinessUnitPerformanceCompletion和GetTianwangGroupPerformanceCompletion添加退卡业绩统计和实际完成业绩计算
- 为GetEmployeePerformanceStatistics添加手工费统计和消耗项目数分类统计(原始、加班、陪同)
- 修复ConsumeCount和RefundCount统计逻辑,改为统计消耗单数和退卡单数
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitPerformanceCompletionOutput.cs
@@ -24,12 +24,27 @@ namespace NCC.Extend.Entitys.Dto.LqDailyReport @@ -24,12 +24,27 @@ namespace NCC.Extend.Entitys.Dto.LqDailyReport
24 public decimal TargetPerformance { get; set; } 24 public decimal TargetPerformance { get; set; }
25 25
26 /// <summary> 26 /// <summary>
27 - /// 完成业绩(管理门店的开单业绩总和) 27 + /// 开单业绩(管理门店的开单业绩总和)
  28 + /// </summary>
  29 + public decimal BillingPerformance { get; set; }
  30 +
  31 + /// <summary>
  32 + /// 退款业绩(退卡业绩总和)
  33 + /// </summary>
  34 + public decimal RefundPerformance { get; set; }
  35 +
  36 + /// <summary>
  37 + /// 开单业绩(管理门店的开单业绩总和)
  38 + /// </summary>
  39 + public decimal ActualPerformance { get; set; }
  40 +
  41 + /// <summary>
  42 + /// 实际完成业绩(开单业绩 - 退款业绩)
28 /// </summary> 43 /// </summary>
29 public decimal CompletedPerformance { get; set; } 44 public decimal CompletedPerformance { get; set; }
30 45
31 /// <summary> 46 /// <summary>
32 - /// 完成率(百分比 47 + /// 完成率(百分比,基于实际完成业绩计算
33 /// </summary> 48 /// </summary>
34 public decimal CompletionRate { get; set; } 49 public decimal CompletionRate { get; set; }
35 50
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/TianwangGroupPerformanceCompletionOutput.cs
@@ -24,12 +24,27 @@ namespace NCC.Extend.Entitys.Dto.LqDailyReport @@ -24,12 +24,27 @@ namespace NCC.Extend.Entitys.Dto.LqDailyReport
24 public decimal TargetPerformance { get; set; } 24 public decimal TargetPerformance { get; set; }
25 25
26 /// <summary> 26 /// <summary>
27 - /// 完成业绩(管理门店的开单业绩总和) 27 + /// 开单业绩(管理门店的开单业绩总和)
  28 + /// </summary>
  29 + public decimal BillingPerformance { get; set; }
  30 +
  31 + /// <summary>
  32 + /// 退款业绩(退卡业绩总和)
  33 + /// </summary>
  34 + public decimal RefundPerformance { get; set; }
  35 +
  36 + /// <summary>
  37 + /// 开单业绩(与BillingPerformance相同,用于兼容)
  38 + /// </summary>
  39 + public decimal ActualPerformance { get; set; }
  40 +
  41 + /// <summary>
  42 + /// 实际完成业绩(开单业绩 - 退款业绩)
28 /// </summary> 43 /// </summary>
29 public decimal CompletedPerformance { get; set; } 44 public decimal CompletedPerformance { get; set; }
30 45
31 /// <summary> 46 /// <summary>
32 - /// 完成率(百分比 47 + /// 完成率(百分比,基于实际完成业绩计算
33 /// </summary> 48 /// </summary>
34 public decimal CompletionRate { get; set; } 49 public decimal CompletionRate { get; set; }
35 50
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/EmployeePerformanceStatisticsOutput.cs
@@ -41,7 +41,7 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics @@ -41,7 +41,7 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics
41 public decimal BillingAmount { get; set; } 41 public decimal BillingAmount { get; set; }
42 42
43 /// <summary> 43 /// <summary>
44 - /// 消耗数量 44 + /// 消耗单数(消耗主表的去重记录数)
45 /// </summary> 45 /// </summary>
46 public int ConsumeCount { get; set; } 46 public int ConsumeCount { get; set; }
47 47
@@ -51,7 +51,7 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics @@ -51,7 +51,7 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics
51 public decimal ConsumeAmount { get; set; } 51 public decimal ConsumeAmount { get; set; }
52 52
53 /// <summary> 53 /// <summary>
54 - /// 退卡数量 54 + /// 退卡单数量(退卡主表的去重记录数)
55 /// </summary> 55 /// </summary>
56 public int RefundCount { get; set; } 56 public int RefundCount { get; set; }
57 57
@@ -76,8 +76,28 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics @@ -76,8 +76,28 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics
76 public int BillingProjectCount { get; set; } 76 public int BillingProjectCount { get; set; }
77 77
78 /// <summary> 78 /// <summary>
79 - /// 消耗项目数(项目次数总和 79 + /// 消耗项目数(项目次数总和,包含原始+加班+陪同
80 /// </summary> 80 /// </summary>
81 public int ConsumeProjectCount { get; set; } 81 public int ConsumeProjectCount { get; set; }
  82 +
  83 + /// <summary>
  84 + /// 消耗原始项目数(原始项目次数总和)
  85 + /// </summary>
  86 + public decimal ConsumeOriginalProjectCount { get; set; }
  87 +
  88 + /// <summary>
  89 + /// 消耗加班项目数(加班项目次数总和)
  90 + /// </summary>
  91 + public decimal ConsumeOvertimeProjectCount { get; set; }
  92 +
  93 + /// <summary>
  94 + /// 消耗陪同项目数(陪同项目次数总和)
  95 + /// </summary>
  96 + public decimal ConsumeAccompaniedProjectCount { get; set; }
  97 +
  98 + /// <summary>
  99 + /// 手工费(消耗手工费总和)
  100 + /// </summary>
  101 + public decimal LaborCost { get; set; }
82 } 102 }
83 } 103 }
netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs
@@ -125,7 +125,7 @@ namespace NCC.Extend @@ -125,7 +125,7 @@ namespace NCC.Extend
125 storeFilter = $"AND consume.Md IN ('{storeIdsStr}')"; 125 storeFilter = $"AND consume.Md IN ('{storeIdsStr}')";
126 } 126 }
127 127
128 - // SQL查询:获取门店每日运营数据 128 + // SQL查询:获取门店每日运营数据(只统计zxzt为"开店"的门店)
129 var sql = $@" 129 var sql = $@"
130 SELECT 130 SELECT
131 consume.Md as StoreId, 131 consume.Md as StoreId,
@@ -148,7 +148,7 @@ namespace NCC.Extend @@ -148,7 +148,7 @@ namespace NCC.Extend
148 -- 消耗业绩(总金额) 148 -- 消耗业绩(总金额)
149 COALESCE(SUM(project.F_TotalPrice), 0) as ConsumePerformance 149 COALESCE(SUM(project.F_TotalPrice), 0) as ConsumePerformance
150 FROM lq_xh_hyhk consume 150 FROM lq_xh_hyhk consume
151 - LEFT JOIN lq_mdxx store ON consume.Md = store.F_Id 151 + INNER JOIN lq_mdxx store ON consume.Md = store.F_Id AND store.zxzt = '开店'
152 LEFT JOIN lq_xh_pxmx project ON consume.F_Id = project.F_ConsumeInfoId AND project.F_IsEffective = 1 152 LEFT JOIN lq_xh_pxmx project ON consume.F_Id = project.F_ConsumeInfoId AND project.F_IsEffective = 1
153 WHERE consume.F_IsEffective = 1 153 WHERE consume.F_IsEffective = 1
154 AND DATE(consume.Hksj) >= '{startDate:yyyy-MM-dd}' 154 AND DATE(consume.Hksj) >= '{startDate:yyyy-MM-dd}'
@@ -227,7 +227,7 @@ namespace NCC.Extend @@ -227,7 +227,7 @@ namespace NCC.Extend
227 storeFilter = $"AND store.F_Id IN ('{storeIdsStr}')"; 227 storeFilter = $"AND store.F_Id IN ('{storeIdsStr}')";
228 } 228 }
229 229
230 - // SQL查询:获取门店业绩完成情况 230 + // SQL查询:获取门店业绩完成情况(只统计zxzt为"开店"的门店)
231 var sql = $@" 231 var sql = $@"
232 SELECT 232 SELECT
233 store.F_Id as StoreId, 233 store.F_Id as StoreId,
@@ -254,7 +254,7 @@ namespace NCC.Extend @@ -254,7 +254,7 @@ namespace NCC.Extend
254 ), 0) as RefundPerformance 254 ), 0) as RefundPerformance
255 FROM lq_mdxx store 255 FROM lq_mdxx store
256 LEFT JOIN lq_md_target target ON target.F_StoreId = store.F_Id AND target.F_Month = '{month}' 256 LEFT JOIN lq_md_target target ON target.F_StoreId = store.F_Id AND target.F_Month = '{month}'
257 - WHERE 1=1 {storeFilter} 257 + WHERE store.zxzt = '开店' {storeFilter}
258 ORDER BY (BillingPerformance - RefundPerformance) DESC"; 258 ORDER BY (BillingPerformance - RefundPerformance) DESC";
259 259
260 var result = await _db.Ado.SqlQueryAsync<dynamic>(sql); 260 var result = await _db.Ado.SqlQueryAsync<dynamic>(sql);
@@ -289,7 +289,7 @@ namespace NCC.Extend @@ -289,7 +289,7 @@ namespace NCC.Extend
289 /// 获取事业部业绩完成情况 289 /// 获取事业部业绩完成情况
290 /// </summary> 290 /// </summary>
291 /// <remarks> 291 /// <remarks>
292 - /// 根据指定日期统计各事业部的业绩完成情况,包括目标业绩、完成业绩、完成率 292 + /// 根据指定日期统计各事业部的业绩完成情况,包括目标业绩、开单业绩、退卡金额、实际完成业绩、完成率
293 /// 293 ///
294 /// 示例请求: 294 /// 示例请求:
295 /// ```json 295 /// ```json
@@ -309,7 +309,10 @@ namespace NCC.Extend @@ -309,7 +309,10 @@ namespace NCC.Extend
309 /// - BusinessUnitId: 事业部ID 309 /// - BusinessUnitId: 事业部ID
310 /// - BusinessUnitName: 事业部名称 310 /// - BusinessUnitName: 事业部名称
311 /// - TargetPerformance: 目标业绩(来自门店目标表lq_md_target的F_BusinessUnitTarget字段,根据开始时间所在月份获取,通过F_BusinessUnit字段关联,如果未查询到则为0) 311 /// - TargetPerformance: 目标业绩(来自门店目标表lq_md_target的F_BusinessUnitTarget字段,根据开始时间所在月份获取,通过F_BusinessUnit字段关联,如果未查询到则为0)
312 - /// - CompletedPerformance: 完成业绩(指定时间范围内的开单业绩总和) 312 + /// - BillingPerformance: 开单业绩(指定时间范围内的开单业绩总和)
  313 + /// - RefundPerformance: 退款业绩(指定时间范围内的退卡业绩总和)
  314 + /// - ActualPerformance: 开单业绩(与BillingPerformance相同,用于兼容)
  315 + /// - CompletedPerformance: 实际完成业绩(开单业绩 - 退款业绩)
313 /// - CompletionRate: 完成率(百分比,CompletedPerformance / TargetPerformance * 100) 316 /// - CompletionRate: 完成率(百分比,CompletedPerformance / TargetPerformance * 100)
314 /// - StoreCount: 门店数量(根据门店目标表中归属该事业部的门店数统计) 317 /// - StoreCount: 门店数量(根据门店目标表中归属该事业部的门店数统计)
315 /// </remarks> 318 /// </remarks>
@@ -368,20 +371,23 @@ namespace NCC.Extend @@ -368,20 +371,23 @@ namespace NCC.Extend
368 BusinessUnitId = unit.BusinessUnitId.ToString(), 371 BusinessUnitId = unit.BusinessUnitId.ToString(),
369 BusinessUnitName = unit.BusinessUnitName.ToString(), 372 BusinessUnitName = unit.BusinessUnitName.ToString(),
370 TargetPerformance = Convert.ToDecimal(unit.TargetPerformance), 373 TargetPerformance = Convert.ToDecimal(unit.TargetPerformance),
  374 + BillingPerformance = 0,
  375 + RefundPerformance = 0,
  376 + ActualPerformance = 0,
371 CompletedPerformance = 0, 377 CompletedPerformance = 0,
372 CompletionRate = 0, 378 CompletionRate = 0,
373 StoreCount = Convert.ToInt32(unit.StoreCount) 379 StoreCount = Convert.ToInt32(unit.StoreCount)
374 }; 380 };
375 } 381 }
376 382
377 - // 第二步:统计各事业部的完成业绩 383 + // 第二步:统计各事业部的开单业绩
378 var businessUnitIds = businessUnitDict.Keys.ToList(); 384 var businessUnitIds = businessUnitDict.Keys.ToList();
379 var unitIdsStr = string.Join("','", businessUnitIds); 385 var unitIdsStr = string.Join("','", businessUnitIds);
380 386
381 - var completedPerformanceSql = $@" 387 + var billingPerformanceSql = $@"
382 SELECT 388 SELECT
383 store.syb as BusinessUnitId, 389 store.syb as BusinessUnitId,
384 - COALESCE(SUM(billing.sfyj), 0) as CompletedPerformance 390 + COALESCE(SUM(billing.sfyj), 0) as BillingPerformance
385 FROM lq_kd_kdjlb billing 391 FROM lq_kd_kdjlb billing
386 INNER JOIN lq_mdxx store ON billing.djmd = store.F_Id 392 INNER JOIN lq_mdxx store ON billing.djmd = store.F_Id
387 INNER JOIN base_organize o ON store.syb = o.F_Id 393 INNER JOIN base_organize o ON store.syb = o.F_Id
@@ -394,28 +400,58 @@ namespace NCC.Extend @@ -394,28 +400,58 @@ namespace NCC.Extend
394 AND store.syb IN ('{unitIdsStr}') 400 AND store.syb IN ('{unitIdsStr}')
395 GROUP BY store.syb"; 401 GROUP BY store.syb";
396 402
397 - var completedPerformanceData = await _db.Ado.SqlQueryAsync<dynamic>(completedPerformanceSql); 403 + var billingPerformanceData = await _db.Ado.SqlQueryAsync<dynamic>(billingPerformanceSql);
  404 +
  405 + // 第三步:统计各事业部的退卡金额
  406 + var refundPerformanceSql = $@"
  407 + SELECT
  408 + store.syb as BusinessUnitId,
  409 + COALESCE(SUM(refund.F_ActualRefundAmount), 0) as RefundPerformance
  410 + FROM lq_hytk_hytk refund
  411 + INNER JOIN lq_mdxx store ON refund.md = store.F_Id
  412 + INNER JOIN base_organize o ON store.syb = o.F_Id
  413 + WHERE refund.F_IsEffective = 1
  414 + AND o.F_Category = 'department'
  415 + AND (o.F_DeleteMark IS NULL OR o.F_DeleteMark != 1)
  416 + AND o.F_FullName IN ('事业一部', '事业二部', '事业三部', '事业四部', '事业五部', '事业六部')
  417 + AND DATE(refund.tksj) >= '{startDate:yyyy-MM-dd}'
  418 + AND DATE(refund.tksj) <= '{endDate:yyyy-MM-dd}'
  419 + AND store.syb IN ('{unitIdsStr}')
  420 + GROUP BY store.syb";
  421 +
  422 + var refundPerformanceData = await _db.Ado.SqlQueryAsync<dynamic>(refundPerformanceSql);
398 423
399 - // 第三步:合并数据并计算完成率  
400 - foreach (var item in completedPerformanceData) 424 + // 第四步:合并开单业绩数据
  425 + foreach (var item in billingPerformanceData)
401 { 426 {
402 var businessUnitId = item.BusinessUnitId.ToString(); 427 var businessUnitId = item.BusinessUnitId.ToString();
403 if (businessUnitDict.ContainsKey(businessUnitId)) 428 if (businessUnitDict.ContainsKey(businessUnitId))
404 { 429 {
405 - var completedPerformance = Convert.ToDecimal(item.CompletedPerformance);  
406 - var unit = businessUnitDict[businessUnitId];  
407 - unit.CompletedPerformance = completedPerformance;  
408 -  
409 - var completionRate = unit.TargetPerformance > 0  
410 - ? (completedPerformance / unit.TargetPerformance * 100m)  
411 - : 0m;  
412 - unit.CompletionRate = decimal.Round(completionRate, 2); 430 + businessUnitDict[businessUnitId].BillingPerformance = Convert.ToDecimal(item.BillingPerformance);
413 } 431 }
414 } 432 }
415 433
416 - var outputList = businessUnitDict.Values  
417 - .OrderByDescending(x => x.CompletedPerformance)  
418 - .ToList(); 434 + // 第五步:合并退卡金额数据
  435 + foreach (var item in refundPerformanceData)
  436 + {
  437 + var businessUnitId = item.BusinessUnitId.ToString();
  438 + if (businessUnitDict.ContainsKey(businessUnitId))
  439 + {
  440 + businessUnitDict[businessUnitId].RefundPerformance = Convert.ToDecimal(item.RefundPerformance);
  441 + }
  442 + }
  443 +
  444 + // 第六步:计算实际完成业绩和完成率
  445 + foreach (var unit in businessUnitDict.Values)
  446 + {
  447 + unit.ActualPerformance = unit.BillingPerformance; // 开单业绩
  448 + var actualCompletedPerformance = unit.BillingPerformance - unit.RefundPerformance; // 实际完成业绩
  449 + unit.CompletedPerformance = actualCompletedPerformance; // 实际完成业绩
  450 + var completionRate = unit.TargetPerformance > 0 ? (actualCompletedPerformance / unit.TargetPerformance * 100m) : 0m;
  451 + unit.CompletionRate = decimal.Round(completionRate, 2);
  452 + }
  453 +
  454 + var outputList = businessUnitDict.Values.OrderByDescending(x => x.CompletedPerformance).ToList();
419 455
420 return outputList; 456 return outputList;
421 } 457 }
@@ -426,7 +462,7 @@ namespace NCC.Extend @@ -426,7 +462,7 @@ namespace NCC.Extend
426 /// 获取天王团业绩完成情况 462 /// 获取天王团业绩完成情况
427 /// </summary> 463 /// </summary>
428 /// <remarks> 464 /// <remarks>
429 - /// 根据指定日期统计各天王团的业绩完成情况,包括目标业绩、完成业绩、完成率 465 + /// 根据指定日期统计各天王团的业绩完成情况,包括目标业绩、开单业绩、退卡金额、实际完成业绩、完成率
430 /// 466 ///
431 /// 示例请求: 467 /// 示例请求:
432 /// ```json 468 /// ```json
@@ -446,7 +482,10 @@ namespace NCC.Extend @@ -446,7 +482,10 @@ namespace NCC.Extend
446 /// - DepartmentId: 部门ID 482 /// - DepartmentId: 部门ID
447 /// - DepartmentName: 部门名称(教育一部、教育二部、科技一部、科技二部、大项目一部、大项目二部) 483 /// - DepartmentName: 部门名称(教育一部、教育二部、科技一部、科技二部、大项目一部、大项目二部)
448 /// - TargetPerformance: 目标业绩(来自门店目标表lq_md_target,根据部门类型使用对应字段:教育部使用F_EducationDepartmentTarget,科技部使用F_TechDepartmentTarget,大项目部使用F_MajorProjectDepartmentTarget,根据开始时间所在月份获取,通过对应归属字段关联,如果未查询到则为0) 484 /// - TargetPerformance: 目标业绩(来自门店目标表lq_md_target,根据部门类型使用对应字段:教育部使用F_EducationDepartmentTarget,科技部使用F_TechDepartmentTarget,大项目部使用F_MajorProjectDepartmentTarget,根据开始时间所在月份获取,通过对应归属字段关联,如果未查询到则为0)
449 - /// - CompletedPerformance: 完成业绩(指定时间范围内的开单业绩总和) 485 + /// - BillingPerformance: 开单业绩(指定时间范围内的开单业绩总和)
  486 + /// - RefundPerformance: 退款业绩(指定时间范围内的退卡业绩总和)
  487 + /// - ActualPerformance: 开单业绩(与BillingPerformance相同,用于兼容)
  488 + /// - CompletedPerformance: 实际完成业绩(开单业绩 - 退款业绩)
450 /// - CompletionRate: 完成率(百分比,CompletedPerformance / TargetPerformance * 100) 489 /// - CompletionRate: 完成率(百分比,CompletedPerformance / TargetPerformance * 100)
451 /// - StoreCount: 门店数量(根据门店目标表中归属该部门的门店数统计) 490 /// - StoreCount: 门店数量(根据门店目标表中归属该部门的门店数统计)
452 /// </remarks> 491 /// </remarks>
@@ -517,6 +556,9 @@ namespace NCC.Extend @@ -517,6 +556,9 @@ namespace NCC.Extend
517 DepartmentId = dept.DepartmentId.ToString(), 556 DepartmentId = dept.DepartmentId.ToString(),
518 DepartmentName = dept.DepartmentName.ToString(), 557 DepartmentName = dept.DepartmentName.ToString(),
519 TargetPerformance = Convert.ToDecimal(dept.TargetPerformance), 558 TargetPerformance = Convert.ToDecimal(dept.TargetPerformance),
  559 + BillingPerformance = 0,
  560 + RefundPerformance = 0,
  561 + ActualPerformance = 0,
520 CompletedPerformance = 0, 562 CompletedPerformance = 0,
521 CompletionRate = 0, 563 CompletionRate = 0,
522 StoreCount = Convert.ToInt32(dept.StoreCount) 564 StoreCount = Convert.ToInt32(dept.StoreCount)
@@ -530,14 +572,14 @@ namespace NCC.Extend @@ -530,14 +572,14 @@ namespace NCC.Extend
530 return new List<TianwangGroupPerformanceCompletionOutput>(); 572 return new List<TianwangGroupPerformanceCompletionOutput>();
531 } 573 }
532 574
533 - // 第二步:统计各天王团的完成业绩(直接按部门ID统计,避免重复计算) 575 + // 第二步:统计各天王团的开单业绩(直接按部门ID统计,避免重复计算)
534 var deptIdsStrForQuery = string.Join("','", departmentDict.Keys); 576 var deptIdsStrForQuery = string.Join("','", departmentDict.Keys);
535 577
536 // 使用 OR 条件连接三个部门类型字段,确保每个开单记录只被统计一次到对应的部门 578 // 使用 OR 条件连接三个部门类型字段,确保每个开单记录只被统计一次到对应的部门
537 - var completedPerformanceSql = $@" 579 + var billingPerformanceSql = $@"
538 SELECT 580 SELECT
539 o.F_Id as DepartmentId, 581 o.F_Id as DepartmentId,
540 - COALESCE(SUM(billing.sfyj), 0) as CompletedPerformance 582 + COALESCE(SUM(billing.sfyj), 0) as BillingPerformance
541 FROM lq_kd_kdjlb billing 583 FROM lq_kd_kdjlb billing
542 INNER JOIN lq_mdxx store ON billing.djmd = store.F_Id 584 INNER JOIN lq_mdxx store ON billing.djmd = store.F_Id
543 INNER JOIN base_organize o ON ( 585 INNER JOIN base_organize o ON (
@@ -553,35 +595,63 @@ namespace NCC.Extend @@ -553,35 +595,63 @@ namespace NCC.Extend
553 AND o.F_Id IN ('{deptIdsStrForQuery}') 595 AND o.F_Id IN ('{deptIdsStrForQuery}')
554 GROUP BY o.F_Id"; 596 GROUP BY o.F_Id";
555 597
556 - var completedPerformanceData = await _db.Ado.SqlQueryAsync<dynamic>(completedPerformanceSql); 598 + var billingPerformanceData = await _db.Ado.SqlQueryAsync<dynamic>(billingPerformanceSql);
  599 +
  600 + // 第三步:统计各天王团的退卡金额
  601 + var refundPerformanceSql = $@"
  602 + SELECT
  603 + o.F_Id as DepartmentId,
  604 + COALESCE(SUM(refund.F_ActualRefundAmount), 0) as RefundPerformance
  605 + FROM lq_hytk_hytk refund
  606 + INNER JOIN lq_mdxx store ON refund.md = store.F_Id
  607 + INNER JOIN base_organize o ON (
  608 + (store.jyb = o.F_Id AND o.F_FullName IN ('教育一部', '教育二部'))
  609 + OR (store.kjb = o.F_Id AND o.F_FullName IN ('科技一部', '科技二部'))
  610 + OR (store.dxmb = o.F_Id AND o.F_FullName IN ('大项目一部', '大项目二部'))
  611 + )
  612 + WHERE refund.F_IsEffective = 1
  613 + AND o.F_Category = 'department'
  614 + AND (o.F_DeleteMark IS NULL OR o.F_DeleteMark != 1)
  615 + AND DATE(refund.tksj) >= '{startDate:yyyy-MM-dd}'
  616 + AND DATE(refund.tksj) <= '{endDate:yyyy-MM-dd}'
  617 + AND o.F_Id IN ('{deptIdsStrForQuery}')
  618 + GROUP BY o.F_Id";
  619 +
  620 + var refundPerformanceData = await _db.Ado.SqlQueryAsync<dynamic>(refundPerformanceSql);
557 621
558 - // 第三步:将完成业绩数据填充到部门字典中  
559 - var departmentPerformanceDict = new Dictionary<string, decimal>();  
560 - if (completedPerformanceData != null) 622 + // 第四步:合并开单业绩数据
  623 + foreach (var item in billingPerformanceData ?? Enumerable.Empty<dynamic>())
561 { 624 {
562 - foreach (var item in completedPerformanceData) 625 + var departmentId = item.DepartmentId.ToString();
  626 + if (departmentDict.ContainsKey(departmentId))
563 { 627 {
564 - var departmentId = item.DepartmentId.ToString();  
565 - var completedPerformance = Convert.ToDecimal(item.CompletedPerformance);  
566 - departmentPerformanceDict[departmentId] = completedPerformance; 628 + departmentDict[departmentId].BillingPerformance = Convert.ToDecimal(item.BillingPerformance);
567 } 629 }
568 } 630 }
569 631
570 - // 计算完成率  
571 - foreach (var kvp in departmentPerformanceDict) 632 + // 第五步:合并退卡金额数据
  633 + foreach (var item in refundPerformanceData ?? Enumerable.Empty<dynamic>())
572 { 634 {
573 - if (departmentDict.ContainsKey(kvp.Key)) 635 + var departmentId = item.DepartmentId.ToString();
  636 + if (departmentDict.ContainsKey(departmentId))
574 { 637 {
575 - var dept = departmentDict[kvp.Key];  
576 - dept.CompletedPerformance = kvp.Value;  
577 -  
578 - var completionRate = dept.TargetPerformance > 0  
579 - ? (kvp.Value / dept.TargetPerformance * 100m)  
580 - : 0m;  
581 - dept.CompletionRate = decimal.Round(completionRate, 2); 638 + departmentDict[departmentId].RefundPerformance = Convert.ToDecimal(item.RefundPerformance);
582 } 639 }
583 } 640 }
584 641
  642 + // 第六步:计算实际完成业绩和完成率
  643 + foreach (var dept in departmentDict.Values)
  644 + {
  645 + dept.ActualPerformance = dept.BillingPerformance; // 开单业绩
  646 + var actualCompletedPerformance = dept.BillingPerformance - dept.RefundPerformance; // 实际完成业绩
  647 + dept.CompletedPerformance = actualCompletedPerformance; // 实际完成业绩
  648 +
  649 + var completionRate = dept.TargetPerformance > 0
  650 + ? (actualCompletedPerformance / dept.TargetPerformance * 100m)
  651 + : 0m;
  652 + dept.CompletionRate = decimal.Round(completionRate, 2);
  653 + }
  654 +
585 var outputList = departmentDict.Values 655 var outputList = departmentDict.Values
586 .OrderByDescending(x => x.CompletedPerformance) 656 .OrderByDescending(x => x.CompletedPerformance)
587 .ToList(); 657 .ToList();
netcore/src/Modularity/Extend/NCC.Extend/LqMdxxService.cs
@@ -361,6 +361,7 @@ namespace NCC.Extend.LqMdxx @@ -361,6 +361,7 @@ namespace NCC.Extend.LqMdxx
361 public async Task<dynamic> GetSelector() 361 public async Task<dynamic> GetSelector()
362 { 362 {
363 var list = await _db.Queryable<LqMdxxEntity>() 363 var list = await _db.Queryable<LqMdxxEntity>()
  364 + .Where(it => it.Zxzt == "开店")
364 .Select(it => new { id = it.Id, fullName = it.Dm, enCode = it.Mdbm }) 365 .Select(it => new { id = it.Id, fullName = it.Dm, enCode = it.Mdbm })
365 .ToListAsync(); 366 .ToListAsync();
366 return new { list = list }; 367 return new { list = list };
netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs
@@ -3495,13 +3495,17 @@ namespace NCC.Extend.LqStatistics @@ -3495,13 +3495,17 @@ namespace NCC.Extend.LqStatistics
3495 /// - BillingCount: 开单数量 3495 /// - BillingCount: 开单数量
3496 /// - BillingAmount: 开单金额 3496 /// - BillingAmount: 开单金额
3497 /// - BillingProjectCount: 开单项目数(项目次数总和) 3497 /// - BillingProjectCount: 开单项目数(项目次数总和)
3498 - /// - ConsumeCount: 消耗数量 3498 + /// - ConsumeCount: 消耗单数(消耗主表的去重记录数)
3499 /// - ConsumeAmount: 消耗金额 3499 /// - ConsumeAmount: 消耗金额
3500 - /// - ConsumeProjectCount: 消耗项目数(项目次数总和)  
3501 - /// - RefundCount: 退卡数量 3500 + /// - ConsumeProjectCount: 消耗项目数(项目次数总和,包含原始+加班+陪同)
  3501 + /// - ConsumeOriginalProjectCount: 消耗原始项目数(原始项目次数总和)
  3502 + /// - ConsumeOvertimeProjectCount: 消耗加班项目数(加班项目次数总和)
  3503 + /// - ConsumeAccompaniedProjectCount: 消耗陪同项目数(陪同项目次数总和)
  3504 + /// - RefundCount: 退卡单数量
3502 /// - RefundAmount: 退卡金额 3505 /// - RefundAmount: 退卡金额
3503 /// - HeadCount: 人头(月度去重客户数) 3506 /// - HeadCount: 人头(月度去重客户数)
3504 /// - PersonCount: 人次(日度去重客户数) 3507 /// - PersonCount: 人次(日度去重客户数)
  3508 + /// - LaborCost: 手工费(消耗手工费总和)
3505 /// </remarks> 3509 /// </remarks>
3506 /// <param name="input">查询参数</param> 3510 /// <param name="input">查询参数</param>
3507 /// <returns>员工业绩统计数据</returns> 3511 /// <returns>员工业绩统计数据</returns>
@@ -3549,8 +3553,11 @@ namespace NCC.Extend.LqStatistics @@ -3549,8 +3553,11 @@ namespace NCC.Extend.LqStatistics
3549 // 9. 开单项目数统计 3553 // 9. 开单项目数统计
3550 var billingProjectCount = await GetBillingProjectCount(input.UserId, statisticsMonth); 3554 var billingProjectCount = await GetBillingProjectCount(input.UserId, statisticsMonth);
3551 3555
3552 - // 10. 消耗项目数统计  
3553 - var consumeProjectCount = await GetConsumeProjectCount(input.UserId, statisticsMonth); 3556 + // 10. 消耗项目数统计(包含总项目数、原始项目数、加班项目数、陪同项目数)
  3557 + var consumeProjectStats = await GetConsumeProjectCountDetails(input.UserId, statisticsMonth);
  3558 +
  3559 + // 11. 手工费统计
  3560 + var laborCost = await GetLaborCost(input.UserId, statisticsMonth);
3554 3561
3555 return new EmployeePerformanceStatisticsOutput 3562 return new EmployeePerformanceStatisticsOutput
3556 { 3563 {
@@ -3568,7 +3575,11 @@ namespace NCC.Extend.LqStatistics @@ -3568,7 +3575,11 @@ namespace NCC.Extend.LqStatistics
3568 HeadCount = headCount, 3575 HeadCount = headCount,
3569 PersonCount = personCount, 3576 PersonCount = personCount,
3570 BillingProjectCount = billingProjectCount, 3577 BillingProjectCount = billingProjectCount,
3571 - ConsumeProjectCount = consumeProjectCount 3578 + ConsumeProjectCount = consumeProjectStats.TotalCount,
  3579 + ConsumeOriginalProjectCount = consumeProjectStats.OriginalCount,
  3580 + ConsumeOvertimeProjectCount = consumeProjectStats.OvertimeCount,
  3581 + ConsumeAccompaniedProjectCount = consumeProjectStats.AccompaniedCount,
  3582 + LaborCost = laborCost
3572 }; 3583 };
3573 } 3584 }
3574 catch (Exception ex) 3585 catch (Exception ex)
@@ -3647,9 +3658,10 @@ namespace NCC.Extend.LqStatistics @@ -3647,9 +3658,10 @@ namespace NCC.Extend.LqStatistics
3647 /// </summary> 3658 /// </summary>
3648 private async Task<(int Count, decimal Amount)> GetConsumeStats(string userId, string month) 3659 private async Task<(int Count, decimal Amount)> GetConsumeStats(string userId, string month)
3649 { 3660 {
  3661 + // 统计消耗单数(消耗主表的去重记录数)和消耗金额(健康师业绩总和)
3650 var sql = $@" 3662 var sql = $@"
3651 SELECT 3663 SELECT
3652 - COUNT(*) as Count, 3664 + COUNT(DISTINCT hyhk.F_Id) as Count,
3653 COALESCE(SUM(jksyj.jksyj), 0) as Amount 3665 COALESCE(SUM(jksyj.jksyj), 0) as Amount
3654 FROM lq_xh_jksyj jksyj 3666 FROM lq_xh_jksyj jksyj
3655 INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id 3667 INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
@@ -3668,14 +3680,17 @@ namespace NCC.Extend.LqStatistics @@ -3668,14 +3680,17 @@ namespace NCC.Extend.LqStatistics
3668 /// </summary> 3680 /// </summary>
3669 private async Task<(int Count, decimal Amount)> GetRefundStats(string userId, string month) 3681 private async Task<(int Count, decimal Amount)> GetRefundStats(string userId, string month)
3670 { 3682 {
  3683 + // 统计退卡单数(退卡主表的去重记录数)和退卡金额(健康师业绩总和)
3671 var sql = $@" 3684 var sql = $@"
3672 SELECT 3685 SELECT
3673 - COUNT(*) as Count,  
3674 - COALESCE(SUM(jksyj), 0) as Amount  
3675 - FROM lq_hytk_jksyj  
3676 - WHERE jkszh = '{userId}'  
3677 - AND F_IsEffective = 1  
3678 - AND DATE_FORMAT(tksj, '%Y%m') = '{month}'"; 3686 + COUNT(DISTINCT hytk.F_Id) as Count,
  3687 + COALESCE(SUM(jksyj.jksyj), 0) as Amount
  3688 + FROM lq_hytk_jksyj jksyj
  3689 + INNER JOIN lq_hytk_hytk hytk ON jksyj.gltkbh = hytk.F_Id
  3690 + WHERE jksyj.jkszh = '{userId}'
  3691 + AND jksyj.F_IsEffective = 1
  3692 + AND hytk.F_IsEffective = 1
  3693 + AND DATE_FORMAT(hytk.tksj, '%Y%m') = '{month}'";
3679 3694
3680 var result = await _db.Ado.SqlQueryAsync<dynamic>(sql); 3695 var result = await _db.Ado.SqlQueryAsync<dynamic>(sql);
3681 var data = result.FirstOrDefault(); 3696 var data = result.FirstOrDefault();
@@ -3754,6 +3769,53 @@ namespace NCC.Extend.LqStatistics @@ -3754,6 +3769,53 @@ namespace NCC.Extend.LqStatistics
3754 return Convert.ToInt32(result.FirstOrDefault()?.Count ?? 0); 3769 return Convert.ToInt32(result.FirstOrDefault()?.Count ?? 0);
3755 } 3770 }
3756 3771
  3772 + /// <summary>
  3773 + /// 统计消耗项目数详情(包含总项目数、原始项目数、加班项目数、陪同项目数)
  3774 + /// </summary>
  3775 + private async Task<(int TotalCount, decimal OriginalCount, decimal OvertimeCount, decimal AccompaniedCount)> GetConsumeProjectCountDetails(string userId, string month)
  3776 + {
  3777 + var sql = $@"
  3778 + SELECT
  3779 + COALESCE(SUM(pxmx.F_ProjectNumber), 0) as TotalCount,
  3780 + COALESCE(SUM(COALESCE(pxmx.F_OriginalProjectNumber, pxmx.F_ProjectNumber)), 0) as OriginalCount,
  3781 + COALESCE(SUM(COALESCE(pxmx.F_OvertimeProjectNumber, 0)), 0) as OvertimeCount,
  3782 + COALESCE(SUM(COALESCE(jksyj.F_AccompaniedProjectNumber, 0)), 0) as AccompaniedCount
  3783 + FROM lq_xh_jksyj jksyj
  3784 + INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
  3785 + INNER JOIN lq_xh_pxmx pxmx ON pxmx.F_ConsumeInfoId = hyhk.F_Id
  3786 + WHERE jksyj.jkszh = '{userId}'
  3787 + AND jksyj.F_IsEffective = 1
  3788 + AND hyhk.F_IsEffective = 1
  3789 + AND DATE_FORMAT(hyhk.hksj, '%Y%m') = '{month}'";
  3790 +
  3791 + var result = await _db.Ado.SqlQueryAsync<dynamic>(sql);
  3792 + var data = result.FirstOrDefault();
  3793 + return (
  3794 + Convert.ToInt32(data?.TotalCount ?? 0),
  3795 + Convert.ToDecimal(data?.OriginalCount ?? 0),
  3796 + Convert.ToDecimal(data?.OvertimeCount ?? 0),
  3797 + Convert.ToDecimal(data?.AccompaniedCount ?? 0)
  3798 + );
  3799 + }
  3800 +
  3801 + /// <summary>
  3802 + /// 统计手工费(消耗手工费总和)
  3803 + /// </summary>
  3804 + private async Task<decimal> GetLaborCost(string userId, string month)
  3805 + {
  3806 + var sql = $@"
  3807 + SELECT COALESCE(SUM(jksyj.F_LaborCost), 0) as LaborCost
  3808 + FROM lq_xh_jksyj jksyj
  3809 + INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
  3810 + WHERE jksyj.jkszh = '{userId}'
  3811 + AND jksyj.F_IsEffective = 1
  3812 + AND hyhk.F_IsEffective = 1
  3813 + AND DATE_FORMAT(hyhk.hksj, '%Y%m') = '{month}'";
  3814 +
  3815 + var result = await _db.Ado.SqlQueryAsync<dynamic>(sql);
  3816 + return Convert.ToDecimal(result.FirstOrDefault()?.LaborCost ?? 0);
  3817 + }
  3818 +
3757 #endregion 3819 #endregion
3758 } 3820 }
3759 } 3821 }