Commit f390c57fdd8643fc16957da3d0eff410b23c3e7b

Authored by 李宇
2 parents a856ffdc 6b697cd3

Merge branch 'master' of http://39.98.150.180/antissoft/lvqianmeiye_ERP

Showing 32 changed files with 1991 additions and 118 deletions
netcore/src/Application/NCC.API/appsettings.json
... ... @@ -181,6 +181,11 @@
181 181 "scope": "snsapi_userinfo"
182 182 }
183 183 },
  184 + "WeChatBot": {
  185 + "BotApiUrl": "http://wx.lvqianmeiye.com/api/Bot/send-text",
  186 + "WebhookUrl": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=496f1add-122b-43fc-9e38-0ca79c48b33f",
  187 + "WebhookUrlTest": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=6f8686ec-5011-4c1d-bae9-d82a2a2f4d83"
  188 + },
184 189 "NCC_App": {
185 190 "CodeAreasName": "SubDev,Food,Extend,test",
186 191 //系统文件路径(末尾必须带斜杆)
... ...
netcore/src/Modularity/Common/NCC.Common/Extension/Ext.cs
... ... @@ -808,7 +808,7 @@ namespace NCC.Common.Extension
808 808 }
809 809  
810 810 #endregion
811   -
  811 +
812 812 /// <summary>
813 813 /// 元转分
814 814 /// </summary>
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitBillingStatisticsInput.cs 0 → 100644
  1 +using System;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.LqDailyReport
  4 +{
  5 + /// <summary>
  6 + /// 事业部开单统计查询输入
  7 + /// </summary>
  8 + public class BusinessUnitBillingStatisticsInput
  9 + {
  10 + /// <summary>
  11 + /// 统计日期(格式:yyyy-MM-dd)
  12 + /// </summary>
  13 + public string Date { get; set; }
  14 + }
  15 +}
  16 +
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitBillingStatisticsOutput.cs 0 → 100644
  1 +using System;
  2 +using System.Collections.Generic;
  3 +
  4 +namespace NCC.Extend.Entitys.Dto.LqDailyReport
  5 +{
  6 + /// <summary>
  7 + /// 事业部开单统计输出
  8 + /// </summary>
  9 + public class BusinessUnitBillingStatisticsOutput
  10 + {
  11 + /// <summary>
  12 + /// 事业部ID
  13 + /// </summary>
  14 + public string BusinessUnitId { get; set; }
  15 +
  16 + /// <summary>
  17 + /// 事业部名称
  18 + /// </summary>
  19 + public string BusinessUnitName { get; set; }
  20 +
  21 + /// <summary>
  22 + /// 总业绩
  23 + /// </summary>
  24 + public decimal TotalPerformance { get; set; }
  25 +
  26 + /// <summary>
  27 + /// 总单量
  28 + /// </summary>
  29 + public int TotalOrderCount { get; set; }
  30 +
  31 + /// <summary>
  32 + /// 开单列表
  33 + /// </summary>
  34 + public List<BillingOrderInfo> Orders { get; set; }
  35 + }
  36 +
  37 + /// <summary>
  38 + /// 开单信息
  39 + /// </summary>
  40 + public class BillingOrderInfo
  41 + {
  42 + /// <summary>
  43 + /// 开单ID
  44 + /// </summary>
  45 + public string OrderId { get; set; }
  46 +
  47 + /// <summary>
  48 + /// 门店名称
  49 + /// </summary>
  50 + public string StoreName { get; set; }
  51 +
  52 + /// <summary>
  53 + /// 健康师姓名(多个用逗号分隔)
  54 + /// </summary>
  55 + public string HealthTeacherNames { get; set; }
  56 +
  57 + /// <summary>
  58 + /// 金额
  59 + /// </summary>
  60 + public decimal Amount { get; set; }
  61 +
  62 + /// <summary>
  63 + /// 开单时间
  64 + /// </summary>
  65 + public DateTime? OrderTime { get; set; }
  66 + }
  67 +}
  68 +
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/LqHytkHytkListOutput.cs
1 1 using System;
  2 +using System.Collections.Generic;
  3 +using NCC.Extend.Entitys.Dto.LqHytkMx;
  4 +using NCC.Extend.Entitys.Dto.LqHytkJksyj;
  5 +using NCC.Extend.Entitys.Dto.LqHytkKjbsyj;
2 6  
3 7 namespace NCC.Extend.Entitys.Dto.LqHytkHytk
4 8 {
... ... @@ -102,5 +106,19 @@ namespace NCC.Extend.Entitys.Dto.LqHytkHytk
102 106 /// </summary>
103 107 public string cancelRemark { get; set; }
104 108  
  109 + /// <summary>
  110 + /// 退卡品项明细列表
  111 + /// </summary>
  112 + public List<LqHytkMxInfoOutput> lqHytkMxList { get; set; }
  113 +
  114 + /// <summary>
  115 + /// 健康师业绩列表
  116 + /// </summary>
  117 + public List<LqHytkJksyjInfoOutput> lqHytkJksyjList { get; set; }
  118 +
  119 + /// <summary>
  120 + /// 科技部老师业绩列表
  121 + /// </summary>
  122 + public List<LqHytkKjbsyjInfoOutput> lqHytkKjbsyjList { get; set; }
105 123 }
106 124 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/LqHytkHytkListQueryInput.cs
... ... @@ -93,5 +93,14 @@ namespace NCC.Extend.Entitys.Dto.LqHytkHytk
93 93 /// </summary>
94 94 public int isEffective { get; set; } = 0;
95 95  
  96 + /// <summary>
  97 + /// 健康师ID(可选,传入后只返回该健康师参与的退卡记录)
  98 + /// </summary>
  99 + public string jksId { get; set; }
  100 +
  101 + /// <summary>
  102 + /// 科技部老师ID(可选,传入后只返回该老师参与的退卡记录)
  103 + /// </summary>
  104 + public string kjblsId { get; set; }
96 105 }
97 106 }
98 107 \ No newline at end of file
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListByJksQueryInput.cs 0 → 100644
  1 +using NCC.Common.Filter;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.LqKdKdjlb
  4 +{
  5 + /// <summary>
  6 + /// 根据健康师ID查询开单列表输入
  7 + /// </summary>
  8 + public class LqKdKdjlbListByJksQueryInput : PageInputBase
  9 + {
  10 + /// <summary>
  11 + /// 健康师ID(必填)
  12 + /// </summary>
  13 + public string jksId { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  17 + /// </summary>
  18 + public string startTime { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  22 + /// </summary>
  23 + public string endTime { get; set; }
  24 +
  25 + /// <summary>
  26 + /// 门店ID(可选)
  27 + /// </summary>
  28 + public string djmd { get; set; }
  29 +
  30 + /// <summary>
  31 + /// 是否有效(可选,0=全部,1=有效,2=无效,默认1)
  32 + /// </summary>
  33 + public int isEffective { get; set; } = 1;
  34 + }
  35 +}
  36 +
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListByKjbQueryInput.cs 0 → 100644
  1 +using NCC.Common.Filter;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.LqKdKdjlb
  4 +{
  5 + /// <summary>
  6 + /// 根据科技部老师ID查询开单列表输入
  7 + /// </summary>
  8 + public class LqKdKdjlbListByKjbQueryInput : PageInputBase
  9 + {
  10 + /// <summary>
  11 + /// 科技部老师ID(必填)
  12 + /// </summary>
  13 + public string kjblsId { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  17 + /// </summary>
  18 + public string startTime { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  22 + /// </summary>
  23 + public string endTime { get; set; }
  24 +
  25 + /// <summary>
  26 + /// 门店ID(可选)
  27 + /// </summary>
  28 + public string djmd { get; set; }
  29 +
  30 + /// <summary>
  31 + /// 是否有效(可选,0=全部,1=有效,2=无效,默认1)
  32 + /// </summary>
  33 + public int isEffective { get; set; } = 1;
  34 + }
  35 +}
  36 +
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListOutput.cs
... ... @@ -170,5 +170,15 @@ namespace NCC.Extend.Entitys.Dto.LqKdKdjlb
170 170 /// 开单品项明细列表
171 171 /// </summary>
172 172 public List<LqKdPxmxInfoOutput> ItemDetails { get; set; }
  173 +
  174 + /// <summary>
  175 + /// 健康师业绩列表
  176 + /// </summary>
  177 + public List<LqKdJksyjInfoOutput> lqKdJksyjList { get; set; }
  178 +
  179 + /// <summary>
  180 + /// 科技部老师业绩列表
  181 + /// </summary>
  182 + public List<LqKdKjbsyjInfoOutput> lqKdKjbsyjList { get; set; }
173 183 }
174 184 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListQueryInput.cs
... ... @@ -139,5 +139,14 @@ namespace NCC.Extend.Entitys.Dto.LqKdKdjlb
139 139 /// </summary>
140 140 public int isEffective { get; set; } = 0;
141 141  
  142 + /// <summary>
  143 + /// 健康师ID(可选,传入后只返回该健康师参与的开单记录)
  144 + /// </summary>
  145 + public string jksId { get; set; }
  146 +
  147 + /// <summary>
  148 + /// 科技部老师ID(可选,传入后只返回该老师参与的开单记录)
  149 + /// </summary>
  150 + public string kjblsId { get; set; }
142 151 }
143 152 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsByItemOutput.cs 0 → 100644
  1 +using System.Collections.Generic;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.LqPackageInfo
  4 +{
  5 + /// <summary>
  6 + /// 营销活动按品项统计输出
  7 + /// </summary>
  8 + public class ActivityStatisticsByItemOutput
  9 + {
  10 + /// <summary>
  11 + /// 营销活动ID
  12 + /// </summary>
  13 + public string ActivityId { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 营销活动名称
  17 + /// </summary>
  18 + public string ActivityName { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 品项统计列表
  22 + /// </summary>
  23 + public List<ItemStatisticsItem> ItemList { get; set; }
  24 + }
  25 +
  26 + /// <summary>
  27 + /// 品项统计项
  28 + /// </summary>
  29 + public class ItemStatisticsItem
  30 + {
  31 + /// <summary>
  32 + /// 品项ID
  33 + /// </summary>
  34 + public string ItemId { get; set; }
  35 +
  36 + /// <summary>
  37 + /// 品项名称
  38 + /// </summary>
  39 + public string ItemName { get; set; }
  40 +
  41 + /// <summary>
  42 + /// 销售数量(项目次数总和)
  43 + /// </summary>
  44 + public decimal SalesQuantity { get; set; }
  45 +
  46 + /// <summary>
  47 + /// 销售金额
  48 + /// </summary>
  49 + public decimal SalesAmount { get; set; }
  50 +
  51 + /// <summary>
  52 + /// 开单数量(包含该品项的开单数)
  53 + /// </summary>
  54 + public int BillingCount { get; set; }
  55 +
  56 + /// <summary>
  57 + /// 销售次数(品项明细记录数)
  58 + /// </summary>
  59 + public int SalesCount { get; set; }
  60 + }
  61 +}
  62 +
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsByStoreItemOutput.cs 0 → 100644
  1 +using System.Collections.Generic;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.LqPackageInfo
  4 +{
  5 + /// <summary>
  6 + /// 营销活动按门店品项统计输出
  7 + /// </summary>
  8 + public class ActivityStatisticsByStoreItemOutput
  9 + {
  10 + /// <summary>
  11 + /// 营销活动ID
  12 + /// </summary>
  13 + public string ActivityId { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 营销活动名称
  17 + /// </summary>
  18 + public string ActivityName { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 门店品项统计列表
  22 + /// </summary>
  23 + public List<StoreItemStatisticsItem> StoreItemList { get; set; }
  24 + }
  25 +
  26 + /// <summary>
  27 + /// 门店品项统计项
  28 + /// </summary>
  29 + public class StoreItemStatisticsItem
  30 + {
  31 + /// <summary>
  32 + /// 门店ID
  33 + /// </summary>
  34 + public string StoreId { get; set; }
  35 +
  36 + /// <summary>
  37 + /// 门店名称
  38 + /// </summary>
  39 + public string StoreName { get; set; }
  40 +
  41 + /// <summary>
  42 + /// 品项ID
  43 + /// </summary>
  44 + public string ItemId { get; set; }
  45 +
  46 + /// <summary>
  47 + /// 品项名称
  48 + /// </summary>
  49 + public string ItemName { get; set; }
  50 +
  51 + /// <summary>
  52 + /// 销售数量(项目次数总和)
  53 + /// </summary>
  54 + public decimal SalesQuantity { get; set; }
  55 +
  56 + /// <summary>
  57 + /// 销售金额
  58 + /// </summary>
  59 + public decimal SalesAmount { get; set; }
  60 +
  61 + /// <summary>
  62 + /// 开单数量(包含该品项的开单数)
  63 + /// </summary>
  64 + public int BillingCount { get; set; }
  65 +
  66 + /// <summary>
  67 + /// 销售次数(品项明细记录数)
  68 + /// </summary>
  69 + public int SalesCount { get; set; }
  70 + }
  71 +}
  72 +
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsByStoreOutput.cs 0 → 100644
  1 +using System.Collections.Generic;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.LqPackageInfo
  4 +{
  5 + /// <summary>
  6 + /// 营销活动按门店统计输出
  7 + /// </summary>
  8 + public class ActivityStatisticsByStoreOutput
  9 + {
  10 + /// <summary>
  11 + /// 营销活动ID
  12 + /// </summary>
  13 + public string ActivityId { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 营销活动名称
  17 + /// </summary>
  18 + public string ActivityName { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 门店统计列表
  22 + /// </summary>
  23 + public List<StoreStatisticsItem> StoreList { get; set; }
  24 + }
  25 +
  26 + /// <summary>
  27 + /// 门店统计项
  28 + /// </summary>
  29 + public class StoreStatisticsItem
  30 + {
  31 + /// <summary>
  32 + /// 门店ID
  33 + /// </summary>
  34 + public string StoreId { get; set; }
  35 +
  36 + /// <summary>
  37 + /// 门店名称
  38 + /// </summary>
  39 + public string StoreName { get; set; }
  40 +
  41 + /// <summary>
  42 + /// 开单数量
  43 + /// </summary>
  44 + public int BillingCount { get; set; }
  45 +
  46 + /// <summary>
  47 + /// 开单金额
  48 + /// </summary>
  49 + public decimal BillingAmount { get; set; }
  50 +
  51 + /// <summary>
  52 + /// 欠款金额
  53 + /// </summary>
  54 + public decimal DebtAmount { get; set; }
  55 +
  56 + /// <summary>
  57 + /// 人头数(去重客户数)
  58 + /// </summary>
  59 + public int CustomerCount { get; set; }
  60 +
  61 + /// <summary>
  62 + /// 项目数(品项项目次数总和)
  63 + /// </summary>
  64 + public decimal ItemCount { get; set; }
  65 + }
  66 +}
  67 +
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/TechTeacherSimpleStatisticsOutput.cs
... ... @@ -41,5 +41,10 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics
41 41 /// 耗卡品项次数
42 42 /// </summary>
43 43 public int ConsumeItemCount { get; set; }
  44 +
  45 + /// <summary>
  46 + /// 消耗手工费(耗卡手工费)
  47 + /// </summary>
  48 + public decimal ConsumeLaborCost { get; set; }
44 49 }
45 50 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/MemberRemainingItemsOutput.cs
... ... @@ -25,6 +25,7 @@ namespace NCC.Extend.Entitys.Dto.LqXhHyhk
25 25 public string MemberName { get; set; }
26 26  
27 27 /// <summary>
  28 + /// <summary>
28 29 /// 剩余品项列表
29 30 /// </summary>
30 31 /// <remarks>按剩余数量降序排列的品项列表</remarks>
... ... @@ -71,6 +72,12 @@ namespace NCC.Extend.Entitys.Dto.LqXhHyhk
71 72 public string SourceType { get; set; }
72 73  
73 74 /// <summary>
  75 + /// 备注
  76 + /// </summary>
  77 + /// <example>备注</example>
  78 + public string Remark { get; set; }
  79 +
  80 + /// <summary>
74 81 /// 总购买数量
75 82 /// </summary>
76 83 /// <remarks>该品项的总购买次数</remarks>
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqYaoyjl/LqYaoyjlListQueryInput.cs
... ... @@ -17,47 +17,50 @@ namespace NCC.Extend.Entitys.Dto.LqYaoyjl
17 17 ///
18 18 /// </summary>
19 19 public int dataType { get; set; }
20   -
21   -
22 20 /// <summary>
23 21 /// 邀约编号
24 22 /// </summary>
25 23 public string id { get; set; }
26   -
  24 +
27 25 /// <summary>
28 26 /// 邀约人
29 27 /// </summary>
30 28 public string yyr { get; set; }
31   -
  29 +
32 30 /// <summary>
33 31 /// 邀约时间
34 32 /// </summary>
35 33 public string yysj { get; set; }
36   -
  34 +
37 35 /// <summary>
38 36 /// 邀约客户
39 37 /// </summary>
40 38 public string yykh { get; set; }
41   -
  39 +
42 40 /// <summary>
43 41 /// 邀约客户姓名
44 42 /// </summary>
45 43 public string yykhxm { get; set; }
46   -
  44 +
47 45 /// <summary>
48 46 /// 电话是否有效
49 47 /// </summary>
50 48 public string dhsfyx { get; set; }
51   -
  49 +
52 50 /// <summary>
53 51 /// 联系时间
54 52 /// </summary>
55 53 public string lxsj { get; set; }
56   -
  54 +
57 55 /// <summary>
58 56 /// 联系记录
59 57 /// </summary>
60 58 public string lxjl { get; set; }
61   -
  59 +
  60 + /// <summary>
  61 + /// 门店ID
  62 + /// </summary>
  63 + public string storeId { get; set; }
  64 +
62 65 }
63 66 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineCrInput.cs
... ... @@ -28,6 +28,12 @@ namespace NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline
28 28 public string generalManagerId { get; set; }
29 29  
30 30 /// <summary>
  31 + /// 经理类型(0=经理,1=总经理)
  32 + /// </summary>
  33 + [Required(ErrorMessage = "经理类型不能为空")]
  34 + public int managerType { get; set; } = 1;
  35 +
  36 + /// <summary>
31 37 /// 生命线1
32 38 /// </summary>
33 39 [Required(ErrorMessage = "生命线1不能为空")]
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineInfoOutput.cs
... ... @@ -28,6 +28,11 @@ namespace NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline
28 28 public string generalManagerId { get; set; }
29 29  
30 30 /// <summary>
  31 + /// 经理类型(0=经理,1=总经理)
  32 + /// </summary>
  33 + public int managerType { get; set; }
  34 +
  35 + /// <summary>
31 36 /// 生命线1
32 37 /// </summary>
33 38 public decimal lifeline1 { get; set; }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineListOutput.cs
... ... @@ -28,6 +28,16 @@ namespace NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline
28 28 public string generalManagerId { get; set; }
29 29  
30 30 /// <summary>
  31 + /// 经理类型(0=经理,1=总经理)
  32 + /// </summary>
  33 + public int managerType { get; set; }
  34 +
  35 + /// <summary>
  36 + /// 经理类型(0=经理,1=总经理)
  37 + /// </summary>
  38 + public string managerTypeName { get; set; }
  39 +
  40 + /// <summary>
31 41 /// 生命线1
32 42 /// </summary>
33 43 public decimal lifeline1 { get; set; }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineUpInput.cs
... ... @@ -28,6 +28,12 @@ namespace NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline
28 28 public string generalManagerId { get; set; }
29 29  
30 30 /// <summary>
  31 + /// 经理类型(0=经理,1=总经理)
  32 + /// </summary>
  33 + [Required(ErrorMessage = "经理类型不能为空")]
  34 + public int managerType { get; set; } = 1;
  35 +
  36 + /// <summary>
31 37 /// 生命线1
32 38 /// </summary>
33 39 [Required(ErrorMessage = "生命线1不能为空")]
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_general_manager_lifeline/LqMdGeneralManagerLifelineEntity.cs
... ... @@ -36,6 +36,12 @@ namespace NCC.Extend.Entitys.lq_md_general_manager_lifeline
36 36 public string GeneralManagerId { get; set; }
37 37  
38 38 /// <summary>
  39 + /// 经理类型(0=经理,1=总经理)
  40 + /// </summary>
  41 + [SugarColumn(ColumnName = "F_ManagerType")]
  42 + public int ManagerType { get; set; } = 1;
  43 +
  44 + /// <summary>
39 45 /// 生命线1
40 46 /// </summary>
41 47 [SugarColumn(ColumnName = "F_Lifeline1")]
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Enum/ManagerTypeEnum.cs 0 → 100644
  1 +using System.ComponentModel;
  2 +
  3 +namespace NCC.Extend.Entitys.Enum
  4 +{
  5 + /// <summary>
  6 + /// 经理类型枚举
  7 + /// </summary>
  8 + public enum ManagerTypeEnum
  9 + {
  10 + /// <summary>
  11 + /// 经理
  12 + /// </summary>
  13 + [Description("经理")]
  14 + 经理 = 0,
  15 +
  16 + /// <summary>
  17 + /// 总经理
  18 + /// </summary>
  19 + [Description("总经理")]
  20 + 总经理 = 1,
  21 + }
  22 +}
  23 +
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs
... ... @@ -12,6 +12,7 @@ using SqlSugar;
12 12 using System;
13 13 using System.Collections.Generic;
14 14 using System.Linq;
  15 +using System.Text;
15 16 using System.Threading.Tasks;
16 17 using Yitter.IdGenerator;
17 18 using NCC.Common.Helper;
... ... @@ -22,6 +23,10 @@ using NCC.DataEncryption;
22 23 using NCC.ClayObject;
23 24 using NCC.Extend.Entitys.Dto.LqDailyReport;
24 25 using NCC.Extend.Entitys.lq_kd_kdjlb;
  26 +using NCC.Extend.Entitys.lq_kd_jksyj;
  27 +using NCC.Extend.Entitys.lq_mdxx;
  28 +using NCC.System.Entitys.Permission;
  29 +using NCC.Extend.Entitys.Enum;
25 30 using Microsoft.AspNetCore.Authorization;
26 31  
27 32 namespace NCC.Extend
... ... @@ -752,7 +757,7 @@ namespace NCC.Extend
752 757 managerFilter = $"AND target.F_GeneralManagerId = '{input.ManagerId}'";
753 758 }
754 759  
755   - // SQL查询:获取经理汇总业绩
  760 + // SQL查询:获取经理汇总业绩(基于lq_md_general_manager_lifeline表中的经理和门店关系)
756 761 var sql = $@"
757 762 SELECT
758 763 target.F_GeneralManagerId as ManagerId,
... ... @@ -761,7 +766,7 @@ namespace NCC.Extend
761 766 COALESCE(SUM(target.F_Lifeline2), 0) as TotalTarget2,
762 767 COALESCE(SUM(target.F_Lifeline3), 0) as TotalTarget3,
763 768 COUNT(DISTINCT target.F_StoreId) as StoreCount,
764   - -- 总完成业绩
  769 + -- 总完成业绩(基于lq_md_general_manager_lifeline表中的门店关系计算)
765 770 SUM(COALESCE((
766 771 SELECT SUM(billing.sfyj)
767 772 FROM lq_kd_kdjlb billing
... ... @@ -957,7 +962,267 @@ namespace NCC.Extend
957 962  
958 963 return outputList;
959 964 }
  965 +
  966 + /// <summary>
  967 + /// 获取指定日期的事业部开单统计数据
  968 + /// </summary>
  969 + /// <remarks>
  970 + /// 统计指定日期的事业部开单数据,包括:
  971 + /// - 只统计有效的开单(F_IsEffective = 1)
  972 + /// - 只统计有金额的开单(sfyj > 0)
  973 + /// - 只统计有效的健康师业绩(F_IsEffective = 1)
  974 + /// - 如果有多个健康师就合并显示
  975 + /// - 按照事业部名称排序
  976 + /// - 每个事业部内的开单按照时间先后顺序进行排序
  977 + ///
  978 + /// 示例请求:
  979 + /// ```json
  980 + /// {
  981 + /// "date": "2025-11-10"
  982 + /// }
  983 + /// ```
  984 + /// </remarks>
  985 + /// <param name="input">查询参数</param>
  986 + /// <returns>事业部开单统计数据列表</returns>
  987 + /// <response code="200">成功返回统计数据</response>
  988 + /// <response code="400">日期格式错误或参数无效</response>
  989 + /// <response code="500">服务器内部错误</response>
  990 + [HttpPost("get-business-unit-billing-statistics")]
  991 + [AllowAnonymous]
  992 + public async Task<List<BusinessUnitBillingStatisticsOutput>> GetBusinessUnitBillingStatistics(BusinessUnitBillingStatisticsInput input)
  993 + {
  994 + try
  995 + {
  996 + // 1. 验证日期参数
  997 + if (string.IsNullOrEmpty(input.Date))
  998 + {
  999 + throw NCCException.Oh("日期不能为空");
  1000 + }
  1001 +
  1002 + if (!DateTime.TryParse(input.Date, out var targetDate))
  1003 + {
  1004 + throw NCCException.Oh("日期格式错误,请使用 yyyy-MM-dd 格式");
  1005 + }
  1006 +
  1007 + // 2. 查询指定日期的有效开单记录(有金额的)
  1008 + var billingQuery = _db.Queryable<LqKdKdjlbEntity, LqMdxxEntity, OrganizeEntity>(
  1009 + (billing, store, org) => billing.Djmd == store.Id && store.Syb == org.Id)
  1010 + .Where((billing, store, org) => billing.IsEffective == StatusEnum.有效.GetHashCode())
  1011 + .Where((billing, store, org) => billing.Sfyj > 0) // 只统计有金额的开单
  1012 + .Where((billing, store, org) => billing.Kdrq.HasValue && billing.Kdrq.Value.Date == targetDate.Date)
  1013 + .Where((billing, store, org) => org.Category == "department")
  1014 + .Where((billing, store, org) => org.FullName.Contains("事业"))
  1015 + .Select((billing, store, org) => new
  1016 + {
  1017 + OrderId = billing.Id,
  1018 + StoreName = store.Dm,
  1019 + BusinessUnitId = org.Id,
  1020 + BusinessUnitName = org.FullName,
  1021 + Amount = billing.Sfyj,
  1022 + OrderTime = billing.Kdrq,
  1023 + })
  1024 + .ToListAsync();
  1025 +
  1026 + var billingRecords = await billingQuery;
  1027 +
  1028 + if (!billingRecords.Any())
  1029 + {
  1030 + return new List<BusinessUnitBillingStatisticsOutput>();
  1031 + }
  1032 +
  1033 + // 3. 批量查询健康师信息
  1034 + var orderIds = billingRecords.Select(x => x.OrderId).Distinct().ToList();
  1035 + var healthTeachers = await _db.Queryable<LqKdJksyjEntity>()
  1036 + .Where(x => orderIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode())
  1037 + .Select(x => new
  1038 + {
  1039 + OrderId = x.Glkdbh,
  1040 + TeacherName = x.Jksxm,
  1041 + })
  1042 + .ToListAsync();
  1043 +
  1044 + // 4. 按开单ID分组健康师
  1045 + var healthTeacherDict = healthTeachers
  1046 + .GroupBy(x => x.OrderId)
  1047 + .ToDictionary(
  1048 + g => g.Key,
  1049 + g => string.Join("、", g.Select(x => x.TeacherName).Distinct())
  1050 + );
  1051 +
  1052 + // 5. 按事业部分组统计
  1053 + var result = billingRecords
  1054 + .GroupBy(x => new { x.BusinessUnitId, x.BusinessUnitName })
  1055 + .Select(g => new BusinessUnitBillingStatisticsOutput
  1056 + {
  1057 + BusinessUnitId = g.Key.BusinessUnitId,
  1058 + BusinessUnitName = g.Key.BusinessUnitName,
  1059 + TotalPerformance = g.Sum(x => x.Amount),
  1060 + TotalOrderCount = g.Count(),
  1061 + Orders = g.OrderBy(x => x.OrderTime ?? DateTime.MinValue)
  1062 + .Select(x => new BillingOrderInfo
  1063 + {
  1064 + OrderId = x.OrderId,
  1065 + StoreName = x.StoreName,
  1066 + HealthTeacherNames = healthTeacherDict.GetValueOrDefault(x.OrderId, ""),
  1067 + Amount = x.Amount,
  1068 + OrderTime = x.OrderTime,
  1069 + })
  1070 + .ToList(),
  1071 + })
  1072 + .OrderBy(x => x.BusinessUnitName) // 按事业部名称排序
  1073 + .ToList();
  1074 +
  1075 + return result;
  1076 + }
  1077 + catch (Exception ex)
  1078 + {
  1079 + throw NCCException.Oh($"获取事业部开单统计数据失败: {ex.Message}", ex);
  1080 + }
  1081 + }
  1082 +
  1083 + /// <summary>
  1084 + /// 将事业部开单统计数据格式化为中文文本
  1085 + /// </summary>
  1086 + /// <remarks>
  1087 + /// 将结构化的统计数据格式化为中文文本格式,用于显示或发送消息。
  1088 + ///
  1089 + /// 示例请求:
  1090 + /// ```json
  1091 + /// {
  1092 + /// "date": "2025-11-10"
  1093 + /// }
  1094 + /// ```
  1095 + ///
  1096 + /// 返回格式:
  1097 + /// ```
  1098 + /// 11月8日
  1099 + ///
  1100 + /// 今日总业绩:32317
  1101 + ///
  1102 + /// 今日总单量:18
  1103 + ///
  1104 + /// 绿纤人用结果捍卫尊严
  1105 + ///
  1106 + /// 业绩捷报
  1107 + ///
  1108 + /// ▃▃▃▃▃▃▃▃▃▃
  1109 + ///
  1110 + /// 事业1部总业绩:4722
  1111 + ///
  1112 + /// 事业1部总单量:4
  1113 + ///
  1114 + /// 第1单:红光店马丽亚1000
  1115 + ///
  1116 + /// 第2单:468店陈小琴、苟小春500
  1117 + ///
  1118 + /// ...
  1119 + /// ```
  1120 + /// </remarks>
  1121 + /// <param name="input">查询参数</param>
  1122 + /// <returns>格式化的中文文本</returns>
  1123 + /// <response code="200">成功返回格式化文本</response>
  1124 + /// <response code="400">日期格式错误或参数无效</response>
  1125 + /// <response code="500">服务器内部错误</response>
  1126 + [HttpPost("get-business-unit-billing-statistics-text")]
  1127 + [AllowAnonymous]
  1128 + public async Task<string> GetBusinessUnitBillingStatisticsText(BusinessUnitBillingStatisticsInput input)
  1129 + {
  1130 + try
  1131 + {
  1132 + // 1. 获取统计数据
  1133 + var statistics = await GetBusinessUnitBillingStatistics(input);
  1134 +
  1135 + if (!statistics.Any())
  1136 + {
  1137 + return $"日期 {input.Date} 暂无开单数据";
  1138 + }
  1139 +
  1140 + // 2. 解析日期
  1141 + if (!DateTime.TryParse(input.Date, out var targetDate))
  1142 + {
  1143 + throw NCCException.Oh("日期格式错误,请使用 yyyy-MM-dd 格式");
  1144 + }
  1145 +
  1146 + // 3. 计算总业绩和总单量
  1147 + var totalPerformance = statistics.Sum(x => x.TotalPerformance);
  1148 + var totalOrderCount = statistics.Sum(x => x.TotalOrderCount);
  1149 +
  1150 + // 4. 格式化为中文文本
  1151 + var textBuilder = new StringBuilder();
  1152 +
  1153 + // 日期(格式:11月8日)
  1154 + textBuilder.AppendLine($"{targetDate.Month}月{targetDate.Day}日");
  1155 + textBuilder.AppendLine();
  1156 +
  1157 + // 今日总业绩和总单量
  1158 + textBuilder.AppendLine($"今日总业绩:{totalPerformance:F0}");
  1159 + textBuilder.AppendLine();
  1160 + textBuilder.AppendLine($"今日总单量:{totalOrderCount}");
  1161 + textBuilder.AppendLine();
  1162 +
  1163 + // 标语
  1164 + textBuilder.AppendLine("绿纤人用结果捍卫尊严 ");
  1165 + textBuilder.AppendLine();
  1166 + textBuilder.AppendLine("业绩捷报 ");
  1167 + textBuilder.AppendLine();
  1168 +
  1169 + // 每个事业部的数据
  1170 + foreach (var unit in statistics)
  1171 + {
  1172 + // 分隔线
  1173 + textBuilder.AppendLine("▃▃▃▃▃▃▃▃▃▃");
  1174 + textBuilder.AppendLine();
  1175 +
  1176 + // 事业部业绩和单量
  1177 + textBuilder.AppendLine($"{unit.BusinessUnitName}总业绩:{unit.TotalPerformance:F0}");
  1178 + textBuilder.AppendLine();
  1179 + textBuilder.AppendLine($"{unit.BusinessUnitName}总单量:{unit.TotalOrderCount}");
  1180 + textBuilder.AppendLine();
  1181 +
  1182 + // 按门店分组订单
  1183 + var ordersByStore = unit.Orders
  1184 + .GroupBy(x => x.StoreName)
  1185 + .OrderBy(g => g.Key) // 按门店名称排序
  1186 + .ToList();
  1187 +
  1188 + // 遍历每个门店的订单
  1189 + foreach (var storeGroup in ordersByStore)
  1190 + {
  1191 + // 每个门店的订单按时间排序
  1192 + var storeOrders = storeGroup
  1193 + .OrderBy(x => x.OrderTime ?? DateTime.MinValue)
  1194 + .ToList();
  1195 +
  1196 + // 每个门店的订单单独编号(从第1单开始)
  1197 + int orderIndex = 1;
  1198 + foreach (var order in storeOrders)
  1199 + {
  1200 + var teacherNames = string.IsNullOrEmpty(order.HealthTeacherNames) ? "" : order.HealthTeacherNames;
  1201 + // 格式:第1单:门店名健康师名金额(没有"、",没有"金额"字样,直接数字)
  1202 + if (string.IsNullOrEmpty(teacherNames))
  1203 + {
  1204 + textBuilder.AppendLine($"第{orderIndex}单:{order.StoreName}{order.Amount:F0}");
  1205 + }
  1206 + else
  1207 + {
  1208 + textBuilder.AppendLine($"第{orderIndex}单:{order.StoreName}{teacherNames}{order.Amount:F0}");
  1209 + }
  1210 + textBuilder.AppendLine();
  1211 + orderIndex++;
  1212 + }
  1213 + }
  1214 + }
  1215 +
  1216 + return textBuilder.ToString().TrimEnd();
  1217 + }
  1218 + catch (Exception ex)
  1219 + {
  1220 + throw NCCException.Oh($"获取事业部开单统计文本失败: {ex.Message}", ex);
  1221 + }
  1222 + }
960 1223 #endregion
  1224 +
  1225 +
961 1226 }
962 1227 }
963 1228  
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs
... ... @@ -70,8 +70,35 @@ namespace NCC.Extend.LqHytkHytk
70 70 /// <summary>
71 71 /// 获取退卡信息列表
72 72 /// </summary>
  73 + /// <remarks>
  74 + /// 获取退卡记录列表,支持根据健康师ID或科技部老师ID筛选,返回品项明细、健康师业绩和科技部老师业绩
  75 + ///
  76 + /// 示例请求:
  77 + /// ```json
  78 + /// GET /api/Extend/LqHytkHytk?jksId=健康师ID&amp;kjblsId=科技部老师ID&amp;currentPage=1&amp;pageSize=10
  79 + /// ```
  80 + ///
  81 + /// 参数说明:
  82 + /// - jksId: 健康师ID(可选,传入后只返回该健康师参与的退卡记录)
  83 + /// - kjblsId: 科技部老师ID(可选,传入后只返回该老师参与的退卡记录)
  84 + /// - id: 退卡编号(可选)
  85 + /// - md: 门店ID(可选)
  86 + /// - hy: 会员ID(可选)
  87 + /// - tksj: 退卡时间(可选,格式:yyyy-MM-dd,yyyy-MM-dd)
  88 + /// - currentPage: 当前页码(必填)
  89 + /// - pageSize: 每页数量(必填)
  90 + ///
  91 + /// 返回数据说明:
  92 + /// - 退卡基本信息:id、门店信息、会员信息、退卡金额、退卡时间等
  93 + /// - lqHytkMxList: 退卡品项明细列表,每个明细包含品项信息、退款金额、项目次数等
  94 + /// - lqHytkJksyjList: 健康师业绩列表,每个业绩包含健康师信息、业绩金额、手工费、退卡品项次数等
  95 + /// - lqHytkKjbsyjList: 科技部老师业绩列表,每个业绩包含科技部老师信息、业绩金额、手工费、退卡品项次数等
  96 + /// </remarks>
73 97 /// <param name="input">查询参数</param>
74   - /// <returns></returns>
  98 + /// <returns>分页的退卡记录列表,包含退卡基本信息、品项明细、健康师业绩、科技部老师业绩</returns>
  99 + /// <response code="200">成功返回退卡列表</response>
  100 + /// <response code="400">参数错误</response>
  101 + /// <response code="500">服务器内部错误</response>
75 102 [HttpGet("")]
76 103 public async Task<dynamic> GetList([FromQuery] LqHytkHytkListQueryInput input)
77 104 {
... ... @@ -79,7 +106,48 @@ namespace NCC.Extend.LqHytkHytk
79 106 List<string> queryTksj = input.tksj != null ? input.tksj.Split(',').ToObeject<List<string>>() : null;
80 107 DateTime? startTksj = queryTksj != null ? Ext.GetDateTime(queryTksj.First()) : null;
81 108 DateTime? endTksj = queryTksj != null ? Ext.GetDateTime(queryTksj.Last()) : null;
82   - var data = await _db.Queryable<LqHytkHytkEntity>()
  109 +
  110 + // 根据是否传入健康师ID或科技部老师ID,动态构建查询
  111 + ISugarQueryable<LqHytkHytkEntity> baseQuery = null;
  112 +
  113 + if (!string.IsNullOrEmpty(input.jksId) && !string.IsNullOrEmpty(input.kjblsId))
  114 + {
  115 + // 同时传入健康师ID和科技部老师ID,需要同时关联两个业绩表(不过滤有效性)
  116 + baseQuery = _db.Queryable<LqHytkJksyjEntity, LqHytkKjbsyjEntity, LqHytkHytkEntity>(
  117 + (jksyj, kjbsyj, hytk) => jksyj.Gltkbh == hytk.Id && kjbsyj.Gltkbh == hytk.Id)
  118 + .Where((jksyj, kjbsyj, hytk) => jksyj.Jkszh == input.jksId)
  119 + .Where((jksyj, kjbsyj, hytk) => kjbsyj.Kjblszh == input.kjblsId)
  120 + .Select((jksyj, kjbsyj, hytk) => hytk)
  121 + .Distinct()
  122 + .MergeTable();
  123 + }
  124 + else if (!string.IsNullOrEmpty(input.jksId))
  125 + {
  126 + // 只传入健康师ID,关联健康师业绩表(不过滤有效性)
  127 + baseQuery = _db.Queryable<LqHytkJksyjEntity, LqHytkHytkEntity>(
  128 + (jksyj, hytk) => jksyj.Gltkbh == hytk.Id)
  129 + .Where((jksyj, hytk) => jksyj.Jkszh == input.jksId)
  130 + .Select((jksyj, hytk) => hytk)
  131 + .Distinct()
  132 + .MergeTable();
  133 + }
  134 + else if (!string.IsNullOrEmpty(input.kjblsId))
  135 + {
  136 + // 只传入科技部老师ID,关联科技部老师业绩表(不过滤有效性)
  137 + baseQuery = _db.Queryable<LqHytkKjbsyjEntity, LqHytkHytkEntity>(
  138 + (kjbsyj, hytk) => kjbsyj.Gltkbh == hytk.Id)
  139 + .Where((kjbsyj, hytk) => kjbsyj.Kjblszh == input.kjblsId)
  140 + .Select((kjbsyj, hytk) => hytk)
  141 + .Distinct()
  142 + .MergeTable();
  143 + }
  144 + else
  145 + {
  146 + // 没有传入健康师ID或科技部老师ID,使用原来的查询逻辑
  147 + baseQuery = _db.Queryable<LqHytkHytkEntity>();
  148 + }
  149 +
  150 + var data = await baseQuery
83 151 .WhereIF(!string.IsNullOrEmpty(input.id), p => p.Id.Contains(input.id))
84 152 .WhereIF(!string.IsNullOrEmpty(input.md), p => p.Md.Equals(input.md))
85 153 .WhereIF(!string.IsNullOrEmpty(input.mdbh), p => p.Mdbh.Contains(input.mdbh))
... ... @@ -123,6 +191,104 @@ namespace NCC.Extend.LqHytkHytk
123 191 .MergeTable()
124 192 .OrderBy(sidx + " " + input.sort)
125 193 .ToPagedListAsync(input.currentPage, input.pageSize);
  194 +
  195 + // 获取当前页的退卡记录ID列表
  196 + var refundIds = data.list.Select(x => x.id).ToList();
  197 +
  198 + // 批量查询品项明细(不过滤有效性,返回所有记录)
  199 + var itemDetails = new List<LqHytkMxInfoOutput>();
  200 + if (refundIds.Any())
  201 + {
  202 + itemDetails = await _db.Queryable<LqHytkMxEntity>()
  203 + .Where(x => refundIds.Contains(x.RefundInfoId))
  204 + .Select(x => new LqHytkMxInfoOutput
  205 + {
  206 + id = x.Id,
  207 + refundInfoId = x.RefundInfoId,
  208 + billingItemId = x.BillingItemId,
  209 + px = x.Px,
  210 + pxmc = x.Pxmc,
  211 + pxjg = x.Pxjg,
  212 + tkje = x.Tkje,
  213 + projectNumber = x.ProjectNumber,
  214 + isEffective = x.IsEffective,
  215 + sourceType = x.SourceType,
  216 + totalPrice = x.TotalPrice
  217 + })
  218 + .ToListAsync();
  219 + }
  220 +
  221 + // 批量查询健康师业绩(性能优化:一次性查询所有退卡的健康师业绩,不过滤有效性)
  222 + var jksyjList = new List<LqHytkJksyjInfoOutput>();
  223 + if (refundIds.Any())
  224 + {
  225 + jksyjList = await _db.Queryable<LqHytkJksyjEntity>()
  226 + .Where(x => refundIds.Contains(x.Gltkbh))
  227 + .Select(x => new LqHytkJksyjInfoOutput
  228 + {
  229 + id = x.Id,
  230 + gltkbh = x.Gltkbh,
  231 + jks = x.Jks,
  232 + jksxm = x.Jksxm,
  233 + jkszh = x.Jkszh,
  234 + jksyj = x.Jksyj,
  235 + tksj = x.Tksj,
  236 + F_jsjid = x.F_jsjid,
  237 + F_tkpxid = x.F_tkpxid,
  238 + F_LaborCost = x.F_LaborCost,
  239 + F_tkpxNumber = x.F_tkpxNumber
  240 + })
  241 + .ToListAsync();
  242 + }
  243 +
  244 + // 批量查询科技部老师业绩(性能优化:一次性查询所有退卡的科技部老师业绩,不过滤有效性)
  245 + var kjbsyjList = new List<LqHytkKjbsyjInfoOutput>();
  246 + if (refundIds.Any())
  247 + {
  248 + kjbsyjList = await _db.Queryable<LqHytkKjbsyjEntity>()
  249 + .Where(x => refundIds.Contains(x.Gltkbh))
  250 + .Select(x => new LqHytkKjbsyjInfoOutput
  251 + {
  252 + id = x.Id,
  253 + gltkbh = x.Gltkbh,
  254 + kjbls = x.Kjbls,
  255 + kjblsxm = x.Kjblsxm,
  256 + kjblszh = x.Kjblszh,
  257 + kjblsyj = x.Kjblsyj,
  258 + tksj = x.Tksj,
  259 + F_tkpxid = x.F_tkpxid,
  260 + F_LaborCost = x.F_LaborCost,
  261 + F_tkpxNumber = x.F_tkpxNumber
  262 + })
  263 + .ToListAsync();
  264 + }
  265 +
  266 + // 按退卡ID分组品项明细
  267 + var itemDetailsGrouped = itemDetails.GroupBy(x => x.refundInfoId)
  268 + .ToDictionary(g => g.Key, g => g.ToList());
  269 +
  270 + // 按退卡ID分组健康师业绩
  271 + var jksyjGrouped = jksyjList.GroupBy(x => x.gltkbh)
  272 + .ToDictionary(g => g.Key, g => g.ToList());
  273 +
  274 + // 按退卡ID分组科技部老师业绩
  275 + var kjbsyjGrouped = kjbsyjList.GroupBy(x => x.gltkbh)
  276 + .ToDictionary(g => g.Key, g => g.ToList());
  277 +
  278 + // 为每个退卡记录分配品项明细、健康师业绩和科技部老师业绩
  279 + foreach (var item in data.list)
  280 + {
  281 + item.lqHytkMxList = itemDetailsGrouped.ContainsKey(item.id)
  282 + ? itemDetailsGrouped[item.id]
  283 + : new List<LqHytkMxInfoOutput>();
  284 + item.lqHytkJksyjList = jksyjGrouped.ContainsKey(item.id)
  285 + ? jksyjGrouped[item.id]
  286 + : new List<LqHytkJksyjInfoOutput>();
  287 + item.lqHytkKjbsyjList = kjbsyjGrouped.ContainsKey(item.id)
  288 + ? kjbsyjGrouped[item.id]
  289 + : new List<LqHytkKjbsyjInfoOutput>();
  290 + }
  291 +
126 292 return PageResult<LqHytkHytkListOutput>.SqlSugarPageResult(data);
127 293 }
128 294 #endregion
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
... ... @@ -45,6 +45,7 @@ using Yitter.IdGenerator;
45 45 using NCC.Extend.Entitys.lq_package_info;
46 46 using NCC.Extend.Entitys.lq_mdxx;
47 47 using NCC.Extend.Entitys.lq_card_transfer_log;
  48 +using NCC.Extend.Entitys.Dto.LqDailyReport;
48 49  
49 50 namespace NCC.Extend.LqKdKdjlb
50 51 {
... ... @@ -64,6 +65,7 @@ namespace NCC.Extend.LqKdKdjlb
64 65 private readonly WeChatBotService _weChatBotService;
65 66 private readonly LqKdKdjlbStringGenerator _stringGenerator;
66 67 private readonly ILogger<LqKdKdjlbService> _logger;
  68 + private readonly LqDailyReportService _dailyReportService;
67 69  
68 70 /// <summary>
69 71 /// 初始化一个<see cref="LqKdKdjlbService"/>类型的新实例
... ... @@ -76,7 +78,8 @@ namespace NCC.Extend.LqKdKdjlb
76 78 IUserManager userManager,
77 79 WeChatBotService weChatBotService,
78 80 LqKdKdjlbStringGenerator stringGenerator,
79   - ILogger<LqKdKdjlbService> logger
  81 + ILogger<LqKdKdjlbService> logger,
  82 + LqDailyReportService dailyReportService
80 83 )
81 84 {
82 85 _lqKdKdjlbRepository = lqKdKdjlbRepository;
... ... @@ -88,6 +91,7 @@ namespace NCC.Extend.LqKdKdjlb
88 91 _weChatBotService = weChatBotService;
89 92 _stringGenerator = stringGenerator;
90 93 _logger = logger;
  94 + _dailyReportService = dailyReportService;
91 95 }
92 96  
93 97 #region 获取开单记录表
... ... @@ -214,8 +218,49 @@ namespace NCC.Extend.LqKdKdjlb
214 218 List<string> queryKdrq = input.kdrq != null ? input.kdrq.Split(',').ToObeject<List<string>>() : null;
215 219 DateTime? startKdrq = queryKdrq != null ? Ext.GetDateTime(queryKdrq.First()) : null;
216 220 DateTime? endKdrq = queryKdrq != null ? Ext.GetDateTime(queryKdrq.Last()) : null;
217   - var data = await _db.Queryable<LqKdKdjlbEntity>()
218   - .WhereIF(!string.IsNullOrEmpty(input.keyword), p => p.Kdhyc.Contains(input.keyword) || p.Kdhysjh.Contains(input.keyword))
  221 +
  222 + // 根据是否传入健康师ID或科技部老师ID,动态构建查询
  223 + ISugarQueryable<LqKdKdjlbEntity> baseQuery = null;
  224 +
  225 + if (!string.IsNullOrEmpty(input.jksId) && !string.IsNullOrEmpty(input.kjblsId))
  226 + {
  227 + // 同时传入健康师ID和科技部老师ID,需要同时关联两个业绩表
  228 + baseQuery = _db.Queryable<LqKdJksyjEntity, LqKdKjbsyjEntity, LqKdKdjlbEntity>(
  229 + (jksyj, kjbsyj, kdjlb) => jksyj.Glkdbh == kdjlb.Id && kjbsyj.Glkdbh == kdjlb.Id)
  230 + .Where((jksyj, kjbsyj, kdjlb) => jksyj.Jkszh == input.jksId && jksyj.IsEffective == StatusEnum.有效.GetHashCode())
  231 + .Where((jksyj, kjbsyj, kdjlb) => kjbsyj.Kjbls == input.kjblsId && kjbsyj.IsEffective == StatusEnum.有效.GetHashCode())
  232 + .Select((jksyj, kjbsyj, kdjlb) => kdjlb)
  233 + .Distinct()
  234 + .MergeTable();
  235 + }
  236 + else if (!string.IsNullOrEmpty(input.jksId))
  237 + {
  238 + // 只传入健康师ID,关联健康师业绩表
  239 + baseQuery = _db.Queryable<LqKdJksyjEntity, LqKdKdjlbEntity>(
  240 + (jksyj, kdjlb) => jksyj.Glkdbh == kdjlb.Id)
  241 + .Where((jksyj, kdjlb) => jksyj.Jkszh == input.jksId && jksyj.IsEffective == StatusEnum.有效.GetHashCode())
  242 + .Select((jksyj, kdjlb) => kdjlb)
  243 + .Distinct()
  244 + .MergeTable();
  245 + }
  246 + else if (!string.IsNullOrEmpty(input.kjblsId))
  247 + {
  248 + // 只传入科技部老师ID,关联科技部老师业绩表
  249 + baseQuery = _db.Queryable<LqKdKjbsyjEntity, LqKdKdjlbEntity>(
  250 + (kjbsyj, kdjlb) => kjbsyj.Glkdbh == kdjlb.Id)
  251 + .Where((kjbsyj, kdjlb) => kjbsyj.Kjbls == input.kjblsId && kjbsyj.IsEffective == StatusEnum.有效.GetHashCode())
  252 + .Select((kjbsyj, kdjlb) => kdjlb)
  253 + .Distinct()
  254 + .MergeTable();
  255 + }
  256 + else
  257 + {
  258 + // 没有传入健康师ID或科技部老师ID,使用原来的查询逻辑
  259 + baseQuery = _db.Queryable<LqKdKdjlbEntity>();
  260 + }
  261 +
  262 + var data = await baseQuery
  263 + .WhereIF(!string.IsNullOrEmpty(input.keyword), p => p.Kdhyc.Contains(input.keyword) || p.Kdhysjh.Contains(input.keyword))
219 264 .WhereIF(!string.IsNullOrEmpty(input.id), p => p.Id.Contains(input.id))
220 265 .WhereIF(!string.IsNullOrEmpty(input.djmd), p => p.Djmd.Equals(input.djmd))
221 266 .WhereIF(!string.IsNullOrEmpty(input.jsj), p => p.Jsj.Equals(input.jsj))
... ... @@ -308,18 +353,380 @@ namespace NCC.Extend.LqKdKdjlb
308 353 var itemDetailsGrouped = itemDetails.GroupBy(x => x.glkdbh)
309 354 .ToDictionary(g => g.Key, g => g.ToList());
310 355  
311   - // 为每个开单记录分配品项明细
  356 + // 批量查询健康师业绩(性能优化:一次性查询所有开单的健康师业绩)
  357 + var jksyjList = new List<LqKdJksyjInfoOutput>();
  358 + if (billingIds.Any())
  359 + {
  360 + jksyjList = await _db.Queryable<LqKdJksyjEntity>()
  361 + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode())
  362 + .Select(x => new LqKdJksyjInfoOutput
  363 + {
  364 + id = x.Id,
  365 + glkdbh = x.Glkdbh,
  366 + kdpxid = x.Kdpxid,
  367 + jks = x.Jks,
  368 + jksxm = x.Jksxm,
  369 + jkszh = x.Jkszh,
  370 + jksyj = x.Jksyj,
  371 + yjsj = x.Yjsj,
  372 + jsj_id = x.Jsj_id,
  373 + isEffective = x.IsEffective
  374 + })
  375 + .ToListAsync();
  376 + }
  377 +
  378 + // 批量查询科技部老师业绩(性能优化:一次性查询所有开单的科技部老师业绩)
  379 + var kjbsyjList = new List<LqKdKjbsyjInfoOutput>();
  380 + if (billingIds.Any())
  381 + {
  382 + kjbsyjList = await _db.Queryable<LqKdKjbsyjEntity>()
  383 + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode())
  384 + .Select(x => new LqKdKjbsyjInfoOutput
  385 + {
  386 + id = x.Id,
  387 + glkdbh = x.Glkdbh,
  388 + kdpxid = x.Kdpxid,
  389 + kjbls = x.Kjbls,
  390 + kjblsxm = x.Kjblsxm,
  391 + kjblszh = x.Kjblszh,
  392 + kjblsyj = x.Kjblsyj,
  393 + yjsj = x.Yjsj,
  394 + isEffective = x.IsEffective
  395 + })
  396 + .ToListAsync();
  397 + }
  398 +
  399 + // 按开单ID分组健康师业绩
  400 + var jksyjGrouped = jksyjList.GroupBy(x => x.glkdbh)
  401 + .ToDictionary(g => g.Key, g => g.ToList());
  402 +
  403 + // 按开单ID分组科技部老师业绩
  404 + var kjbsyjGrouped = kjbsyjList.GroupBy(x => x.glkdbh)
  405 + .ToDictionary(g => g.Key, g => g.ToList());
  406 +
  407 + // 为每个开单记录分配品项明细、健康师业绩和科技部老师业绩
312 408 foreach (var item in data.list)
313 409 {
314 410 item.ItemDetails = itemDetailsGrouped.ContainsKey(item.id)
315 411 ? itemDetailsGrouped[item.id]
316 412 : new List<LqKdPxmxInfoOutput>();
  413 + item.lqKdJksyjList = jksyjGrouped.ContainsKey(item.id)
  414 + ? jksyjGrouped[item.id]
  415 + : new List<LqKdJksyjInfoOutput>();
  416 + item.lqKdKjbsyjList = kjbsyjGrouped.ContainsKey(item.id)
  417 + ? kjbsyjGrouped[item.id]
  418 + : new List<LqKdKjbsyjInfoOutput>();
317 419 }
318 420  
319 421 return PageResult<LqKdKdjlbListOutput>.SqlSugarPageResult(data);
320 422 }
321 423 #endregion
322 424  
  425 + #region 根据健康师ID获取开单列表
  426 + /// <summary>
  427 + /// 根据健康师ID获取开单列表
  428 + /// </summary>
  429 + /// <remarks>
  430 + /// 根据健康师ID查询该健康师参与的所有开单记录,支持时间周期查询和分页
  431 + ///
  432 + /// 示例请求:
  433 + /// GET /api/Extend/LqKdKdjlb/GetListByJksId?jksId=健康师ID&amp;startTime=2025-01-01&amp;endTime=2025-01-31&amp;currentPage=1&amp;pageSize=10
  434 + ///
  435 + /// 参数说明:
  436 + /// - jksId: 健康师ID(必填)
  437 + /// - startTime: 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  438 + /// - endTime: 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  439 + /// - djmd: 门店ID(可选)
  440 + /// - isEffective: 是否有效(可选,0=全部,1=有效,2=无效,默认1)
  441 + /// - currentPage: 当前页码(必填)
  442 + /// - pageSize: 每页数量(必填)
  443 + ///
  444 + /// 返回说明:
  445 + /// - 返回格式与GetList接口相同,包含开单基本信息及品项明细列表
  446 + /// </remarks>
  447 + /// <param name="input">查询参数</param>
  448 + /// <returns>开单列表(分页)</returns>
  449 + /// <response code="200">查询成功</response>
  450 + /// <response code="400">参数错误</response>
  451 + /// <response code="500">服务器内部错误</response>
  452 + [HttpGet("GetListByJksId")]
  453 + public async Task<dynamic> GetListByJksId([FromQuery] LqKdKdjlbListByJksQueryInput input)
  454 + {
  455 + try
  456 + {
  457 + if (string.IsNullOrEmpty(input.jksId))
  458 + {
  459 + throw NCCException.Oh("健康师ID不能为空");
  460 + }
  461 + var sidx = input.sidx == null ? "kdrq" : input.sidx;
  462 + var sort = string.IsNullOrEmpty(input.sort) ? "DESC" : input.sort;
  463 + // 解析时间范围
  464 + DateTime? startDate = null;
  465 + DateTime? endDate = null;
  466 + if (!string.IsNullOrEmpty(input.startTime))
  467 + {
  468 + startDate = Ext.GetDateTime(input.startTime);
  469 + }
  470 + if (!string.IsNullOrEmpty(input.endTime))
  471 + {
  472 + endDate = Ext.GetDateTime(input.endTime);
  473 + // 如果只传了日期,则设置为当天的23:59:59
  474 + if (endDate.HasValue && !input.endTime.Contains(":"))
  475 + {
  476 + endDate = new DateTime(endDate.Value.Year, endDate.Value.Month, endDate.Value.Day, 23, 59, 59);
  477 + }
  478 + }
  479 +
  480 + // 通过健康师业绩表关联查询开单记录
  481 + var data = await _db.Queryable<LqKdJksyjEntity, LqKdKdjlbEntity>((jksyj, kdjlb) => jksyj.Glkdbh == kdjlb.Id)
  482 + .Where((jksyj, kdjlb) => jksyj.Jkszh == input.jksId)
  483 + .WhereIF(input.isEffective != 0, (jksyj, kdjlb) => jksyj.IsEffective == input.isEffective && kdjlb.IsEffective == input.isEffective)
  484 + .WhereIF(input.isEffective == 0, (jksyj, kdjlb) => jksyj.IsEffective == StatusEnum.有效.GetHashCode() && kdjlb.IsEffective == StatusEnum.有效.GetHashCode())
  485 + .WhereIF(startDate.HasValue, (jksyj, kdjlb) => kdjlb.Kdrq >= startDate.Value)
  486 + .WhereIF(endDate.HasValue, (jksyj, kdjlb) => kdjlb.Kdrq <= endDate.Value)
  487 + .WhereIF(!string.IsNullOrEmpty(input.djmd), (jksyj, kdjlb) => kdjlb.Djmd == input.djmd)
  488 + .Select((jksyj, kdjlb) => new LqKdKdjlbListOutput
  489 + {
  490 + id = kdjlb.Id,
  491 + djmd = kdjlb.Djmd,
  492 + jsj = kdjlb.Jsj,
  493 + kdrq = kdjlb.Kdrq,
  494 + gjlx = kdjlb.Gjlx,
  495 + hgjg = kdjlb.Hgjg,
  496 + zdyj = kdjlb.Zdyj,
  497 + sfyj = kdjlb.Sfyj,
  498 + qk = kdjlb.Qk,
  499 + ckfs = kdjlb.Ckfs,
  500 + fkfs = kdjlb.Fkfs,
  501 + fkyy = kdjlb.Fkyy,
  502 + fkpd = kdjlb.Fkpd,
  503 + khly = kdjlb.Khly,
  504 + tjr = kdjlb.Tjr,
  505 + deductAmount = kdjlb.DeductAmount,
  506 + paidDebt = kdjlb.PaidDebt,
  507 + supplementBillingId = kdjlb.SupplementBillingId,
  508 + sfskdd = kdjlb.Sfskdd,
  509 + jj = kdjlb.Jj,
  510 + bz = kdjlb.Bz,
  511 + kdhy = kdjlb.Kdhy,
  512 + kdhyc = SqlFunc.Subqueryable<LqKhxxEntity>().Where(x => x.Id == kdjlb.Kdhy).Select(x => x.Khmc),
  513 + kdhysjh = SqlFunc.Subqueryable<LqKhxxEntity>().Where(x => x.Id == kdjlb.Kdhy).Select(x => x.Sjh),
  514 + isEffective = kdjlb.IsEffective,
  515 + createUser = kdjlb.CreateUser,
  516 + createUserName = SqlFunc.Subqueryable<UserEntity>().Where(x => x.Id == kdjlb.CreateUser).Select(x => x.RealName),
  517 + activityId = kdjlb.ActivityId,
  518 + activityName = SqlFunc.Subqueryable<LqPackageInfoEntity>().Where(x => x.Id == kdjlb.ActivityId).Select(x => x.ActivityName),
  519 + })
  520 + .MergeTable()
  521 + .Distinct() // 去重,因为一个开单可能对应多个健康师业绩记录
  522 + .OrderBy($"{sidx} {sort}")
  523 + .ToPagedListAsync(input.currentPage, input.pageSize);
  524 +
  525 + // 获取当前页的开单记录ID列表
  526 + var billingIds = data.list.Select(x => x.id).ToList();
  527 +
  528 + // 批量查询品项明细
  529 + var itemDetails = new List<LqKdPxmxInfoOutput>();
  530 + if (billingIds.Any())
  531 + {
  532 + itemDetails = await _db.Queryable<LqKdPxmxEntity>()
  533 + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode())
  534 + .Select(x => new LqKdPxmxInfoOutput
  535 + {
  536 + id = x.Id,
  537 + glkdbh = x.Glkdbh,
  538 + px = x.Px,
  539 + pxmc = x.Pxmc,
  540 + pxjg = x.Pxjg,
  541 + projectNumber = x.ProjectNumber,
  542 + isEnabled = x.IsEnabled,
  543 + sourceType = x.SourceType,
  544 + memberId = x.MemberId,
  545 + createTime = x.CreateTIme,
  546 + totalPrice = x.TotalPrice,
  547 + actualPrice = x.ActualPrice,
  548 + remark = x.Remark,
  549 + isEffective = x.IsEffective
  550 + })
  551 + .ToListAsync();
  552 + }
  553 +
  554 + // 按开单ID分组品项明细
  555 + var itemDetailsGrouped = itemDetails.GroupBy(x => x.glkdbh)
  556 + .ToDictionary(g => g.Key, g => g.ToList());
  557 +
  558 + // 为每个开单记录分配品项明细
  559 + foreach (var item in data.list)
  560 + {
  561 + item.ItemDetails = itemDetailsGrouped.ContainsKey(item.id)
  562 + ? itemDetailsGrouped[item.id]
  563 + : new List<LqKdPxmxInfoOutput>();
  564 + }
  565 +
  566 + return PageResult<LqKdKdjlbListOutput>.SqlSugarPageResult(data);
  567 + }
  568 + catch (Exception ex)
  569 + {
  570 + _logger.LogError(ex, $"根据健康师ID获取开单列表失败 - 健康师ID: {input?.jksId}, 开始时间: {input?.startTime}, 结束时间: {input?.endTime}");
  571 + throw NCCException.Oh($"根据健康师ID获取开单列表失败: {ex.Message}");
  572 + }
  573 + }
  574 + #endregion
  575 +
  576 + #region 根据科技部老师ID获取开单列表
  577 + /// <summary>
  578 + /// 根据科技部老师ID获取开单列表
  579 + /// </summary>
  580 + /// <remarks>
  581 + /// 根据科技部老师ID查询该老师参与的所有开单记录,支持时间周期查询和分页
  582 + ///
  583 + /// 示例请求:
  584 + /// GET /api/Extend/LqKdKdjlb/GetListByKjbId?kjblsId=科技部老师ID&amp;startTime=2025-01-01&amp;endTime=2025-01-31&amp;currentPage=1&amp;pageSize=10
  585 + ///
  586 + /// 参数说明:
  587 + /// - kjblsId: 科技部老师ID(必填)
  588 + /// - startTime: 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  589 + /// - endTime: 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  590 + /// - djmd: 门店ID(可选)
  591 + /// - isEffective: 是否有效(可选,0=全部,1=有效,2=无效,默认1)
  592 + /// - currentPage: 当前页码(必填)
  593 + /// - pageSize: 每页数量(必填)
  594 + ///
  595 + /// 返回说明:
  596 + /// - 返回格式与GetList接口相同,包含开单基本信息及品项明细列表
  597 + /// </remarks>
  598 + /// <param name="input">查询参数</param>
  599 + /// <returns>开单列表(分页)</returns>
  600 + /// <response code="200">查询成功</response>
  601 + /// <response code="400">参数错误</response>
  602 + /// <response code="500">服务器内部错误</response>
  603 + [HttpGet("GetListByKjbId")]
  604 + public async Task<dynamic> GetListByKjbId([FromQuery] LqKdKdjlbListByKjbQueryInput input)
  605 + {
  606 + try
  607 + {
  608 + if (string.IsNullOrEmpty(input.kjblsId))
  609 + {
  610 + throw NCCException.Oh("科技部老师ID不能为空");
  611 + }
  612 +
  613 + var sidx = input.sidx == null ? "kdrq" : input.sidx;
  614 + var sort = string.IsNullOrEmpty(input.sort) ? "DESC" : input.sort;
  615 +
  616 + // 解析时间范围
  617 + DateTime? startDate = null;
  618 + DateTime? endDate = null;
  619 + if (!string.IsNullOrEmpty(input.startTime))
  620 + {
  621 + startDate = Ext.GetDateTime(input.startTime);
  622 + }
  623 + if (!string.IsNullOrEmpty(input.endTime))
  624 + {
  625 + endDate = Ext.GetDateTime(input.endTime);
  626 + // 如果只传了日期,则设置为当天的23:59:59
  627 + if (endDate.HasValue && !input.endTime.Contains(":"))
  628 + {
  629 + endDate = new DateTime(endDate.Value.Year, endDate.Value.Month, endDate.Value.Day, 23, 59, 59);
  630 + }
  631 + }
  632 +
  633 + // 通过科技部老师业绩表关联查询开单记录
  634 + var data = await _db.Queryable<LqKdKjbsyjEntity, LqKdKdjlbEntity>(
  635 + (kjbsyj, kdjlb) => kjbsyj.Glkdbh == kdjlb.Id)
  636 + .Where((kjbsyj, kdjlb) => kjbsyj.Kjbls == input.kjblsId)
  637 + .WhereIF(input.isEffective != 0, (kjbsyj, kdjlb) => kjbsyj.IsEffective == input.isEffective && kdjlb.IsEffective == input.isEffective)
  638 + .WhereIF(input.isEffective == 0, (kjbsyj, kdjlb) => kjbsyj.IsEffective == StatusEnum.有效.GetHashCode() && kdjlb.IsEffective == StatusEnum.有效.GetHashCode())
  639 + .WhereIF(startDate.HasValue, (kjbsyj, kdjlb) => kdjlb.Kdrq >= startDate.Value)
  640 + .WhereIF(endDate.HasValue, (kjbsyj, kdjlb) => kdjlb.Kdrq <= endDate.Value)
  641 + .WhereIF(!string.IsNullOrEmpty(input.djmd), (kjbsyj, kdjlb) => kdjlb.Djmd == input.djmd)
  642 + .Select((kjbsyj, kdjlb) => new LqKdKdjlbListOutput
  643 + {
  644 + id = kdjlb.Id,
  645 + djmd = kdjlb.Djmd,
  646 + jsj = kdjlb.Jsj,
  647 + kdrq = kdjlb.Kdrq,
  648 + gjlx = kdjlb.Gjlx,
  649 + hgjg = kdjlb.Hgjg,
  650 + zdyj = kdjlb.Zdyj,
  651 + sfyj = kdjlb.Sfyj,
  652 + qk = kdjlb.Qk,
  653 + ckfs = kdjlb.Ckfs,
  654 + fkfs = kdjlb.Fkfs,
  655 + fkyy = kdjlb.Fkyy,
  656 + fkpd = kdjlb.Fkpd,
  657 + khly = kdjlb.Khly,
  658 + tjr = kdjlb.Tjr,
  659 + deductAmount = kdjlb.DeductAmount,
  660 + paidDebt = kdjlb.PaidDebt,
  661 + supplementBillingId = kdjlb.SupplementBillingId,
  662 + sfskdd = kdjlb.Sfskdd,
  663 + jj = kdjlb.Jj,
  664 + bz = kdjlb.Bz,
  665 + kdhy = kdjlb.Kdhy,
  666 + kdhyc = SqlFunc.Subqueryable<LqKhxxEntity>().Where(x => x.Id == kdjlb.Kdhy).Select(x => x.Khmc),
  667 + kdhysjh = SqlFunc.Subqueryable<LqKhxxEntity>().Where(x => x.Id == kdjlb.Kdhy).Select(x => x.Sjh),
  668 + isEffective = kdjlb.IsEffective,
  669 + createUser = kdjlb.CreateUser,
  670 + createUserName = SqlFunc.Subqueryable<UserEntity>().Where(x => x.Id == kdjlb.CreateUser).Select(x => x.RealName),
  671 + activityId = kdjlb.ActivityId,
  672 + activityName = SqlFunc.Subqueryable<LqPackageInfoEntity>().Where(x => x.Id == kdjlb.ActivityId).Select(x => x.ActivityName),
  673 + })
  674 + .MergeTable()
  675 + .Distinct() // 去重,因为一个开单可能对应多个科技部老师业绩记录
  676 + .OrderBy($"{sidx} {sort}")
  677 + .ToPagedListAsync(input.currentPage, input.pageSize);
  678 +
  679 + // 获取当前页的开单记录ID列表
  680 + var billingIds = data.list.Select(x => x.id).ToList();
  681 +
  682 + // 批量查询品项明细
  683 + var itemDetails = new List<LqKdPxmxInfoOutput>();
  684 + if (billingIds.Any())
  685 + {
  686 + itemDetails = await _db.Queryable<LqKdPxmxEntity>()
  687 + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode())
  688 + .Select(x => new LqKdPxmxInfoOutput
  689 + {
  690 + id = x.Id,
  691 + glkdbh = x.Glkdbh,
  692 + px = x.Px,
  693 + pxmc = x.Pxmc,
  694 + pxjg = x.Pxjg,
  695 + projectNumber = x.ProjectNumber,
  696 + isEnabled = x.IsEnabled,
  697 + sourceType = x.SourceType,
  698 + memberId = x.MemberId,
  699 + createTime = x.CreateTIme,
  700 + totalPrice = x.TotalPrice,
  701 + actualPrice = x.ActualPrice,
  702 + remark = x.Remark,
  703 + isEffective = x.IsEffective
  704 + })
  705 + .ToListAsync();
  706 + }
  707 +
  708 + // 按开单ID分组品项明细
  709 + var itemDetailsGrouped = itemDetails.GroupBy(x => x.glkdbh)
  710 + .ToDictionary(g => g.Key, g => g.ToList());
  711 +
  712 + // 为每个开单记录分配品项明细
  713 + foreach (var item in data.list)
  714 + {
  715 + item.ItemDetails = itemDetailsGrouped.ContainsKey(item.id)
  716 + ? itemDetailsGrouped[item.id]
  717 + : new List<LqKdPxmxInfoOutput>();
  718 + }
  719 +
  720 + return PageResult<LqKdKdjlbListOutput>.SqlSugarPageResult(data);
  721 + }
  722 + catch (Exception ex)
  723 + {
  724 + _logger.LogError(ex, $"根据科技部老师ID获取开单列表失败 - 科技部老师ID: {input?.kjblsId}, 开始时间: {input?.startTime}, 结束时间: {input?.endTime}");
  725 + throw NCCException.Oh($"根据科技部老师ID获取开单列表失败: {ex.Message}");
  726 + }
  727 + }
  728 + #endregion
  729 +
323 730 #region 新建开单记录表
324 731 /// <summary>
325 732 /// 新建开单记录表
... ... @@ -563,6 +970,47 @@ namespace NCC.Extend.LqKdKdjlb
563 970 // 字符串生成失败不影响主流程,只记录日志
564 971 Console.WriteLine($"生成开单记录字符串失败: {ex.Message}");
565 972 }
  973 +
  974 + // 播报事业部开单统计数据
  975 + try
  976 + {
  977 + //判断如果开单金额大于0,则播报事业部开单统计数据
  978 + if (newEntity.Sfyj > 0 && newEntity.Kdrq.HasValue)
  979 + {
  980 + var billingDate = newEntity.Kdrq.Value.ToString("yyyy-MM-dd");
  981 + var statisticsInput = new BusinessUnitBillingStatisticsInput
  982 + {
  983 + Date = billingDate
  984 + };
  985 + var statisticsText = await _dailyReportService.GetBusinessUnitBillingStatisticsText(statisticsInput);
  986 +
  987 + if (!string.IsNullOrEmpty(statisticsText) && !statisticsText.Contains("暂无开单数据"))
  988 + {
  989 + // 发送到企业微信群
  990 + try
  991 + {
  992 + var sendResult = await _weChatBotService.SendTextMessage(statisticsText);
  993 + if (sendResult)
  994 + {
  995 + Console.WriteLine("事业部开单统计数据已成功发送到企业微信群");
  996 + }
  997 + else
  998 + {
  999 + Console.WriteLine("事业部开单统计数据发送到企业微信群失败");
  1000 + }
  1001 + }
  1002 + catch (Exception wechatEx)
  1003 + {
  1004 + Console.WriteLine($"发送事业部开单统计数据异常: {wechatEx.Message}");
  1005 + }
  1006 + }
  1007 + }
  1008 + }
  1009 + catch (Exception ex)
  1010 + {
  1011 + // 播报失败不影响主流程,只记录日志
  1012 + Console.WriteLine($"播报事业部开单统计数据失败: {ex.Message}");
  1013 + }
566 1014 }
567 1015 catch (Exception ex)
568 1016 {
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs
... ... @@ -551,7 +551,8 @@ namespace NCC.Extend.LqKhxx
551 551 x.Pxmc,
552 552 x.Pxjg,
553 553 x.SourceType,
554   - x.ProjectNumber
  554 + x.ProjectNumber,
  555 + x.Remark
555 556 })
556 557 .ToListAsync();
557 558  
... ... @@ -600,6 +601,7 @@ namespace NCC.Extend.LqKhxx
600 601 ItemPrice = item.Pxjg,
601 602 SourceType = item.SourceType,
602 603 TotalPurchased = item.ProjectNumber,
  604 + Remark = item.Remark,
603 605 ConsumedCount = consumedData.FirstOrDefault(c => c.BillingItemId == item.Id)?.TotalConsumed ?? 0,
604 606 RefundedCount = refundedData.FirstOrDefault(r => r.BillingItemId == item.Id)?.TotalRefunded ?? 0,
605 607 DeductCount = deductData.FirstOrDefault(d => d.BillingItemId == item.Id)?.TotalDeduct ?? 0,
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqMdGeneralManagerLifelineService.cs
... ... @@ -7,10 +7,12 @@ using Mapster;
7 7 using Microsoft.AspNetCore.Mvc;
8 8 using NCC.Common.Core.Manager;
9 9 using NCC.Common.Enum;
  10 +using NCC.Common.Extension;
10 11 using NCC.Common.Filter;
11 12 using NCC.Dependency;
12 13 using NCC.DynamicApiController;
13 14 using NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline;
  15 +using NCC.Extend.Entitys.Enum;
14 16 using NCC.Extend.Entitys.lq_md_general_manager_lifeline;
15 17 using NCC.Extend.Entitys.lq_md_target;
16 18 using NCC.Extend.Interfaces.LqMdGeneralManagerLifeline;
... ... @@ -77,6 +79,7 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline
77 79 storeId = it.StoreId,
78 80 month = it.Month,
79 81 generalManagerId = it.GeneralManagerId,
  82 + managerType = it.ManagerType,
80 83 lifeline1 = it.Lifeline1,
81 84 commissionRate1 = it.CommissionRate1,
82 85 lifeline2 = it.Lifeline2,
... ... @@ -92,6 +95,21 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline
92 95 .MergeTable()
93 96 .OrderBy(sidx + " " + input.sort)
94 97 .ToPagedListAsync(input.currentPage, input.pageSize);
  98 +
  99 + // 设置经理类型中文名称
  100 + foreach (var item in data.list)
  101 + {
  102 + if (Enum.IsDefined(typeof(ManagerTypeEnum), item.managerType))
  103 + {
  104 + var enumValue = (ManagerTypeEnum)item.managerType;
  105 + item.managerTypeName = enumValue.GetDescription();
  106 + }
  107 + else
  108 + {
  109 + item.managerTypeName = string.Empty;
  110 + }
  111 + }
  112 +
95 113 return PageResult<LqMdGeneralManagerLifelineListOutput>.SqlSugarPageResult(data);
96 114 }
97 115 #endregion
... ... @@ -273,6 +291,7 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline
273 291 Id = YitIdHelper.NextId().ToString(),
274 292 StoreId = target.StoreId,
275 293 Month = target.Month,
  294 + ManagerType = ManagerTypeEnum.总经理.GetHashCode(),
276 295 GeneralManagerId = target.BusinessUnitGeneralManager,
277 296 Lifeline1 = 0,
278 297 CommissionRate1 = 0,
... ... @@ -299,14 +318,15 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline
299 318 Id = YitIdHelper.NextId().ToString(),
300 319 StoreId = target.StoreId,
301 320 Month = target.Month,
  321 + ManagerType = ManagerTypeEnum.经理.GetHashCode(),
302 322 GeneralManagerId = target.BusinessUnitManager,
303 323 Lifeline1 = 0,
304 324 CommissionRate1 = 0,
305   - Lifeline2 = null,
306   - CommissionRate2 = null,
307   - Lifeline3 = null,
308   - CommissionRate3 = null,
309   - Remark = null,
  325 + Lifeline2 = 0,
  326 + CommissionRate2 = 0,
  327 + Lifeline3 = 0,
  328 + CommissionRate3 = 0,
  329 + Remark = "",
310 330 CreateTime = DateTime.Now,
311 331 CreateUserId = userInfo.userId,
312 332 });
... ... @@ -405,6 +425,7 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline
405 425 Id = YitIdHelper.NextId().ToString(),
406 426 StoreId = p.StoreId,
407 427 Month = targetMonthStr,
  428 + ManagerType = p.ManagerType,
408 429 GeneralManagerId = p.GeneralManagerId,
409 430 Lifeline1 = p.Lifeline1,
410 431 CommissionRate1 = p.CommissionRate1,
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqPackageInfoService.cs
... ... @@ -14,6 +14,9 @@ using NCC.Extend.Entitys.Enum;
14 14 using NCC.Extend.Entitys.lq_package_info;
15 15 using NCC.Extend.Entitys.lq_package_item_detail;
16 16 using NCC.Extend.Entitys.lq_xmzl;
  17 +using NCC.Extend.Entitys.lq_kd_kdjlb;
  18 +using NCC.Extend.Entitys.lq_kd_pxmx;
  19 +using NCC.Extend.Entitys.lq_mdxx;
17 20 using NCC.Extend.Interfaces.LqPackageInfo;
18 21 using NCC.FriendlyException;
19 22 using SqlSugar;
... ... @@ -693,5 +696,404 @@ namespace NCC.Extend.LqPackageInfo
693 696 }
694 697 #endregion
695 698  
  699 + #region 营销活动按门店统计
  700 + /// <summary>
  701 + /// 获取营销活动按门店统计数据
  702 + /// </summary>
  703 + /// <remarks>
  704 + /// 统计指定营销活动在各个门店的开单数据
  705 + /// 包括:开单数量、开单金额、欠款金额、人头数、项目数
  706 + ///
  707 + /// 示例请求:
  708 + /// ```json
  709 + /// {
  710 + /// "activityId": "营销活动ID",
  711 + /// "startTime": "2025-10-01",
  712 + /// "endTime": "2025-10-31",
  713 + /// "storeIds": ["门店ID1", "门店ID2"]
  714 + /// }
  715 + /// ```
  716 + ///
  717 + /// 返回字段说明:
  718 + /// - ActivityId: 营销活动ID
  719 + /// - ActivityName: 营销活动名称
  720 + /// - StoreList: 门店统计列表
  721 + /// - StoreId: 门店ID
  722 + /// - StoreName: 门店名称
  723 + /// - BillingCount: 开单数量
  724 + /// - BillingAmount: 开单金额(实付业绩总和)
  725 + /// - DebtAmount: 欠款金额
  726 + /// - CustomerCount: 人头数(去重客户数)
  727 + /// - ItemCount: 项目数(品项项目次数总和,使用F_ProjectNumber字段)
  728 + /// </remarks>
  729 + /// <param name="input">查询参数</param>
  730 + /// <returns>按门店统计数据</returns>
  731 + /// <response code="200">成功返回统计数据</response>
  732 + /// <response code="400">参数错误</response>
  733 + /// <response code="500">服务器错误</response>
  734 + [HttpPost("get-activity-statistics-by-store")]
  735 + public async Task<object> GetActivityStatisticsByStore(ActivityStatisticsInput input)
  736 + {
  737 + try
  738 + {
  739 + // 1. 获取营销活动信息
  740 + var activity = await _db.Queryable<LqPackageInfoEntity>()
  741 + .Where(x => x.Id == input.ActivityId && x.IsEffective == StatusEnum.有效.GetHashCode())
  742 + .FirstAsync();
  743 +
  744 + if (activity == null)
  745 + {
  746 + throw NCCException.Oh("营销活动不存在或已失效");
  747 + }
  748 +
  749 + // 2. 设置时间范围(如果未提供,使用活动时间范围)
  750 + var startTime = input.StartTime ?? activity.StartTime;
  751 + var endTime = input.EndTime ?? activity.EndTime;
  752 +
  753 + // 3. 构建基础查询:开单记录 JOIN 门店表
  754 + var baseQuery = _db.Queryable<LqKdKdjlbEntity, LqMdxxEntity>(
  755 + (kd, md) => kd.Djmd == md.Id)
  756 + .Where((kd, md) => kd.IsEffective == StatusEnum.有效.GetHashCode())
  757 + .Where((kd, md) => kd.ActivityId == input.ActivityId)
  758 + .Where((kd, md) => kd.Kdrq.HasValue && kd.Kdrq.Value >= startTime && kd.Kdrq.Value <= endTime);
  759 +
  760 + // 4. 门店筛选
  761 + if (input.StoreIds != null && input.StoreIds.Any())
  762 + {
  763 + baseQuery = baseQuery.Where((kd, md) => input.StoreIds.Contains(kd.Djmd));
  764 + }
  765 +
  766 + // 5. 按门店分组统计(先获取基础统计数据)
  767 + var storeStatistics = await baseQuery
  768 + .GroupBy((kd, md) => new { StoreId = kd.Djmd, StoreName = md.Dm })
  769 + .Select((kd, md) => new
  770 + {
  771 + StoreId = kd.Djmd,
  772 + StoreName = md.Dm ?? "",
  773 + BillingCount = SqlFunc.AggregateCount(kd.Id),
  774 + BillingAmount = SqlFunc.AggregateSum(kd.Sfyj),
  775 + DebtAmount = SqlFunc.AggregateSum(kd.Qk)
  776 + })
  777 + .ToListAsync();
  778 +
  779 + // 6. 单独统计每个门店的人头数和项目数
  780 + var storeList = new List<StoreStatisticsItem>();
  781 + foreach (var stat in storeStatistics)
  782 + {
  783 + // 统计人头数(去重客户数)
  784 + var customerCountQuery = _db.Queryable<LqKdKdjlbEntity>()
  785 + .Where(kd => kd.Djmd == stat.StoreId
  786 + && kd.ActivityId == input.ActivityId
  787 + && kd.IsEffective == StatusEnum.有效.GetHashCode()
  788 + && kd.Kdrq.HasValue && kd.Kdrq.Value >= startTime && kd.Kdrq.Value <= endTime);
  789 +
  790 + if (input.StoreIds != null && input.StoreIds.Any())
  791 + {
  792 + customerCountQuery = customerCountQuery.Where(kd => input.StoreIds.Contains(kd.Djmd));
  793 + }
  794 +
  795 + var customerCount = await customerCountQuery
  796 + .GroupBy(kd => kd.Kdhy)
  797 + .Select(kd => kd.Kdhy)
  798 + .CountAsync();
  799 +
  800 + // 统计项目数(品项项目次数总和,使用F_ProjectNumber字段)
  801 + var itemCountQuery = _db.Queryable<LqKdPxmxEntity, LqKdKdjlbEntity>(
  802 + (px, kd) => px.Glkdbh == kd.Id)
  803 + .Where((px, kd) => kd.Djmd == stat.StoreId
  804 + && px.IsEffective == StatusEnum.有效.GetHashCode()
  805 + && kd.IsEffective == StatusEnum.有效.GetHashCode()
  806 + && kd.ActivityId == input.ActivityId
  807 + && kd.Kdrq.HasValue && kd.Kdrq.Value >= startTime && kd.Kdrq.Value <= endTime);
  808 +
  809 + if (input.StoreIds != null && input.StoreIds.Any())
  810 + {
  811 + itemCountQuery = itemCountQuery.Where((px, kd) => input.StoreIds.Contains(kd.Djmd));
  812 + }
  813 +
  814 + var itemCount = await itemCountQuery
  815 + .Select((px, kd) => SqlFunc.AggregateSum(px.ProjectNumber))
  816 + .FirstAsync();
  817 +
  818 + storeList.Add(new StoreStatisticsItem
  819 + {
  820 + StoreId = stat.StoreId ?? "",
  821 + StoreName = stat.StoreName ?? "",
  822 + BillingCount = stat.BillingCount,
  823 + BillingAmount = stat.BillingAmount,
  824 + DebtAmount = stat.DebtAmount,
  825 + CustomerCount = customerCount,
  826 + ItemCount = itemCount
  827 + });
  828 + }
  829 +
  830 + // 7. 排序
  831 + storeList = storeList.OrderBy(x => x.StoreName).ToList();
  832 +
  833 + // 7. 返回统计结果
  834 + return new ActivityStatisticsByStoreOutput
  835 + {
  836 + ActivityId = input.ActivityId,
  837 + ActivityName = activity.ActivityName,
  838 + StoreList = storeList
  839 + };
  840 + }
  841 + catch (Exception ex)
  842 + {
  843 + throw NCCException.Oh($"获取营销活动按门店统计数据失败: {ex.Message}");
  844 + }
  845 + }
  846 + #endregion
  847 +
  848 + #region 营销活动按品项统计
  849 + /// <summary>
  850 + /// 获取营销活动按品项统计数据
  851 + /// </summary>
  852 + /// <remarks>
  853 + /// 统计指定营销活动各个品项的销售情况
  854 + /// 包括:销售数量、销售金额、开单数量、销售次数
  855 + ///
  856 + /// 示例请求:
  857 + /// ```json
  858 + /// {
  859 + /// "activityId": "营销活动ID",
  860 + /// "startTime": "2025-10-01",
  861 + /// "endTime": "2025-10-31"
  862 + /// }
  863 + /// ```
  864 + /// </remarks>
  865 + /// <param name="input">查询参数</param>
  866 + /// <returns>按品项统计数据</returns>
  867 + /// <response code="200">成功返回统计数据</response>
  868 + /// <response code="400">参数错误</response>
  869 + /// <response code="500">服务器错误</response>
  870 + [HttpPost("get-activity-statistics-by-item")]
  871 + public async Task<object> GetActivityStatisticsByItem(ActivityStatisticsInput input)
  872 + {
  873 + try
  874 + {
  875 + // 1. 获取营销活动信息
  876 + var activity = await _db.Queryable<LqPackageInfoEntity>()
  877 + .Where(x => x.Id == input.ActivityId && x.IsEffective == StatusEnum.有效.GetHashCode())
  878 + .FirstAsync();
  879 +
  880 + if (activity == null)
  881 + {
  882 + throw NCCException.Oh("营销活动不存在或已失效");
  883 + }
  884 +
  885 + // 2. 设置时间范围(如果未提供,使用活动时间范围)
  886 + var startTime = input.StartTime ?? activity.StartTime;
  887 + var endTime = input.EndTime ?? activity.EndTime;
  888 +
  889 + // 3. 构建基础查询:品项明细 JOIN 开单记录(用于过滤活动ID和时间)
  890 + var baseQuery = _db.Queryable<LqKdPxmxEntity, LqKdKdjlbEntity>(
  891 + (px, kd) => px.Glkdbh == kd.Id)
  892 + .Where((px, kd) => px.IsEffective == StatusEnum.有效.GetHashCode())
  893 + .Where((px, kd) => kd.IsEffective == StatusEnum.有效.GetHashCode())
  894 + .Where((px, kd) => kd.ActivityId == input.ActivityId)
  895 + .Where((px, kd) => kd.Kdrq.HasValue && kd.Kdrq.Value >= startTime && kd.Kdrq.Value <= endTime);
  896 +
  897 + // 4. 门店筛选(如果提供)
  898 + if (input.StoreIds != null && input.StoreIds.Any())
  899 + {
  900 + baseQuery = baseQuery.Where((px, kd) => input.StoreIds.Contains(kd.Djmd));
  901 + }
  902 +
  903 + // 5. 按品项分组统计(先获取基础统计数据)
  904 + var itemStatistics = await baseQuery
  905 + .GroupBy((px, kd) => new { ItemId = px.Px, ItemName = px.Pxmc })
  906 + .Select((px, kd) => new
  907 + {
  908 + ItemId = px.Px ?? "",
  909 + ItemName = px.Pxmc ?? "",
  910 + SalesQuantity = SqlFunc.AggregateSum(px.ProjectNumber),
  911 + SalesAmount = SqlFunc.AggregateSum(px.ActualPrice > 0 ? px.ActualPrice : px.TotalPrice),
  912 + SalesCount = SqlFunc.AggregateCount(px.Id)
  913 + })
  914 + .ToListAsync();
  915 +
  916 + // 6. 单独统计每个品项的开单数量(去重开单ID)
  917 + var itemList = new List<ItemStatisticsItem>();
  918 + foreach (var stat in itemStatistics)
  919 + {
  920 + var billingCountQuery = _db.Queryable<LqKdPxmxEntity, LqKdKdjlbEntity>(
  921 + (px, kd) => px.Glkdbh == kd.Id)
  922 + .Where((px, kd) => px.Px == stat.ItemId
  923 + && px.IsEffective == StatusEnum.有效.GetHashCode()
  924 + && kd.IsEffective == StatusEnum.有效.GetHashCode()
  925 + && kd.ActivityId == input.ActivityId
  926 + && kd.Kdrq.HasValue && kd.Kdrq.Value >= startTime && kd.Kdrq.Value <= endTime);
  927 +
  928 + if (input.StoreIds != null && input.StoreIds.Any())
  929 + {
  930 + billingCountQuery = billingCountQuery.Where((px, kd) => input.StoreIds.Contains(kd.Djmd));
  931 + }
  932 +
  933 + var billingCount = await billingCountQuery
  934 + .GroupBy((px, kd) => px.Glkdbh)
  935 + .Select((px, kd) => px.Glkdbh)
  936 + .CountAsync();
  937 +
  938 + itemList.Add(new ItemStatisticsItem
  939 + {
  940 + ItemId = stat.ItemId ?? "",
  941 + ItemName = stat.ItemName ?? "",
  942 + SalesQuantity = stat.SalesQuantity,
  943 + SalesAmount = stat.SalesAmount,
  944 + BillingCount = billingCount,
  945 + SalesCount = stat.SalesCount
  946 + });
  947 + }
  948 +
  949 + // 7. 排序
  950 + itemList = itemList.OrderBy(x => x.ItemName).ToList();
  951 +
  952 + // 7. 返回统计结果
  953 + return new ActivityStatisticsByItemOutput
  954 + {
  955 + ActivityId = input.ActivityId,
  956 + ActivityName = activity.ActivityName,
  957 + ItemList = itemList
  958 + };
  959 + }
  960 + catch (Exception ex)
  961 + {
  962 + throw NCCException.Oh($"获取营销活动按品项统计数据失败: {ex.Message}");
  963 + }
  964 + }
  965 + #endregion
  966 +
  967 + #region 营销活动按门店品项统计
  968 + /// <summary>
  969 + /// 获取营销活动按门店品项统计数据
  970 + /// </summary>
  971 + /// <remarks>
  972 + /// 统计指定营销活动在各个门店的各个品项销售情况
  973 + /// 包括:销售数量、销售金额、开单数量、销售次数
  974 + ///
  975 + /// 示例请求:
  976 + /// ```json
  977 + /// {
  978 + /// "activityId": "营销活动ID",
  979 + /// "startTime": "2025-10-01",
  980 + /// "endTime": "2025-10-31",
  981 + /// "storeIds": ["门店ID1", "门店ID2"]
  982 + /// }
  983 + /// ```
  984 + /// </remarks>
  985 + /// <param name="input">查询参数</param>
  986 + /// <returns>按门店品项统计数据</returns>
  987 + /// <response code="200">成功返回统计数据</response>
  988 + /// <response code="400">参数错误</response>
  989 + /// <response code="500">服务器错误</response>
  990 + [HttpPost("get-activity-statistics-by-store-item")]
  991 + public async Task<object> GetActivityStatisticsByStoreItem(ActivityStatisticsInput input)
  992 + {
  993 + try
  994 + {
  995 + // 1. 获取营销活动信息
  996 + var activity = await _db.Queryable<LqPackageInfoEntity>()
  997 + .Where(x => x.Id == input.ActivityId && x.IsEffective == StatusEnum.有效.GetHashCode())
  998 + .FirstAsync();
  999 +
  1000 + if (activity == null)
  1001 + {
  1002 + throw NCCException.Oh("营销活动不存在或已失效");
  1003 + }
  1004 +
  1005 + // 2. 设置时间范围(如果未提供,使用活动时间范围)
  1006 + var startTime = input.StartTime ?? activity.StartTime;
  1007 + var endTime = input.EndTime ?? activity.EndTime;
  1008 +
  1009 + // 3. 构建基础查询:品项明细 JOIN 开单记录 JOIN 门店表
  1010 + var baseQuery = _db.Queryable<LqKdPxmxEntity, LqKdKdjlbEntity, LqMdxxEntity>(
  1011 + (px, kd, md) => px.Glkdbh == kd.Id && kd.Djmd == md.Id)
  1012 + .Where((px, kd, md) => px.IsEffective == StatusEnum.有效.GetHashCode())
  1013 + .Where((px, kd, md) => kd.IsEffective == StatusEnum.有效.GetHashCode())
  1014 + .Where((px, kd, md) => kd.ActivityId == input.ActivityId)
  1015 + .Where((px, kd, md) => kd.Kdrq.HasValue && kd.Kdrq.Value >= startTime && kd.Kdrq.Value <= endTime);
  1016 +
  1017 + // 4. 门店筛选(如果提供)
  1018 + if (input.StoreIds != null && input.StoreIds.Any())
  1019 + {
  1020 + baseQuery = baseQuery.Where((px, kd, md) => input.StoreIds.Contains(kd.Djmd));
  1021 + }
  1022 +
  1023 + // 5. 按门店和品项分组统计(先获取基础统计数据)
  1024 + var storeItemStatistics = await baseQuery
  1025 + .GroupBy((px, kd, md) => new
  1026 + {
  1027 + StoreId = kd.Djmd,
  1028 + StoreName = md.Dm,
  1029 + ItemId = px.Px,
  1030 + ItemName = px.Pxmc
  1031 + })
  1032 + .Select((px, kd, md) => new
  1033 + {
  1034 + StoreId = kd.Djmd ?? "",
  1035 + StoreName = md.Dm ?? "",
  1036 + ItemId = px.Px ?? "",
  1037 + ItemName = px.Pxmc ?? "",
  1038 + SalesQuantity = SqlFunc.AggregateSum(px.ProjectNumber),
  1039 + SalesAmount = SqlFunc.AggregateSum(px.ActualPrice > 0 ? px.ActualPrice : px.TotalPrice),
  1040 + SalesCount = SqlFunc.AggregateCount(px.Id)
  1041 + })
  1042 + .ToListAsync();
  1043 +
  1044 + // 6. 单独统计每个门店品项的开单数量(去重开单ID)
  1045 + var storeItemList = new List<StoreItemStatisticsItem>();
  1046 + foreach (var stat in storeItemStatistics)
  1047 + {
  1048 + var billingCountQuery = _db.Queryable<LqKdPxmxEntity, LqKdKdjlbEntity>(
  1049 + (px, kd) => px.Glkdbh == kd.Id)
  1050 + .Where((px, kd) => px.Px == stat.ItemId
  1051 + && kd.Djmd == stat.StoreId
  1052 + && px.IsEffective == StatusEnum.有效.GetHashCode()
  1053 + && kd.IsEffective == StatusEnum.有效.GetHashCode()
  1054 + && kd.ActivityId == input.ActivityId
  1055 + && kd.Kdrq.HasValue && kd.Kdrq.Value >= startTime && kd.Kdrq.Value <= endTime);
  1056 +
  1057 + if (input.StoreIds != null && input.StoreIds.Any())
  1058 + {
  1059 + billingCountQuery = billingCountQuery.Where((px, kd) => input.StoreIds.Contains(kd.Djmd));
  1060 + }
  1061 +
  1062 + var billingCount = await billingCountQuery
  1063 + .GroupBy((px, kd) => px.Glkdbh)
  1064 + .Select((px, kd) => px.Glkdbh)
  1065 + .CountAsync();
  1066 +
  1067 + storeItemList.Add(new StoreItemStatisticsItem
  1068 + {
  1069 + StoreId = stat.StoreId ?? "",
  1070 + StoreName = stat.StoreName ?? "",
  1071 + ItemId = stat.ItemId ?? "",
  1072 + ItemName = stat.ItemName ?? "",
  1073 + SalesQuantity = stat.SalesQuantity,
  1074 + SalesAmount = stat.SalesAmount,
  1075 + BillingCount = billingCount,
  1076 + SalesCount = stat.SalesCount
  1077 + });
  1078 + }
  1079 +
  1080 + // 7. 排序
  1081 + storeItemList = storeItemList.OrderBy(x => x.StoreName).ThenBy(x => x.ItemName).ToList();
  1082 +
  1083 + // 7. 返回统计结果
  1084 + return new ActivityStatisticsByStoreItemOutput
  1085 + {
  1086 + ActivityId = input.ActivityId,
  1087 + ActivityName = activity.ActivityName,
  1088 + StoreItemList = storeItemList
  1089 + };
  1090 + }
  1091 + catch (Exception ex)
  1092 + {
  1093 + throw NCCException.Oh($"获取营销活动按门店品项统计数据失败: {ex.Message}");
  1094 + }
  1095 + }
  1096 + #endregion
  1097 +
696 1098 }
697 1099 }
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs
... ... @@ -28,8 +28,11 @@ using NCC.Extend.Entitys.lq_kd_kjbsyj;
28 28 using NCC.Extend.Entitys.lq_mdxx;
29 29 using NCC.Extend.Entitys.lq_md_xdbhsj;
30 30 using NCC.Extend.Entitys.lq_xh_kjbsyj;
  31 +using NCC.Extend.Entitys.lq_xh_hyhk;
  32 +using NCC.Extend.Entitys.lq_xh_pxmx;
31 33 using NCC.Extend.Entitys.lq_ycsd_jsj;
32 34 using NCC.Extend.Entitys.lq_yjmxb;
  35 +using NCC.Extend.Entitys.Enum;
33 36 using NCC.Extend.Entitys.lq_statistics_gold_triangle;
34 37 using NCC.Extend.Entitys.lq_statistics_personal_performance;
35 38 using NCC.Extend.Entitys.lq_statistics_store_consume_performance;
... ... @@ -831,120 +834,183 @@ namespace NCC.Extend.LqStatistics
831 834 /// <summary>
832 835 /// 获取科技部老师业绩统计
833 836 /// </summary>
  837 + /// <remarks>
  838 + /// 统计科技部老师的开单业绩、消耗业绩、手工费等相关数据
  839 + ///
  840 + /// 示例请求:
  841 + /// ```json
  842 + /// {
  843 + /// "startDate": "2025-01-01T00:00:00",
  844 + /// "endDate": "2025-01-31T23:59:59",
  845 + /// "teacherId": "科技部老师ID(可选)",
  846 + /// "teacherName": "科技部老师姓名(可选)"
  847 + /// }
  848 + /// ```
  849 + ///
  850 + /// 参数说明:
  851 + /// - startDate: 开始日期(可选)
  852 + /// - endDate: 结束日期(可选)
  853 + /// - teacherId: 科技部老师ID(可选)
  854 + /// - teacherName: 科技部老师姓名(可选)
  855 + ///
  856 + /// 返回数据说明:
  857 + /// - DepartmentName: 部门名称(固定为"科技部")
  858 + /// - TeacherName: 老师姓名
  859 + /// - ConsumeProjectCount: 消耗项目数
  860 + /// - ConsumeAchievement: 消耗业绩
  861 + /// - OrderAchievement: 开单业绩(开卡业绩)
  862 + /// - OrderItemCount: 开单品项次数
  863 + /// - ConsumeItemCount: 耗卡品项次数
  864 + /// - ConsumeLaborCost: 消耗手工费(耗卡手工费)
  865 + /// </remarks>
834 866 /// <param name="input">查询参数</param>
835   - /// <returns>科技部老师业绩统计结果</returns>
  867 + /// <returns>科技部老师业绩统计结果列表,包含开单业绩、消耗业绩、手工费等数据</returns>
  868 + /// <response code="200">成功返回统计数据</response>
  869 + /// <response code="400">参数错误</response>
  870 + /// <response code="500">服务器内部错误</response>
836 871 [HttpPost("GetTechTeacherStatistics")]
837 872 [AllowAnonymous]
838 873 public async Task<List<TechTeacherSimpleStatisticsOutput>> GetTechTeacherStatistics(TechTeacherStatisticsInput input)
839 874 {
840 875 try
841   - { // 1. 从用户表获取所有科技部老师
842   - var allTeachers = await _db.Queryable<UserEntity>()
843   - .Where(x => x.Gw == "科技老师")
  876 + {
  877 + // 1. 验证必须传入科技老师ID
  878 + if (string.IsNullOrEmpty(input.TeacherId))
  879 + {
  880 + return new List<TechTeacherSimpleStatisticsOutput>
  881 + {
  882 + new TechTeacherSimpleStatisticsOutput
  883 + {
  884 + DepartmentName = "科技部",
  885 + TeacherName = "",
  886 + OrderAchievement = 0m,
  887 + OrderItemCount = 0,
  888 + ConsumeAchievement = 0m,
  889 + ConsumeItemCount = 0,
  890 + ConsumeProjectCount = 0,
  891 + ConsumeLaborCost = 0m,
  892 + }
  893 + };
  894 + }
  895 +
  896 + // 2. 获取科技老师信息
  897 + var teacher = await _db.Queryable<UserEntity>()
  898 + .Where(x => x.Gw == "科技老师" && x.Id == input.TeacherId)
844 899 .Select(x => new
845 900 {
846 901 TeacherId = x.Id,
847 902 TeacherName = x.RealName,
848 903 TeacherAccount = x.Account,
849 904 })
850   - .ToListAsync();
851   -
852   - // 2. 获取业绩流水数据
853   - var flowQuery = _db.Queryable<VTechTeacherFlowEntity>();
  905 + .FirstAsync();
854 906  
855   - // 老师过滤
856   - if (!string.IsNullOrEmpty(input.TeacherId))
  907 + if (teacher == null)
857 908 {
858   - flowQuery = flowQuery.Where(x => x.TeacherId == input.TeacherId);
  909 + return new List<TechTeacherSimpleStatisticsOutput>
  910 + {
  911 + new TechTeacherSimpleStatisticsOutput
  912 + {
  913 + DepartmentName = "科技部",
  914 + TeacherName = "",
  915 + OrderAchievement = 0m,
  916 + OrderItemCount = 0,
  917 + ConsumeAchievement = 0m,
  918 + ConsumeItemCount = 0,
  919 + ConsumeProjectCount = 0,
  920 + ConsumeLaborCost = 0m,
  921 + }
  922 + };
859 923 }
860 924  
861   - if (!string.IsNullOrEmpty(input.TeacherName))
862   - {
863   - flowQuery = flowQuery.Where(x => x.TeacherName.Contains(input.TeacherName));
864   - }
  925 + // 3. 查询开单业绩(从 lq_kd_kjbsyj 关联 lq_kd_kdjlb 和 lq_kd_pxmx)
  926 + var orderQuery = _db.Queryable<LqKdKjbsyjEntity, LqKdKdjlbEntity, LqKdPxmxEntity>(
  927 + (kjbsyj, kdjlb, pxmx) => kjbsyj.Glkdbh == kdjlb.Id && kjbsyj.Kdpxid == pxmx.Id)
  928 + .Where((kjbsyj, kdjlb, pxmx) => kjbsyj.IsEffective == StatusEnum.有效.GetHashCode())
  929 + .Where((kjbsyj, kdjlb, pxmx) => kdjlb.IsEffective == StatusEnum.有效.GetHashCode())
  930 + .Where((kjbsyj, kdjlb, pxmx) => kjbsyj.Kjblszh == teacher.TeacherAccount);
865 931  
866 932 // 日期过滤
867 933 if (input.StartDate.HasValue)
868 934 {
869   - flowQuery = flowQuery.Where(x => x.BusinessDate >= input.StartDate.Value);
  935 + orderQuery = orderQuery.Where((kjbsyj, kdjlb, pxmx) => kjbsyj.Yjsj >= input.StartDate.Value);
870 936 }
871 937  
872 938 if (input.EndDate.HasValue)
873 939 {
874   - flowQuery = flowQuery.Where(x => x.BusinessDate <= input.EndDate.Value);
  940 + orderQuery = orderQuery.Where((kjbsyj, kdjlb, pxmx) => kjbsyj.Yjsj <= input.EndDate.Value);
875 941 }
876 942  
877   - var flowRecords = await flowQuery.ToListAsync();
878   -
879   - // 3. 按老师分组统计业绩数据
880   - var teacherStatsDict = flowRecords
881   - .GroupBy(x => new
  943 + var orderStats = await orderQuery
  944 + .Select((kjbsyj, kdjlb, pxmx) => new
882 945 {
883   - x.TeacherId,
884   - x.TeacherName,
885   - x.TeacherAccount,
  946 + OrderAchievement = SqlFunc.ToDecimal(kjbsyj.Kjblsyj),
  947 + OrderItemCount = SqlFunc.ToInt32(pxmx.ProjectNumber),
886 948 })
887   - .ToDictionary(
888   - g => g.Key,
889   - g => new
890   - {
891   - ConsumeProjectCount = (int)g.Where(x => x.BusinessType == "耗卡").Sum(x => x.ProjectCount),
892   - ConsumeAchievement = g.Where(x => x.BusinessType == "耗卡").Sum(x => x.Achievement),
893   - OrderAchievement = g.Where(x => x.BusinessType == "开卡").Sum(x => x.Achievement),
894   - OrderItemCount = g.Where(x => x.BusinessType == "开卡").Sum(x => x.ItemCount),
895   - ConsumeItemCount = g.Where(x => x.BusinessType == "耗卡").Sum(x => x.ItemCount),
896   - }
897   - );
  949 + .ToListAsync();
898 950  
899   - // 4. 构建结果,包含所有老师
900   - var result = new List<TechTeacherSimpleStatisticsOutput>();
  951 + // 4. 查询耗卡业绩(从 lq_xh_kjbsyj 关联 lq_xh_hyhk 和 lq_xh_pxmx)
  952 + // 注意:lq_xh_kjbsyj.kjbls 字段存储的是健康师id,不是科技部老师id
  953 + // 科技部老师信息在 kjblszh(账号)和 kjblsxm(姓名)字段
  954 + var consumeQuery = _db.Queryable<LqXhKjbsyjEntity, LqXhHyhkEntity, LqXhPxmxEntity>(
  955 + (kjbsyj, hyhk, pxmx) => kjbsyj.Glkdbh == hyhk.Id && kjbsyj.Hkpxid == pxmx.Id)
  956 + .Where((kjbsyj, hyhk, pxmx) => kjbsyj.IsEffective == StatusEnum.有效.GetHashCode())
  957 + .Where((kjbsyj, hyhk, pxmx) => hyhk.IsEffective == StatusEnum.有效.GetHashCode())
  958 + .Where((kjbsyj, hyhk, pxmx) => kjbsyj.Kjblszh == teacher.TeacherAccount);
901 959  
902   - foreach (var teacher in allTeachers)
  960 + // 日期过滤
  961 + if (input.StartDate.HasValue)
903 962 {
904   - // 应用过滤条件
905   - if (!string.IsNullOrEmpty(input.TeacherId) && teacher.TeacherId != input.TeacherId)
906   - continue;
907   -
908   - if (!string.IsNullOrEmpty(input.TeacherName) && !teacher.TeacherName.Contains(input.TeacherName))
909   - continue;
  963 + consumeQuery = consumeQuery.Where((kjbsyj, hyhk, pxmx) => kjbsyj.Yjsj >= input.StartDate.Value);
  964 + }
910 965  
911   - var stats = teacherStatsDict.GetValueOrDefault(
912   - new
913   - {
914   - TeacherId = teacher.TeacherId,
915   - TeacherName = teacher.TeacherName,
916   - TeacherAccount = teacher.TeacherAccount,
917   - },
918   - new
919   - {
920   - ConsumeProjectCount = 0,
921   - ConsumeAchievement = 0m,
922   - OrderAchievement = 0m,
923   - OrderItemCount = 0,
924   - ConsumeItemCount = 0,
925   - }
926   - );
  966 + if (input.EndDate.HasValue)
  967 + {
  968 + consumeQuery = consumeQuery.Where((kjbsyj, hyhk, pxmx) => kjbsyj.Yjsj <= input.EndDate.Value);
  969 + }
927 970  
928   - var teacherStats = new TechTeacherSimpleStatisticsOutput
  971 + var consumeStats = await consumeQuery
  972 + .Select((kjbsyj, hyhk, pxmx) => new
929 973 {
930   - DepartmentName = "科技部", // 固定为科技部
931   - TeacherName = teacher.TeacherName,
932   - ConsumeProjectCount = stats.ConsumeProjectCount,
933   - ConsumeAchievement = stats.ConsumeAchievement,
934   - OrderAchievement = stats.OrderAchievement,
935   - OrderItemCount = stats.OrderItemCount,
936   - ConsumeItemCount = stats.ConsumeItemCount,
937   - };
  974 + ConsumeAchievement = kjbsyj.Kjblsyj,
  975 + ConsumeItemCount = SqlFunc.ToInt32(pxmx.ProjectNumber),
  976 + ConsumeProjectCount = SqlFunc.ToInt32(kjbsyj.HdpxNumber),
  977 + ConsumeLaborCost = kjbsyj.LaborCost,
  978 + })
  979 + .ToListAsync();
938 980  
939   - result.Add(teacherStats);
940   - }
  981 + // 5. 统计并返回结果
  982 + var result = new TechTeacherSimpleStatisticsOutput
  983 + {
  984 + DepartmentName = "科技部",
  985 + TeacherName = teacher.TeacherName,
  986 + OrderAchievement = orderStats.Sum(x => x.OrderAchievement != null && decimal.TryParse(x.OrderAchievement.ToString(), out var val) ? val : 0m),
  987 + OrderItemCount = orderStats.Sum(x => x.OrderItemCount),
  988 + ConsumeAchievement = consumeStats.Sum(x => x.ConsumeAchievement ?? 0m),
  989 + ConsumeItemCount = consumeStats.Sum(x => x.ConsumeItemCount),
  990 + ConsumeProjectCount = consumeStats.Sum(x => x.ConsumeProjectCount),
  991 + ConsumeLaborCost = consumeStats.Sum(x => x.ConsumeLaborCost ?? 0m),
  992 + };
941 993  
942   - return result;
  994 + return new List<TechTeacherSimpleStatisticsOutput> { result };
943 995 }
944 996 catch (Exception ex)
945 997 {
946 998 _logger.LogError(ex, "获取科技部老师业绩统计时发生错误");
947   - throw NCCException.Oh("获取科技部老师业绩统计失败", ex);
  999 + // 发生错误时返回全0的结果,而不是抛出异常
  1000 + return new List<TechTeacherSimpleStatisticsOutput>
  1001 + {
  1002 + new TechTeacherSimpleStatisticsOutput
  1003 + {
  1004 + DepartmentName = "科技部",
  1005 + TeacherName = "",
  1006 + OrderAchievement = 0m,
  1007 + OrderItemCount = 0,
  1008 + ConsumeAchievement = 0m,
  1009 + ConsumeItemCount = 0,
  1010 + ConsumeProjectCount = 0,
  1011 + ConsumeLaborCost = 0m,
  1012 + }
  1013 + };
948 1014 }
949 1015 }
950 1016  
... ... @@ -3672,6 +3738,5 @@ namespace NCC.Extend.LqStatistics
3672 3738 }
3673 3739  
3674 3740 #endregion
3675   -
3676 3741 }
3677 3742 }
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs
... ... @@ -1043,12 +1043,18 @@ namespace NCC.Extend.LqXhHyhk
1043 1043 Kjblsyj = ikjbs_tem.kjblsyj,
1044 1044 Yjsj = DateTime.Now,
1045 1045 Hkpxid = lqXhPxmxEntity.Id,
  1046 + // OriginalHdpxNumber = ikjbs_tem.hdpxNumber,
  1047 + // OvertimeHdpxNumber = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0)),
  1048 + // HdpxNumber = (decimal)((ikjbs_tem.hdpxNumber ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0))),
1046 1049 OriginalHdpxNumber = ikjbs_tem.hdpxNumber,
1047   - OvertimeHdpxNumber = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0)),
1048   - HdpxNumber = (decimal)((ikjbs_tem.hdpxNumber ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0))),
  1050 + OvertimeHdpxNumber = 0,
  1051 + HdpxNumber = ikjbs_tem.hdpxNumber,
  1052 + // OriginalLaborCost = ikjbs_tem.laborCost,
  1053 + // OvertimeLaborCost = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0)),
  1054 + // LaborCost = (decimal)((ikjbs_tem.laborCost ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0))),
1049 1055 OriginalLaborCost = ikjbs_tem.laborCost,
1050   - OvertimeLaborCost = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0)),
1051   - LaborCost = (decimal)((ikjbs_tem.laborCost ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0))),
  1056 + OvertimeLaborCost = 0,
  1057 + LaborCost = ikjbs_tem.laborCost,
1052 1058 IsEffective = StatusEnum.有效.GetHashCode(),
1053 1059 }
1054 1060 );
... ... @@ -1328,12 +1334,18 @@ namespace NCC.Extend.LqXhHyhk
1328 1334 Kjblsyj = ikjbs_tem.kjblsyj,
1329 1335 Yjsj = DateTime.Now,
1330 1336 Hkpxid = lqXhPxmxEntity.Id,
  1337 + // OriginalHdpxNumber = ikjbs_tem.hdpxNumber,
  1338 + // OvertimeHdpxNumber = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0)),
  1339 + // HdpxNumber = (decimal)((ikjbs_tem.hdpxNumber ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0))),
  1340 + // OriginalLaborCost = ikjbs_tem.laborCost,
  1341 + // OvertimeLaborCost = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0)),
  1342 + // LaborCost = (decimal)((ikjbs_tem.laborCost ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0))),
1331 1343 OriginalHdpxNumber = ikjbs_tem.hdpxNumber,
1332   - OvertimeHdpxNumber = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0)),
1333   - HdpxNumber = (decimal)((ikjbs_tem.hdpxNumber ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0))),
  1344 + OvertimeHdpxNumber = 0,
  1345 + HdpxNumber = ikjbs_tem.hdpxNumber,
1334 1346 OriginalLaborCost = ikjbs_tem.laborCost,
1335   - OvertimeLaborCost = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0)),
1336   - LaborCost = (decimal)((ikjbs_tem.laborCost ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0))),
  1347 + OvertimeLaborCost = 0,
  1348 + LaborCost = ikjbs_tem.laborCost,
1337 1349 IsEffective = StatusEnum.有效.GetHashCode(),
1338 1350 });
1339 1351 }
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqYaoyjlService.cs
... ... @@ -93,6 +93,7 @@ namespace NCC.Extend.LqYaoyjl
93 93 .WhereIF(queryLxsj != null, p => p.Lxsj >= new DateTime(startLxsj.ToDate().Year, startLxsj.ToDate().Month, startLxsj.ToDate().Day, 0, 0, 0))
94 94 .WhereIF(queryLxsj != null, p => p.Lxsj <= new DateTime(endLxsj.ToDate().Year, endLxsj.ToDate().Month, endLxsj.ToDate().Day, 23, 59, 59))
95 95 .WhereIF(!string.IsNullOrEmpty(input.lxjl), p => p.Lxjl.Contains(input.lxjl))
  96 + .WhereIF(!string.IsNullOrEmpty(input.storeId), p => p.StoreId.Equals(input.storeId))
96 97 .Select(it => new LqYaoyjlListOutput
97 98 {
98 99 id = it.Id,
... ... @@ -158,6 +159,7 @@ namespace NCC.Extend.LqYaoyjl
158 159 .WhereIF(queryLxsj != null, p => p.Lxsj >= new DateTime(startLxsj.ToDate().Year, startLxsj.ToDate().Month, startLxsj.ToDate().Day, 0, 0, 0))
159 160 .WhereIF(queryLxsj != null, p => p.Lxsj <= new DateTime(endLxsj.ToDate().Year, endLxsj.ToDate().Month, endLxsj.ToDate().Day, 23, 59, 59))
160 161 .WhereIF(!string.IsNullOrEmpty(input.lxjl), p => p.Lxjl.Contains(input.lxjl))
  162 + .WhereIF(!string.IsNullOrEmpty(input.storeId), p => p.StoreId.Equals(input.storeId))
161 163 .Select(it => new LqYaoyjlListOutput
162 164 {
163 165 id = it.Id,
... ...
netcore/src/Modularity/Extend/NCC.Extend/Utils/WeChatBotService.cs
... ... @@ -3,6 +3,7 @@ using System.Net.Http;
3 3 using System.Text;
4 4 using System.Threading.Tasks;
5 5 using Newtonsoft.Json;
  6 +using NCC;
6 7  
7 8 namespace NCC.Extend.Utils
8 9 {
... ... @@ -12,17 +13,28 @@ namespace NCC.Extend.Utils
12 13 public class WeChatBotService
13 14 {
14 15 private readonly HttpClient _httpClient;
15   - private const string BOT_API_URL = "http://wx.lvqianmeiye.com/api/Bot/send-text";
16   - //正式地址
17   - //https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=581c22a6-cb67-42e5-8c76-b8e90052e188
18   - //测试地址
19   - //https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=6f8686ec-5011-4c1d-bae9-d82a2a2f4d83
20   - private const string WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=496f1add-122b-43fc-9e38-0ca79c48b33f";
21   - private const string WEBHOOK_URL_TEST = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=6f8686ec-5011-4c1d-bae9-d82a2a2f4d83";
  16 + private readonly string _botApiUrl;
  17 + private readonly string _webhookUrl;
22 18  
  19 + /// <summary>
  20 + /// 初始化企业微信机器人服务
  21 + /// </summary>
  22 + /// <param name="httpClient">HTTP客户端</param>
23 23 public WeChatBotService(HttpClient httpClient)
24 24 {
25 25 _httpClient = httpClient;
  26 +
  27 + // 从配置文件中读取企业微信机器人配置
  28 + _botApiUrl = App.Configuration["WeChatBot:BotApiUrl"] ?? "http://wx.lvqianmeiye.com/api/Bot/send-text";
  29 +
  30 + // 从配置文件中读取Webhook地址(正式或测试地址,通过配置文件切换)
  31 + _webhookUrl = App.Configuration["WeChatBot:WebhookUrl"];
  32 +
  33 + // 如果配置文件中没有配置,使用默认值
  34 + if (string.IsNullOrEmpty(_webhookUrl))
  35 + {
  36 + _webhookUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=496f1add-122b-43fc-9e38-0ca79c48b33f";
  37 + }
26 38 }
27 39  
28 40 /// <summary>
... ... @@ -36,8 +48,7 @@ namespace NCC.Extend.Utils
36 48 {
37 49 var requestData = new
38 50 {
39   - webhookUrl = WEBHOOK_URL,
40   - // webhookUrl = WEBHOOK_URL_TEST,
  51 + webhookUrl = _webhookUrl,
41 52 content = content,
42 53 mentionedList = (string)null,
43 54 mentionedMobileList = (string)null,
... ... @@ -46,7 +57,7 @@ namespace NCC.Extend.Utils
46 57 var json = JsonConvert.SerializeObject(requestData);
47 58 var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
48 59  
49   - var response = await _httpClient.PostAsync(BOT_API_URL, httpContent);
  60 + var response = await _httpClient.PostAsync(_botApiUrl, httpContent);
50 61  
51 62 if (response.IsSuccessStatusCode)
52 63 {
... ...