diff --git a/netcore/src/Application/NCC.API/appsettings.json b/netcore/src/Application/NCC.API/appsettings.json index a074cfe..693026a 100644 --- a/netcore/src/Application/NCC.API/appsettings.json +++ b/netcore/src/Application/NCC.API/appsettings.json @@ -181,6 +181,11 @@ "scope": "snsapi_userinfo" } }, + "WeChatBot": { + "BotApiUrl": "http://wx.lvqianmeiye.com/api/Bot/send-text", + "WebhookUrl": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=496f1add-122b-43fc-9e38-0ca79c48b33f", + "WebhookUrlTest": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=6f8686ec-5011-4c1d-bae9-d82a2a2f4d83" + }, "NCC_App": { "CodeAreasName": "SubDev,Food,Extend,test", //系统文件路径(末尾必须带斜杆) diff --git a/netcore/src/Modularity/Common/NCC.Common/Extension/Ext.cs b/netcore/src/Modularity/Common/NCC.Common/Extension/Ext.cs index 48fd3e9..fa7a23d 100644 --- a/netcore/src/Modularity/Common/NCC.Common/Extension/Ext.cs +++ b/netcore/src/Modularity/Common/NCC.Common/Extension/Ext.cs @@ -808,7 +808,7 @@ namespace NCC.Common.Extension } #endregion - + /// /// 元转分 /// diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitBillingStatisticsInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitBillingStatisticsInput.cs new file mode 100644 index 0000000..20a763a --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitBillingStatisticsInput.cs @@ -0,0 +1,16 @@ +using System; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 事业部开单统计查询输入 + /// + public class BusinessUnitBillingStatisticsInput + { + /// + /// 统计日期(格式:yyyy-MM-dd) + /// + public string Date { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitBillingStatisticsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitBillingStatisticsOutput.cs new file mode 100644 index 0000000..8f0342e --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitBillingStatisticsOutput.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 事业部开单统计输出 + /// + public class BusinessUnitBillingStatisticsOutput + { + /// + /// 事业部ID + /// + public string BusinessUnitId { get; set; } + + /// + /// 事业部名称 + /// + public string BusinessUnitName { get; set; } + + /// + /// 总业绩 + /// + public decimal TotalPerformance { get; set; } + + /// + /// 总单量 + /// + public int TotalOrderCount { get; set; } + + /// + /// 开单列表 + /// + public List Orders { get; set; } + } + + /// + /// 开单信息 + /// + public class BillingOrderInfo + { + /// + /// 开单ID + /// + public string OrderId { get; set; } + + /// + /// 门店名称 + /// + public string StoreName { get; set; } + + /// + /// 健康师姓名(多个用逗号分隔) + /// + public string HealthTeacherNames { get; set; } + + /// + /// 金额 + /// + public decimal Amount { get; set; } + + /// + /// 开单时间 + /// + public DateTime? OrderTime { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/LqHytkHytkListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/LqHytkHytkListOutput.cs index 4aeee69..27eadbf 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/LqHytkHytkListOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/LqHytkHytkListOutput.cs @@ -1,4 +1,8 @@ using System; +using System.Collections.Generic; +using NCC.Extend.Entitys.Dto.LqHytkMx; +using NCC.Extend.Entitys.Dto.LqHytkJksyj; +using NCC.Extend.Entitys.Dto.LqHytkKjbsyj; namespace NCC.Extend.Entitys.Dto.LqHytkHytk { @@ -102,5 +106,19 @@ namespace NCC.Extend.Entitys.Dto.LqHytkHytk /// public string cancelRemark { get; set; } + /// + /// 退卡品项明细列表 + /// + public List lqHytkMxList { get; set; } + + /// + /// 健康师业绩列表 + /// + public List lqHytkJksyjList { get; set; } + + /// + /// 科技部老师业绩列表 + /// + public List lqHytkKjbsyjList { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/LqHytkHytkListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/LqHytkHytkListQueryInput.cs index 1369ba5..e3f808e 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/LqHytkHytkListQueryInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/LqHytkHytkListQueryInput.cs @@ -93,5 +93,14 @@ namespace NCC.Extend.Entitys.Dto.LqHytkHytk /// public int isEffective { get; set; } = 0; + /// + /// 健康师ID(可选,传入后只返回该健康师参与的退卡记录) + /// + public string jksId { get; set; } + + /// + /// 科技部老师ID(可选,传入后只返回该老师参与的退卡记录) + /// + public string kjblsId { get; set; } } } \ No newline at end of file diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListByJksQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListByJksQueryInput.cs new file mode 100644 index 0000000..f8e3d82 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListByJksQueryInput.cs @@ -0,0 +1,36 @@ +using NCC.Common.Filter; + +namespace NCC.Extend.Entitys.Dto.LqKdKdjlb +{ + /// + /// 根据健康师ID查询开单列表输入 + /// + public class LqKdKdjlbListByJksQueryInput : PageInputBase + { + /// + /// 健康师ID(必填) + /// + public string jksId { get; set; } + + /// + /// 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// + public string startTime { get; set; } + + /// + /// 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// + public string endTime { get; set; } + + /// + /// 门店ID(可选) + /// + public string djmd { get; set; } + + /// + /// 是否有效(可选,0=全部,1=有效,2=无效,默认1) + /// + public int isEffective { get; set; } = 1; + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListByKjbQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListByKjbQueryInput.cs new file mode 100644 index 0000000..005c9cb --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListByKjbQueryInput.cs @@ -0,0 +1,36 @@ +using NCC.Common.Filter; + +namespace NCC.Extend.Entitys.Dto.LqKdKdjlb +{ + /// + /// 根据科技部老师ID查询开单列表输入 + /// + public class LqKdKdjlbListByKjbQueryInput : PageInputBase + { + /// + /// 科技部老师ID(必填) + /// + public string kjblsId { get; set; } + + /// + /// 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// + public string startTime { get; set; } + + /// + /// 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// + public string endTime { get; set; } + + /// + /// 门店ID(可选) + /// + public string djmd { get; set; } + + /// + /// 是否有效(可选,0=全部,1=有效,2=无效,默认1) + /// + public int isEffective { get; set; } = 1; + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListOutput.cs index 1b40dfc..6ab7a25 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListOutput.cs @@ -170,5 +170,15 @@ namespace NCC.Extend.Entitys.Dto.LqKdKdjlb /// 开单品项明细列表 /// public List ItemDetails { get; set; } + + /// + /// 健康师业绩列表 + /// + public List lqKdJksyjList { get; set; } + + /// + /// 科技部老师业绩列表 + /// + public List lqKdKjbsyjList { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListQueryInput.cs index 8504adb..e5a3a1f 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListQueryInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListQueryInput.cs @@ -139,5 +139,14 @@ namespace NCC.Extend.Entitys.Dto.LqKdKdjlb /// public int isEffective { get; set; } = 0; + /// + /// 健康师ID(可选,传入后只返回该健康师参与的开单记录) + /// + public string jksId { get; set; } + + /// + /// 科技部老师ID(可选,传入后只返回该老师参与的开单记录) + /// + public string kjblsId { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsByItemOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsByItemOutput.cs new file mode 100644 index 0000000..5d5d29c --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsByItemOutput.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqPackageInfo +{ + /// + /// 营销活动按品项统计输出 + /// + public class ActivityStatisticsByItemOutput + { + /// + /// 营销活动ID + /// + public string ActivityId { get; set; } + + /// + /// 营销活动名称 + /// + public string ActivityName { get; set; } + + /// + /// 品项统计列表 + /// + public List ItemList { get; set; } + } + + /// + /// 品项统计项 + /// + public class ItemStatisticsItem + { + /// + /// 品项ID + /// + public string ItemId { get; set; } + + /// + /// 品项名称 + /// + public string ItemName { get; set; } + + /// + /// 销售数量(项目次数总和) + /// + public decimal SalesQuantity { get; set; } + + /// + /// 销售金额 + /// + public decimal SalesAmount { get; set; } + + /// + /// 开单数量(包含该品项的开单数) + /// + public int BillingCount { get; set; } + + /// + /// 销售次数(品项明细记录数) + /// + public int SalesCount { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsByStoreItemOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsByStoreItemOutput.cs new file mode 100644 index 0000000..3f75828 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsByStoreItemOutput.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqPackageInfo +{ + /// + /// 营销活动按门店品项统计输出 + /// + public class ActivityStatisticsByStoreItemOutput + { + /// + /// 营销活动ID + /// + public string ActivityId { get; set; } + + /// + /// 营销活动名称 + /// + public string ActivityName { get; set; } + + /// + /// 门店品项统计列表 + /// + public List StoreItemList { get; set; } + } + + /// + /// 门店品项统计项 + /// + public class StoreItemStatisticsItem + { + /// + /// 门店ID + /// + public string StoreId { get; set; } + + /// + /// 门店名称 + /// + public string StoreName { get; set; } + + /// + /// 品项ID + /// + public string ItemId { get; set; } + + /// + /// 品项名称 + /// + public string ItemName { get; set; } + + /// + /// 销售数量(项目次数总和) + /// + public decimal SalesQuantity { get; set; } + + /// + /// 销售金额 + /// + public decimal SalesAmount { get; set; } + + /// + /// 开单数量(包含该品项的开单数) + /// + public int BillingCount { get; set; } + + /// + /// 销售次数(品项明细记录数) + /// + public int SalesCount { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsByStoreOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsByStoreOutput.cs new file mode 100644 index 0000000..6909027 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsByStoreOutput.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqPackageInfo +{ + /// + /// 营销活动按门店统计输出 + /// + public class ActivityStatisticsByStoreOutput + { + /// + /// 营销活动ID + /// + public string ActivityId { get; set; } + + /// + /// 营销活动名称 + /// + public string ActivityName { get; set; } + + /// + /// 门店统计列表 + /// + public List StoreList { get; set; } + } + + /// + /// 门店统计项 + /// + public class StoreStatisticsItem + { + /// + /// 门店ID + /// + public string StoreId { get; set; } + + /// + /// 门店名称 + /// + public string StoreName { get; set; } + + /// + /// 开单数量 + /// + public int BillingCount { get; set; } + + /// + /// 开单金额 + /// + public decimal BillingAmount { get; set; } + + /// + /// 欠款金额 + /// + public decimal DebtAmount { get; set; } + + /// + /// 人头数(去重客户数) + /// + public int CustomerCount { get; set; } + + /// + /// 项目数(品项项目次数总和) + /// + public decimal ItemCount { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/TechTeacherSimpleStatisticsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/TechTeacherSimpleStatisticsOutput.cs index e8ac726..ca4beb5 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/TechTeacherSimpleStatisticsOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/TechTeacherSimpleStatisticsOutput.cs @@ -41,5 +41,10 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics /// 耗卡品项次数 /// public int ConsumeItemCount { get; set; } + + /// + /// 消耗手工费(耗卡手工费) + /// + public decimal ConsumeLaborCost { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/MemberRemainingItemsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/MemberRemainingItemsOutput.cs index 2ab5392..4e63238 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/MemberRemainingItemsOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/MemberRemainingItemsOutput.cs @@ -25,6 +25,7 @@ namespace NCC.Extend.Entitys.Dto.LqXhHyhk public string MemberName { get; set; } /// + /// /// 剩余品项列表 /// /// 按剩余数量降序排列的品项列表 @@ -71,6 +72,12 @@ namespace NCC.Extend.Entitys.Dto.LqXhHyhk public string SourceType { get; set; } /// + /// 备注 + /// + /// 备注 + public string Remark { get; set; } + + /// /// 总购买数量 /// /// 该品项的总购买次数 diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqYaoyjl/LqYaoyjlListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqYaoyjl/LqYaoyjlListQueryInput.cs index 36188b4..475c1f2 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqYaoyjl/LqYaoyjlListQueryInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqYaoyjl/LqYaoyjlListQueryInput.cs @@ -17,47 +17,50 @@ namespace NCC.Extend.Entitys.Dto.LqYaoyjl /// /// public int dataType { get; set; } - - /// /// 邀约编号 /// public string id { get; set; } - + /// /// 邀约人 /// public string yyr { get; set; } - + /// /// 邀约时间 /// public string yysj { get; set; } - + /// /// 邀约客户 /// public string yykh { get; set; } - + /// /// 邀约客户姓名 /// public string yykhxm { get; set; } - + /// /// 电话是否有效 /// public string dhsfyx { get; set; } - + /// /// 联系时间 /// public string lxsj { get; set; } - + /// /// 联系记录 /// public string lxjl { get; set; } - + + /// + /// 门店ID + /// + public string storeId { get; set; } + } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineCrInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineCrInput.cs index ed01b6d..6620704 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineCrInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineCrInput.cs @@ -28,6 +28,12 @@ namespace NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline public string generalManagerId { get; set; } /// + /// 经理类型(0=经理,1=总经理) + /// + [Required(ErrorMessage = "经理类型不能为空")] + public int managerType { get; set; } = 1; + + /// /// 生命线1 /// [Required(ErrorMessage = "生命线1不能为空")] diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineInfoOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineInfoOutput.cs index 5c3af13..22e5e03 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineInfoOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineInfoOutput.cs @@ -28,6 +28,11 @@ namespace NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline public string generalManagerId { get; set; } /// + /// 经理类型(0=经理,1=总经理) + /// + public int managerType { get; set; } + + /// /// 生命线1 /// public decimal lifeline1 { get; set; } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineListOutput.cs index 0f5f0b2..0c1f481 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineListOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineListOutput.cs @@ -28,6 +28,16 @@ namespace NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline public string generalManagerId { get; set; } /// + /// 经理类型(0=经理,1=总经理) + /// + public int managerType { get; set; } + + /// + /// 经理类型(0=经理,1=总经理) + /// + public string managerTypeName { get; set; } + + /// /// 生命线1 /// public decimal lifeline1 { get; set; } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineUpInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineUpInput.cs index a6fcf76..dfdc4de 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineUpInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineUpInput.cs @@ -28,6 +28,12 @@ namespace NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline public string generalManagerId { get; set; } /// + /// 经理类型(0=经理,1=总经理) + /// + [Required(ErrorMessage = "经理类型不能为空")] + public int managerType { get; set; } = 1; + + /// /// 生命线1 /// [Required(ErrorMessage = "生命线1不能为空")] diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_general_manager_lifeline/LqMdGeneralManagerLifelineEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_general_manager_lifeline/LqMdGeneralManagerLifelineEntity.cs index 536a9ef..5356a42 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_general_manager_lifeline/LqMdGeneralManagerLifelineEntity.cs +++ b/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 public string GeneralManagerId { get; set; } /// + /// 经理类型(0=经理,1=总经理) + /// + [SugarColumn(ColumnName = "F_ManagerType")] + public int ManagerType { get; set; } = 1; + + /// /// 生命线1 /// [SugarColumn(ColumnName = "F_Lifeline1")] diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Enum/ManagerTypeEnum.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Enum/ManagerTypeEnum.cs new file mode 100644 index 0000000..a38b7a9 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Enum/ManagerTypeEnum.cs @@ -0,0 +1,23 @@ +using System.ComponentModel; + +namespace NCC.Extend.Entitys.Enum +{ + /// + /// 经理类型枚举 + /// + public enum ManagerTypeEnum + { + /// + /// 经理 + /// + [Description("经理")] + 经理 = 0, + + /// + /// 总经理 + /// + [Description("总经理")] + 总经理 = 1, + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs index fe5f308..fa274d2 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs @@ -12,6 +12,7 @@ using SqlSugar; using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Threading.Tasks; using Yitter.IdGenerator; using NCC.Common.Helper; @@ -22,6 +23,10 @@ using NCC.DataEncryption; using NCC.ClayObject; using NCC.Extend.Entitys.Dto.LqDailyReport; using NCC.Extend.Entitys.lq_kd_kdjlb; +using NCC.Extend.Entitys.lq_kd_jksyj; +using NCC.Extend.Entitys.lq_mdxx; +using NCC.System.Entitys.Permission; +using NCC.Extend.Entitys.Enum; using Microsoft.AspNetCore.Authorization; namespace NCC.Extend @@ -752,7 +757,7 @@ namespace NCC.Extend managerFilter = $"AND target.F_GeneralManagerId = '{input.ManagerId}'"; } - // SQL查询:获取经理汇总业绩 + // SQL查询:获取经理汇总业绩(基于lq_md_general_manager_lifeline表中的经理和门店关系) var sql = $@" SELECT target.F_GeneralManagerId as ManagerId, @@ -761,7 +766,7 @@ namespace NCC.Extend COALESCE(SUM(target.F_Lifeline2), 0) as TotalTarget2, COALESCE(SUM(target.F_Lifeline3), 0) as TotalTarget3, COUNT(DISTINCT target.F_StoreId) as StoreCount, - -- 总完成业绩 + -- 总完成业绩(基于lq_md_general_manager_lifeline表中的门店关系计算) SUM(COALESCE(( SELECT SUM(billing.sfyj) FROM lq_kd_kdjlb billing @@ -957,7 +962,267 @@ namespace NCC.Extend return outputList; } + + /// + /// 获取指定日期的事业部开单统计数据 + /// + /// + /// 统计指定日期的事业部开单数据,包括: + /// - 只统计有效的开单(F_IsEffective = 1) + /// - 只统计有金额的开单(sfyj > 0) + /// - 只统计有效的健康师业绩(F_IsEffective = 1) + /// - 如果有多个健康师就合并显示 + /// - 按照事业部名称排序 + /// - 每个事业部内的开单按照时间先后顺序进行排序 + /// + /// 示例请求: + /// ```json + /// { + /// "date": "2025-11-10" + /// } + /// ``` + /// + /// 查询参数 + /// 事业部开单统计数据列表 + /// 成功返回统计数据 + /// 日期格式错误或参数无效 + /// 服务器内部错误 + [HttpPost("get-business-unit-billing-statistics")] + [AllowAnonymous] + public async Task> GetBusinessUnitBillingStatistics(BusinessUnitBillingStatisticsInput input) + { + try + { + // 1. 验证日期参数 + if (string.IsNullOrEmpty(input.Date)) + { + throw NCCException.Oh("日期不能为空"); + } + + if (!DateTime.TryParse(input.Date, out var targetDate)) + { + throw NCCException.Oh("日期格式错误,请使用 yyyy-MM-dd 格式"); + } + + // 2. 查询指定日期的有效开单记录(有金额的) + var billingQuery = _db.Queryable( + (billing, store, org) => billing.Djmd == store.Id && store.Syb == org.Id) + .Where((billing, store, org) => billing.IsEffective == StatusEnum.有效.GetHashCode()) + .Where((billing, store, org) => billing.Sfyj > 0) // 只统计有金额的开单 + .Where((billing, store, org) => billing.Kdrq.HasValue && billing.Kdrq.Value.Date == targetDate.Date) + .Where((billing, store, org) => org.Category == "department") + .Where((billing, store, org) => org.FullName.Contains("事业")) + .Select((billing, store, org) => new + { + OrderId = billing.Id, + StoreName = store.Dm, + BusinessUnitId = org.Id, + BusinessUnitName = org.FullName, + Amount = billing.Sfyj, + OrderTime = billing.Kdrq, + }) + .ToListAsync(); + + var billingRecords = await billingQuery; + + if (!billingRecords.Any()) + { + return new List(); + } + + // 3. 批量查询健康师信息 + var orderIds = billingRecords.Select(x => x.OrderId).Distinct().ToList(); + var healthTeachers = await _db.Queryable() + .Where(x => orderIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode()) + .Select(x => new + { + OrderId = x.Glkdbh, + TeacherName = x.Jksxm, + }) + .ToListAsync(); + + // 4. 按开单ID分组健康师 + var healthTeacherDict = healthTeachers + .GroupBy(x => x.OrderId) + .ToDictionary( + g => g.Key, + g => string.Join("、", g.Select(x => x.TeacherName).Distinct()) + ); + + // 5. 按事业部分组统计 + var result = billingRecords + .GroupBy(x => new { x.BusinessUnitId, x.BusinessUnitName }) + .Select(g => new BusinessUnitBillingStatisticsOutput + { + BusinessUnitId = g.Key.BusinessUnitId, + BusinessUnitName = g.Key.BusinessUnitName, + TotalPerformance = g.Sum(x => x.Amount), + TotalOrderCount = g.Count(), + Orders = g.OrderBy(x => x.OrderTime ?? DateTime.MinValue) + .Select(x => new BillingOrderInfo + { + OrderId = x.OrderId, + StoreName = x.StoreName, + HealthTeacherNames = healthTeacherDict.GetValueOrDefault(x.OrderId, ""), + Amount = x.Amount, + OrderTime = x.OrderTime, + }) + .ToList(), + }) + .OrderBy(x => x.BusinessUnitName) // 按事业部名称排序 + .ToList(); + + return result; + } + catch (Exception ex) + { + throw NCCException.Oh($"获取事业部开单统计数据失败: {ex.Message}", ex); + } + } + + /// + /// 将事业部开单统计数据格式化为中文文本 + /// + /// + /// 将结构化的统计数据格式化为中文文本格式,用于显示或发送消息。 + /// + /// 示例请求: + /// ```json + /// { + /// "date": "2025-11-10" + /// } + /// ``` + /// + /// 返回格式: + /// ``` + /// 11月8日 + /// + /// 今日总业绩:32317 + /// + /// 今日总单量:18 + /// + /// 绿纤人用结果捍卫尊严 + /// + /// 业绩捷报 + /// + /// ▃▃▃▃▃▃▃▃▃▃ + /// + /// 事业1部总业绩:4722 + /// + /// 事业1部总单量:4 + /// + /// 第1单:红光店马丽亚1000 + /// + /// 第2单:468店陈小琴、苟小春500 + /// + /// ... + /// ``` + /// + /// 查询参数 + /// 格式化的中文文本 + /// 成功返回格式化文本 + /// 日期格式错误或参数无效 + /// 服务器内部错误 + [HttpPost("get-business-unit-billing-statistics-text")] + [AllowAnonymous] + public async Task GetBusinessUnitBillingStatisticsText(BusinessUnitBillingStatisticsInput input) + { + try + { + // 1. 获取统计数据 + var statistics = await GetBusinessUnitBillingStatistics(input); + + if (!statistics.Any()) + { + return $"日期 {input.Date} 暂无开单数据"; + } + + // 2. 解析日期 + if (!DateTime.TryParse(input.Date, out var targetDate)) + { + throw NCCException.Oh("日期格式错误,请使用 yyyy-MM-dd 格式"); + } + + // 3. 计算总业绩和总单量 + var totalPerformance = statistics.Sum(x => x.TotalPerformance); + var totalOrderCount = statistics.Sum(x => x.TotalOrderCount); + + // 4. 格式化为中文文本 + var textBuilder = new StringBuilder(); + + // 日期(格式:11月8日) + textBuilder.AppendLine($"{targetDate.Month}月{targetDate.Day}日"); + textBuilder.AppendLine(); + + // 今日总业绩和总单量 + textBuilder.AppendLine($"今日总业绩:{totalPerformance:F0}"); + textBuilder.AppendLine(); + textBuilder.AppendLine($"今日总单量:{totalOrderCount}"); + textBuilder.AppendLine(); + + // 标语 + textBuilder.AppendLine("绿纤人用结果捍卫尊严 "); + textBuilder.AppendLine(); + textBuilder.AppendLine("业绩捷报 "); + textBuilder.AppendLine(); + + // 每个事业部的数据 + foreach (var unit in statistics) + { + // 分隔线 + textBuilder.AppendLine("▃▃▃▃▃▃▃▃▃▃"); + textBuilder.AppendLine(); + + // 事业部业绩和单量 + textBuilder.AppendLine($"{unit.BusinessUnitName}总业绩:{unit.TotalPerformance:F0}"); + textBuilder.AppendLine(); + textBuilder.AppendLine($"{unit.BusinessUnitName}总单量:{unit.TotalOrderCount}"); + textBuilder.AppendLine(); + + // 按门店分组订单 + var ordersByStore = unit.Orders + .GroupBy(x => x.StoreName) + .OrderBy(g => g.Key) // 按门店名称排序 + .ToList(); + + // 遍历每个门店的订单 + foreach (var storeGroup in ordersByStore) + { + // 每个门店的订单按时间排序 + var storeOrders = storeGroup + .OrderBy(x => x.OrderTime ?? DateTime.MinValue) + .ToList(); + + // 每个门店的订单单独编号(从第1单开始) + int orderIndex = 1; + foreach (var order in storeOrders) + { + var teacherNames = string.IsNullOrEmpty(order.HealthTeacherNames) ? "" : order.HealthTeacherNames; + // 格式:第1单:门店名健康师名金额(没有"、",没有"金额"字样,直接数字) + if (string.IsNullOrEmpty(teacherNames)) + { + textBuilder.AppendLine($"第{orderIndex}单:{order.StoreName}{order.Amount:F0}"); + } + else + { + textBuilder.AppendLine($"第{orderIndex}单:{order.StoreName}{teacherNames}{order.Amount:F0}"); + } + textBuilder.AppendLine(); + orderIndex++; + } + } + } + + return textBuilder.ToString().TrimEnd(); + } + catch (Exception ex) + { + throw NCCException.Oh($"获取事业部开单统计文本失败: {ex.Message}", ex); + } + } #endregion + + } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs index ce5fd82..56bd52c 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs @@ -70,8 +70,35 @@ namespace NCC.Extend.LqHytkHytk /// /// 获取退卡信息列表 /// + /// + /// 获取退卡记录列表,支持根据健康师ID或科技部老师ID筛选,返回品项明细、健康师业绩和科技部老师业绩 + /// + /// 示例请求: + /// ```json + /// GET /api/Extend/LqHytkHytk?jksId=健康师ID&kjblsId=科技部老师ID&currentPage=1&pageSize=10 + /// ``` + /// + /// 参数说明: + /// - jksId: 健康师ID(可选,传入后只返回该健康师参与的退卡记录) + /// - kjblsId: 科技部老师ID(可选,传入后只返回该老师参与的退卡记录) + /// - id: 退卡编号(可选) + /// - md: 门店ID(可选) + /// - hy: 会员ID(可选) + /// - tksj: 退卡时间(可选,格式:yyyy-MM-dd,yyyy-MM-dd) + /// - currentPage: 当前页码(必填) + /// - pageSize: 每页数量(必填) + /// + /// 返回数据说明: + /// - 退卡基本信息:id、门店信息、会员信息、退卡金额、退卡时间等 + /// - lqHytkMxList: 退卡品项明细列表,每个明细包含品项信息、退款金额、项目次数等 + /// - lqHytkJksyjList: 健康师业绩列表,每个业绩包含健康师信息、业绩金额、手工费、退卡品项次数等 + /// - lqHytkKjbsyjList: 科技部老师业绩列表,每个业绩包含科技部老师信息、业绩金额、手工费、退卡品项次数等 + /// /// 查询参数 - /// + /// 分页的退卡记录列表,包含退卡基本信息、品项明细、健康师业绩、科技部老师业绩 + /// 成功返回退卡列表 + /// 参数错误 + /// 服务器内部错误 [HttpGet("")] public async Task GetList([FromQuery] LqHytkHytkListQueryInput input) { @@ -79,7 +106,48 @@ namespace NCC.Extend.LqHytkHytk List queryTksj = input.tksj != null ? input.tksj.Split(',').ToObeject>() : null; DateTime? startTksj = queryTksj != null ? Ext.GetDateTime(queryTksj.First()) : null; DateTime? endTksj = queryTksj != null ? Ext.GetDateTime(queryTksj.Last()) : null; - var data = await _db.Queryable() + + // 根据是否传入健康师ID或科技部老师ID,动态构建查询 + ISugarQueryable baseQuery = null; + + if (!string.IsNullOrEmpty(input.jksId) && !string.IsNullOrEmpty(input.kjblsId)) + { + // 同时传入健康师ID和科技部老师ID,需要同时关联两个业绩表(不过滤有效性) + baseQuery = _db.Queryable( + (jksyj, kjbsyj, hytk) => jksyj.Gltkbh == hytk.Id && kjbsyj.Gltkbh == hytk.Id) + .Where((jksyj, kjbsyj, hytk) => jksyj.Jkszh == input.jksId) + .Where((jksyj, kjbsyj, hytk) => kjbsyj.Kjblszh == input.kjblsId) + .Select((jksyj, kjbsyj, hytk) => hytk) + .Distinct() + .MergeTable(); + } + else if (!string.IsNullOrEmpty(input.jksId)) + { + // 只传入健康师ID,关联健康师业绩表(不过滤有效性) + baseQuery = _db.Queryable( + (jksyj, hytk) => jksyj.Gltkbh == hytk.Id) + .Where((jksyj, hytk) => jksyj.Jkszh == input.jksId) + .Select((jksyj, hytk) => hytk) + .Distinct() + .MergeTable(); + } + else if (!string.IsNullOrEmpty(input.kjblsId)) + { + // 只传入科技部老师ID,关联科技部老师业绩表(不过滤有效性) + baseQuery = _db.Queryable( + (kjbsyj, hytk) => kjbsyj.Gltkbh == hytk.Id) + .Where((kjbsyj, hytk) => kjbsyj.Kjblszh == input.kjblsId) + .Select((kjbsyj, hytk) => hytk) + .Distinct() + .MergeTable(); + } + else + { + // 没有传入健康师ID或科技部老师ID,使用原来的查询逻辑 + baseQuery = _db.Queryable(); + } + + var data = await baseQuery .WhereIF(!string.IsNullOrEmpty(input.id), p => p.Id.Contains(input.id)) .WhereIF(!string.IsNullOrEmpty(input.md), p => p.Md.Equals(input.md)) .WhereIF(!string.IsNullOrEmpty(input.mdbh), p => p.Mdbh.Contains(input.mdbh)) @@ -123,6 +191,104 @@ namespace NCC.Extend.LqHytkHytk .MergeTable() .OrderBy(sidx + " " + input.sort) .ToPagedListAsync(input.currentPage, input.pageSize); + + // 获取当前页的退卡记录ID列表 + var refundIds = data.list.Select(x => x.id).ToList(); + + // 批量查询品项明细(不过滤有效性,返回所有记录) + var itemDetails = new List(); + if (refundIds.Any()) + { + itemDetails = await _db.Queryable() + .Where(x => refundIds.Contains(x.RefundInfoId)) + .Select(x => new LqHytkMxInfoOutput + { + id = x.Id, + refundInfoId = x.RefundInfoId, + billingItemId = x.BillingItemId, + px = x.Px, + pxmc = x.Pxmc, + pxjg = x.Pxjg, + tkje = x.Tkje, + projectNumber = x.ProjectNumber, + isEffective = x.IsEffective, + sourceType = x.SourceType, + totalPrice = x.TotalPrice + }) + .ToListAsync(); + } + + // 批量查询健康师业绩(性能优化:一次性查询所有退卡的健康师业绩,不过滤有效性) + var jksyjList = new List(); + if (refundIds.Any()) + { + jksyjList = await _db.Queryable() + .Where(x => refundIds.Contains(x.Gltkbh)) + .Select(x => new LqHytkJksyjInfoOutput + { + id = x.Id, + gltkbh = x.Gltkbh, + jks = x.Jks, + jksxm = x.Jksxm, + jkszh = x.Jkszh, + jksyj = x.Jksyj, + tksj = x.Tksj, + F_jsjid = x.F_jsjid, + F_tkpxid = x.F_tkpxid, + F_LaborCost = x.F_LaborCost, + F_tkpxNumber = x.F_tkpxNumber + }) + .ToListAsync(); + } + + // 批量查询科技部老师业绩(性能优化:一次性查询所有退卡的科技部老师业绩,不过滤有效性) + var kjbsyjList = new List(); + if (refundIds.Any()) + { + kjbsyjList = await _db.Queryable() + .Where(x => refundIds.Contains(x.Gltkbh)) + .Select(x => new LqHytkKjbsyjInfoOutput + { + id = x.Id, + gltkbh = x.Gltkbh, + kjbls = x.Kjbls, + kjblsxm = x.Kjblsxm, + kjblszh = x.Kjblszh, + kjblsyj = x.Kjblsyj, + tksj = x.Tksj, + F_tkpxid = x.F_tkpxid, + F_LaborCost = x.F_LaborCost, + F_tkpxNumber = x.F_tkpxNumber + }) + .ToListAsync(); + } + + // 按退卡ID分组品项明细 + var itemDetailsGrouped = itemDetails.GroupBy(x => x.refundInfoId) + .ToDictionary(g => g.Key, g => g.ToList()); + + // 按退卡ID分组健康师业绩 + var jksyjGrouped = jksyjList.GroupBy(x => x.gltkbh) + .ToDictionary(g => g.Key, g => g.ToList()); + + // 按退卡ID分组科技部老师业绩 + var kjbsyjGrouped = kjbsyjList.GroupBy(x => x.gltkbh) + .ToDictionary(g => g.Key, g => g.ToList()); + + // 为每个退卡记录分配品项明细、健康师业绩和科技部老师业绩 + foreach (var item in data.list) + { + item.lqHytkMxList = itemDetailsGrouped.ContainsKey(item.id) + ? itemDetailsGrouped[item.id] + : new List(); + item.lqHytkJksyjList = jksyjGrouped.ContainsKey(item.id) + ? jksyjGrouped[item.id] + : new List(); + item.lqHytkKjbsyjList = kjbsyjGrouped.ContainsKey(item.id) + ? kjbsyjGrouped[item.id] + : new List(); + } + return PageResult.SqlSugarPageResult(data); } #endregion diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs index d02bc86..11e4fb7 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs @@ -45,6 +45,7 @@ using Yitter.IdGenerator; using NCC.Extend.Entitys.lq_package_info; using NCC.Extend.Entitys.lq_mdxx; using NCC.Extend.Entitys.lq_card_transfer_log; +using NCC.Extend.Entitys.Dto.LqDailyReport; namespace NCC.Extend.LqKdKdjlb { @@ -64,6 +65,7 @@ namespace NCC.Extend.LqKdKdjlb private readonly WeChatBotService _weChatBotService; private readonly LqKdKdjlbStringGenerator _stringGenerator; private readonly ILogger _logger; + private readonly LqDailyReportService _dailyReportService; /// /// 初始化一个类型的新实例 @@ -76,7 +78,8 @@ namespace NCC.Extend.LqKdKdjlb IUserManager userManager, WeChatBotService weChatBotService, LqKdKdjlbStringGenerator stringGenerator, - ILogger logger + ILogger logger, + LqDailyReportService dailyReportService ) { _lqKdKdjlbRepository = lqKdKdjlbRepository; @@ -88,6 +91,7 @@ namespace NCC.Extend.LqKdKdjlb _weChatBotService = weChatBotService; _stringGenerator = stringGenerator; _logger = logger; + _dailyReportService = dailyReportService; } #region 获取开单记录表 @@ -214,8 +218,49 @@ namespace NCC.Extend.LqKdKdjlb List queryKdrq = input.kdrq != null ? input.kdrq.Split(',').ToObeject>() : null; DateTime? startKdrq = queryKdrq != null ? Ext.GetDateTime(queryKdrq.First()) : null; DateTime? endKdrq = queryKdrq != null ? Ext.GetDateTime(queryKdrq.Last()) : null; - var data = await _db.Queryable() - .WhereIF(!string.IsNullOrEmpty(input.keyword), p => p.Kdhyc.Contains(input.keyword) || p.Kdhysjh.Contains(input.keyword)) + + // 根据是否传入健康师ID或科技部老师ID,动态构建查询 + ISugarQueryable baseQuery = null; + + if (!string.IsNullOrEmpty(input.jksId) && !string.IsNullOrEmpty(input.kjblsId)) + { + // 同时传入健康师ID和科技部老师ID,需要同时关联两个业绩表 + baseQuery = _db.Queryable( + (jksyj, kjbsyj, kdjlb) => jksyj.Glkdbh == kdjlb.Id && kjbsyj.Glkdbh == kdjlb.Id) + .Where((jksyj, kjbsyj, kdjlb) => jksyj.Jkszh == input.jksId && jksyj.IsEffective == StatusEnum.有效.GetHashCode()) + .Where((jksyj, kjbsyj, kdjlb) => kjbsyj.Kjbls == input.kjblsId && kjbsyj.IsEffective == StatusEnum.有效.GetHashCode()) + .Select((jksyj, kjbsyj, kdjlb) => kdjlb) + .Distinct() + .MergeTable(); + } + else if (!string.IsNullOrEmpty(input.jksId)) + { + // 只传入健康师ID,关联健康师业绩表 + baseQuery = _db.Queryable( + (jksyj, kdjlb) => jksyj.Glkdbh == kdjlb.Id) + .Where((jksyj, kdjlb) => jksyj.Jkszh == input.jksId && jksyj.IsEffective == StatusEnum.有效.GetHashCode()) + .Select((jksyj, kdjlb) => kdjlb) + .Distinct() + .MergeTable(); + } + else if (!string.IsNullOrEmpty(input.kjblsId)) + { + // 只传入科技部老师ID,关联科技部老师业绩表 + baseQuery = _db.Queryable( + (kjbsyj, kdjlb) => kjbsyj.Glkdbh == kdjlb.Id) + .Where((kjbsyj, kdjlb) => kjbsyj.Kjbls == input.kjblsId && kjbsyj.IsEffective == StatusEnum.有效.GetHashCode()) + .Select((kjbsyj, kdjlb) => kdjlb) + .Distinct() + .MergeTable(); + } + else + { + // 没有传入健康师ID或科技部老师ID,使用原来的查询逻辑 + baseQuery = _db.Queryable(); + } + + var data = await baseQuery + .WhereIF(!string.IsNullOrEmpty(input.keyword), p => p.Kdhyc.Contains(input.keyword) || p.Kdhysjh.Contains(input.keyword)) .WhereIF(!string.IsNullOrEmpty(input.id), p => p.Id.Contains(input.id)) .WhereIF(!string.IsNullOrEmpty(input.djmd), p => p.Djmd.Equals(input.djmd)) .WhereIF(!string.IsNullOrEmpty(input.jsj), p => p.Jsj.Equals(input.jsj)) @@ -308,18 +353,380 @@ namespace NCC.Extend.LqKdKdjlb var itemDetailsGrouped = itemDetails.GroupBy(x => x.glkdbh) .ToDictionary(g => g.Key, g => g.ToList()); - // 为每个开单记录分配品项明细 + // 批量查询健康师业绩(性能优化:一次性查询所有开单的健康师业绩) + var jksyjList = new List(); + if (billingIds.Any()) + { + jksyjList = await _db.Queryable() + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode()) + .Select(x => new LqKdJksyjInfoOutput + { + id = x.Id, + glkdbh = x.Glkdbh, + kdpxid = x.Kdpxid, + jks = x.Jks, + jksxm = x.Jksxm, + jkszh = x.Jkszh, + jksyj = x.Jksyj, + yjsj = x.Yjsj, + jsj_id = x.Jsj_id, + isEffective = x.IsEffective + }) + .ToListAsync(); + } + + // 批量查询科技部老师业绩(性能优化:一次性查询所有开单的科技部老师业绩) + var kjbsyjList = new List(); + if (billingIds.Any()) + { + kjbsyjList = await _db.Queryable() + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode()) + .Select(x => new LqKdKjbsyjInfoOutput + { + id = x.Id, + glkdbh = x.Glkdbh, + kdpxid = x.Kdpxid, + kjbls = x.Kjbls, + kjblsxm = x.Kjblsxm, + kjblszh = x.Kjblszh, + kjblsyj = x.Kjblsyj, + yjsj = x.Yjsj, + isEffective = x.IsEffective + }) + .ToListAsync(); + } + + // 按开单ID分组健康师业绩 + var jksyjGrouped = jksyjList.GroupBy(x => x.glkdbh) + .ToDictionary(g => g.Key, g => g.ToList()); + + // 按开单ID分组科技部老师业绩 + var kjbsyjGrouped = kjbsyjList.GroupBy(x => x.glkdbh) + .ToDictionary(g => g.Key, g => g.ToList()); + + // 为每个开单记录分配品项明细、健康师业绩和科技部老师业绩 foreach (var item in data.list) { item.ItemDetails = itemDetailsGrouped.ContainsKey(item.id) ? itemDetailsGrouped[item.id] : new List(); + item.lqKdJksyjList = jksyjGrouped.ContainsKey(item.id) + ? jksyjGrouped[item.id] + : new List(); + item.lqKdKjbsyjList = kjbsyjGrouped.ContainsKey(item.id) + ? kjbsyjGrouped[item.id] + : new List(); } return PageResult.SqlSugarPageResult(data); } #endregion + #region 根据健康师ID获取开单列表 + /// + /// 根据健康师ID获取开单列表 + /// + /// + /// 根据健康师ID查询该健康师参与的所有开单记录,支持时间周期查询和分页 + /// + /// 示例请求: + /// GET /api/Extend/LqKdKdjlb/GetListByJksId?jksId=健康师ID&startTime=2025-01-01&endTime=2025-01-31&currentPage=1&pageSize=10 + /// + /// 参数说明: + /// - jksId: 健康师ID(必填) + /// - startTime: 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// - endTime: 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// - djmd: 门店ID(可选) + /// - isEffective: 是否有效(可选,0=全部,1=有效,2=无效,默认1) + /// - currentPage: 当前页码(必填) + /// - pageSize: 每页数量(必填) + /// + /// 返回说明: + /// - 返回格式与GetList接口相同,包含开单基本信息及品项明细列表 + /// + /// 查询参数 + /// 开单列表(分页) + /// 查询成功 + /// 参数错误 + /// 服务器内部错误 + [HttpGet("GetListByJksId")] + public async Task GetListByJksId([FromQuery] LqKdKdjlbListByJksQueryInput input) + { + try + { + if (string.IsNullOrEmpty(input.jksId)) + { + throw NCCException.Oh("健康师ID不能为空"); + } + var sidx = input.sidx == null ? "kdrq" : input.sidx; + var sort = string.IsNullOrEmpty(input.sort) ? "DESC" : input.sort; + // 解析时间范围 + DateTime? startDate = null; + DateTime? endDate = null; + if (!string.IsNullOrEmpty(input.startTime)) + { + startDate = Ext.GetDateTime(input.startTime); + } + if (!string.IsNullOrEmpty(input.endTime)) + { + endDate = Ext.GetDateTime(input.endTime); + // 如果只传了日期,则设置为当天的23:59:59 + if (endDate.HasValue && !input.endTime.Contains(":")) + { + endDate = new DateTime(endDate.Value.Year, endDate.Value.Month, endDate.Value.Day, 23, 59, 59); + } + } + + // 通过健康师业绩表关联查询开单记录 + var data = await _db.Queryable((jksyj, kdjlb) => jksyj.Glkdbh == kdjlb.Id) + .Where((jksyj, kdjlb) => jksyj.Jkszh == input.jksId) + .WhereIF(input.isEffective != 0, (jksyj, kdjlb) => jksyj.IsEffective == input.isEffective && kdjlb.IsEffective == input.isEffective) + .WhereIF(input.isEffective == 0, (jksyj, kdjlb) => jksyj.IsEffective == StatusEnum.有效.GetHashCode() && kdjlb.IsEffective == StatusEnum.有效.GetHashCode()) + .WhereIF(startDate.HasValue, (jksyj, kdjlb) => kdjlb.Kdrq >= startDate.Value) + .WhereIF(endDate.HasValue, (jksyj, kdjlb) => kdjlb.Kdrq <= endDate.Value) + .WhereIF(!string.IsNullOrEmpty(input.djmd), (jksyj, kdjlb) => kdjlb.Djmd == input.djmd) + .Select((jksyj, kdjlb) => new LqKdKdjlbListOutput + { + id = kdjlb.Id, + djmd = kdjlb.Djmd, + jsj = kdjlb.Jsj, + kdrq = kdjlb.Kdrq, + gjlx = kdjlb.Gjlx, + hgjg = kdjlb.Hgjg, + zdyj = kdjlb.Zdyj, + sfyj = kdjlb.Sfyj, + qk = kdjlb.Qk, + ckfs = kdjlb.Ckfs, + fkfs = kdjlb.Fkfs, + fkyy = kdjlb.Fkyy, + fkpd = kdjlb.Fkpd, + khly = kdjlb.Khly, + tjr = kdjlb.Tjr, + deductAmount = kdjlb.DeductAmount, + paidDebt = kdjlb.PaidDebt, + supplementBillingId = kdjlb.SupplementBillingId, + sfskdd = kdjlb.Sfskdd, + jj = kdjlb.Jj, + bz = kdjlb.Bz, + kdhy = kdjlb.Kdhy, + kdhyc = SqlFunc.Subqueryable().Where(x => x.Id == kdjlb.Kdhy).Select(x => x.Khmc), + kdhysjh = SqlFunc.Subqueryable().Where(x => x.Id == kdjlb.Kdhy).Select(x => x.Sjh), + isEffective = kdjlb.IsEffective, + createUser = kdjlb.CreateUser, + createUserName = SqlFunc.Subqueryable().Where(x => x.Id == kdjlb.CreateUser).Select(x => x.RealName), + activityId = kdjlb.ActivityId, + activityName = SqlFunc.Subqueryable().Where(x => x.Id == kdjlb.ActivityId).Select(x => x.ActivityName), + }) + .MergeTable() + .Distinct() // 去重,因为一个开单可能对应多个健康师业绩记录 + .OrderBy($"{sidx} {sort}") + .ToPagedListAsync(input.currentPage, input.pageSize); + + // 获取当前页的开单记录ID列表 + var billingIds = data.list.Select(x => x.id).ToList(); + + // 批量查询品项明细 + var itemDetails = new List(); + if (billingIds.Any()) + { + itemDetails = await _db.Queryable() + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode()) + .Select(x => new LqKdPxmxInfoOutput + { + id = x.Id, + glkdbh = x.Glkdbh, + px = x.Px, + pxmc = x.Pxmc, + pxjg = x.Pxjg, + projectNumber = x.ProjectNumber, + isEnabled = x.IsEnabled, + sourceType = x.SourceType, + memberId = x.MemberId, + createTime = x.CreateTIme, + totalPrice = x.TotalPrice, + actualPrice = x.ActualPrice, + remark = x.Remark, + isEffective = x.IsEffective + }) + .ToListAsync(); + } + + // 按开单ID分组品项明细 + var itemDetailsGrouped = itemDetails.GroupBy(x => x.glkdbh) + .ToDictionary(g => g.Key, g => g.ToList()); + + // 为每个开单记录分配品项明细 + foreach (var item in data.list) + { + item.ItemDetails = itemDetailsGrouped.ContainsKey(item.id) + ? itemDetailsGrouped[item.id] + : new List(); + } + + return PageResult.SqlSugarPageResult(data); + } + catch (Exception ex) + { + _logger.LogError(ex, $"根据健康师ID获取开单列表失败 - 健康师ID: {input?.jksId}, 开始时间: {input?.startTime}, 结束时间: {input?.endTime}"); + throw NCCException.Oh($"根据健康师ID获取开单列表失败: {ex.Message}"); + } + } + #endregion + + #region 根据科技部老师ID获取开单列表 + /// + /// 根据科技部老师ID获取开单列表 + /// + /// + /// 根据科技部老师ID查询该老师参与的所有开单记录,支持时间周期查询和分页 + /// + /// 示例请求: + /// GET /api/Extend/LqKdKdjlb/GetListByKjbId?kjblsId=科技部老师ID&startTime=2025-01-01&endTime=2025-01-31&currentPage=1&pageSize=10 + /// + /// 参数说明: + /// - kjblsId: 科技部老师ID(必填) + /// - startTime: 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// - endTime: 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// - djmd: 门店ID(可选) + /// - isEffective: 是否有效(可选,0=全部,1=有效,2=无效,默认1) + /// - currentPage: 当前页码(必填) + /// - pageSize: 每页数量(必填) + /// + /// 返回说明: + /// - 返回格式与GetList接口相同,包含开单基本信息及品项明细列表 + /// + /// 查询参数 + /// 开单列表(分页) + /// 查询成功 + /// 参数错误 + /// 服务器内部错误 + [HttpGet("GetListByKjbId")] + public async Task GetListByKjbId([FromQuery] LqKdKdjlbListByKjbQueryInput input) + { + try + { + if (string.IsNullOrEmpty(input.kjblsId)) + { + throw NCCException.Oh("科技部老师ID不能为空"); + } + + var sidx = input.sidx == null ? "kdrq" : input.sidx; + var sort = string.IsNullOrEmpty(input.sort) ? "DESC" : input.sort; + + // 解析时间范围 + DateTime? startDate = null; + DateTime? endDate = null; + if (!string.IsNullOrEmpty(input.startTime)) + { + startDate = Ext.GetDateTime(input.startTime); + } + if (!string.IsNullOrEmpty(input.endTime)) + { + endDate = Ext.GetDateTime(input.endTime); + // 如果只传了日期,则设置为当天的23:59:59 + if (endDate.HasValue && !input.endTime.Contains(":")) + { + endDate = new DateTime(endDate.Value.Year, endDate.Value.Month, endDate.Value.Day, 23, 59, 59); + } + } + + // 通过科技部老师业绩表关联查询开单记录 + var data = await _db.Queryable( + (kjbsyj, kdjlb) => kjbsyj.Glkdbh == kdjlb.Id) + .Where((kjbsyj, kdjlb) => kjbsyj.Kjbls == input.kjblsId) + .WhereIF(input.isEffective != 0, (kjbsyj, kdjlb) => kjbsyj.IsEffective == input.isEffective && kdjlb.IsEffective == input.isEffective) + .WhereIF(input.isEffective == 0, (kjbsyj, kdjlb) => kjbsyj.IsEffective == StatusEnum.有效.GetHashCode() && kdjlb.IsEffective == StatusEnum.有效.GetHashCode()) + .WhereIF(startDate.HasValue, (kjbsyj, kdjlb) => kdjlb.Kdrq >= startDate.Value) + .WhereIF(endDate.HasValue, (kjbsyj, kdjlb) => kdjlb.Kdrq <= endDate.Value) + .WhereIF(!string.IsNullOrEmpty(input.djmd), (kjbsyj, kdjlb) => kdjlb.Djmd == input.djmd) + .Select((kjbsyj, kdjlb) => new LqKdKdjlbListOutput + { + id = kdjlb.Id, + djmd = kdjlb.Djmd, + jsj = kdjlb.Jsj, + kdrq = kdjlb.Kdrq, + gjlx = kdjlb.Gjlx, + hgjg = kdjlb.Hgjg, + zdyj = kdjlb.Zdyj, + sfyj = kdjlb.Sfyj, + qk = kdjlb.Qk, + ckfs = kdjlb.Ckfs, + fkfs = kdjlb.Fkfs, + fkyy = kdjlb.Fkyy, + fkpd = kdjlb.Fkpd, + khly = kdjlb.Khly, + tjr = kdjlb.Tjr, + deductAmount = kdjlb.DeductAmount, + paidDebt = kdjlb.PaidDebt, + supplementBillingId = kdjlb.SupplementBillingId, + sfskdd = kdjlb.Sfskdd, + jj = kdjlb.Jj, + bz = kdjlb.Bz, + kdhy = kdjlb.Kdhy, + kdhyc = SqlFunc.Subqueryable().Where(x => x.Id == kdjlb.Kdhy).Select(x => x.Khmc), + kdhysjh = SqlFunc.Subqueryable().Where(x => x.Id == kdjlb.Kdhy).Select(x => x.Sjh), + isEffective = kdjlb.IsEffective, + createUser = kdjlb.CreateUser, + createUserName = SqlFunc.Subqueryable().Where(x => x.Id == kdjlb.CreateUser).Select(x => x.RealName), + activityId = kdjlb.ActivityId, + activityName = SqlFunc.Subqueryable().Where(x => x.Id == kdjlb.ActivityId).Select(x => x.ActivityName), + }) + .MergeTable() + .Distinct() // 去重,因为一个开单可能对应多个科技部老师业绩记录 + .OrderBy($"{sidx} {sort}") + .ToPagedListAsync(input.currentPage, input.pageSize); + + // 获取当前页的开单记录ID列表 + var billingIds = data.list.Select(x => x.id).ToList(); + + // 批量查询品项明细 + var itemDetails = new List(); + if (billingIds.Any()) + { + itemDetails = await _db.Queryable() + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode()) + .Select(x => new LqKdPxmxInfoOutput + { + id = x.Id, + glkdbh = x.Glkdbh, + px = x.Px, + pxmc = x.Pxmc, + pxjg = x.Pxjg, + projectNumber = x.ProjectNumber, + isEnabled = x.IsEnabled, + sourceType = x.SourceType, + memberId = x.MemberId, + createTime = x.CreateTIme, + totalPrice = x.TotalPrice, + actualPrice = x.ActualPrice, + remark = x.Remark, + isEffective = x.IsEffective + }) + .ToListAsync(); + } + + // 按开单ID分组品项明细 + var itemDetailsGrouped = itemDetails.GroupBy(x => x.glkdbh) + .ToDictionary(g => g.Key, g => g.ToList()); + + // 为每个开单记录分配品项明细 + foreach (var item in data.list) + { + item.ItemDetails = itemDetailsGrouped.ContainsKey(item.id) + ? itemDetailsGrouped[item.id] + : new List(); + } + + return PageResult.SqlSugarPageResult(data); + } + catch (Exception ex) + { + _logger.LogError(ex, $"根据科技部老师ID获取开单列表失败 - 科技部老师ID: {input?.kjblsId}, 开始时间: {input?.startTime}, 结束时间: {input?.endTime}"); + throw NCCException.Oh($"根据科技部老师ID获取开单列表失败: {ex.Message}"); + } + } + #endregion + #region 新建开单记录表 /// /// 新建开单记录表 @@ -563,6 +970,47 @@ namespace NCC.Extend.LqKdKdjlb // 字符串生成失败不影响主流程,只记录日志 Console.WriteLine($"生成开单记录字符串失败: {ex.Message}"); } + + // 播报事业部开单统计数据 + try + { + //判断如果开单金额大于0,则播报事业部开单统计数据 + if (newEntity.Sfyj > 0 && newEntity.Kdrq.HasValue) + { + var billingDate = newEntity.Kdrq.Value.ToString("yyyy-MM-dd"); + var statisticsInput = new BusinessUnitBillingStatisticsInput + { + Date = billingDate + }; + var statisticsText = await _dailyReportService.GetBusinessUnitBillingStatisticsText(statisticsInput); + + if (!string.IsNullOrEmpty(statisticsText) && !statisticsText.Contains("暂无开单数据")) + { + // 发送到企业微信群 + try + { + var sendResult = await _weChatBotService.SendTextMessage(statisticsText); + if (sendResult) + { + Console.WriteLine("事业部开单统计数据已成功发送到企业微信群"); + } + else + { + Console.WriteLine("事业部开单统计数据发送到企业微信群失败"); + } + } + catch (Exception wechatEx) + { + Console.WriteLine($"发送事业部开单统计数据异常: {wechatEx.Message}"); + } + } + } + } + catch (Exception ex) + { + // 播报失败不影响主流程,只记录日志 + Console.WriteLine($"播报事业部开单统计数据失败: {ex.Message}"); + } } catch (Exception ex) { diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs index ad22a1d..e7b3951 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs @@ -551,7 +551,8 @@ namespace NCC.Extend.LqKhxx x.Pxmc, x.Pxjg, x.SourceType, - x.ProjectNumber + x.ProjectNumber, + x.Remark }) .ToListAsync(); @@ -600,6 +601,7 @@ namespace NCC.Extend.LqKhxx ItemPrice = item.Pxjg, SourceType = item.SourceType, TotalPurchased = item.ProjectNumber, + Remark = item.Remark, ConsumedCount = consumedData.FirstOrDefault(c => c.BillingItemId == item.Id)?.TotalConsumed ?? 0, RefundedCount = refundedData.FirstOrDefault(r => r.BillingItemId == item.Id)?.TotalRefunded ?? 0, DeductCount = deductData.FirstOrDefault(d => d.BillingItemId == item.Id)?.TotalDeduct ?? 0, diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqMdGeneralManagerLifelineService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqMdGeneralManagerLifelineService.cs index 3189ddf..975f66c 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqMdGeneralManagerLifelineService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqMdGeneralManagerLifelineService.cs @@ -7,10 +7,12 @@ using Mapster; using Microsoft.AspNetCore.Mvc; using NCC.Common.Core.Manager; using NCC.Common.Enum; +using NCC.Common.Extension; using NCC.Common.Filter; using NCC.Dependency; using NCC.DynamicApiController; using NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline; +using NCC.Extend.Entitys.Enum; using NCC.Extend.Entitys.lq_md_general_manager_lifeline; using NCC.Extend.Entitys.lq_md_target; using NCC.Extend.Interfaces.LqMdGeneralManagerLifeline; @@ -77,6 +79,7 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline storeId = it.StoreId, month = it.Month, generalManagerId = it.GeneralManagerId, + managerType = it.ManagerType, lifeline1 = it.Lifeline1, commissionRate1 = it.CommissionRate1, lifeline2 = it.Lifeline2, @@ -92,6 +95,21 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline .MergeTable() .OrderBy(sidx + " " + input.sort) .ToPagedListAsync(input.currentPage, input.pageSize); + + // 设置经理类型中文名称 + foreach (var item in data.list) + { + if (Enum.IsDefined(typeof(ManagerTypeEnum), item.managerType)) + { + var enumValue = (ManagerTypeEnum)item.managerType; + item.managerTypeName = enumValue.GetDescription(); + } + else + { + item.managerTypeName = string.Empty; + } + } + return PageResult.SqlSugarPageResult(data); } #endregion @@ -273,6 +291,7 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline Id = YitIdHelper.NextId().ToString(), StoreId = target.StoreId, Month = target.Month, + ManagerType = ManagerTypeEnum.总经理.GetHashCode(), GeneralManagerId = target.BusinessUnitGeneralManager, Lifeline1 = 0, CommissionRate1 = 0, @@ -299,14 +318,15 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline Id = YitIdHelper.NextId().ToString(), StoreId = target.StoreId, Month = target.Month, + ManagerType = ManagerTypeEnum.经理.GetHashCode(), GeneralManagerId = target.BusinessUnitManager, Lifeline1 = 0, CommissionRate1 = 0, - Lifeline2 = null, - CommissionRate2 = null, - Lifeline3 = null, - CommissionRate3 = null, - Remark = null, + Lifeline2 = 0, + CommissionRate2 = 0, + Lifeline3 = 0, + CommissionRate3 = 0, + Remark = "", CreateTime = DateTime.Now, CreateUserId = userInfo.userId, }); @@ -405,6 +425,7 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline Id = YitIdHelper.NextId().ToString(), StoreId = p.StoreId, Month = targetMonthStr, + ManagerType = p.ManagerType, GeneralManagerId = p.GeneralManagerId, Lifeline1 = p.Lifeline1, CommissionRate1 = p.CommissionRate1, diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqPackageInfoService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqPackageInfoService.cs index 4ad743a..eb6bc42 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqPackageInfoService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqPackageInfoService.cs @@ -14,6 +14,9 @@ using NCC.Extend.Entitys.Enum; using NCC.Extend.Entitys.lq_package_info; using NCC.Extend.Entitys.lq_package_item_detail; using NCC.Extend.Entitys.lq_xmzl; +using NCC.Extend.Entitys.lq_kd_kdjlb; +using NCC.Extend.Entitys.lq_kd_pxmx; +using NCC.Extend.Entitys.lq_mdxx; using NCC.Extend.Interfaces.LqPackageInfo; using NCC.FriendlyException; using SqlSugar; @@ -693,5 +696,404 @@ namespace NCC.Extend.LqPackageInfo } #endregion + #region 营销活动按门店统计 + /// + /// 获取营销活动按门店统计数据 + /// + /// + /// 统计指定营销活动在各个门店的开单数据 + /// 包括:开单数量、开单金额、欠款金额、人头数、项目数 + /// + /// 示例请求: + /// ```json + /// { + /// "activityId": "营销活动ID", + /// "startTime": "2025-10-01", + /// "endTime": "2025-10-31", + /// "storeIds": ["门店ID1", "门店ID2"] + /// } + /// ``` + /// + /// 返回字段说明: + /// - ActivityId: 营销活动ID + /// - ActivityName: 营销活动名称 + /// - StoreList: 门店统计列表 + /// - StoreId: 门店ID + /// - StoreName: 门店名称 + /// - BillingCount: 开单数量 + /// - BillingAmount: 开单金额(实付业绩总和) + /// - DebtAmount: 欠款金额 + /// - CustomerCount: 人头数(去重客户数) + /// - ItemCount: 项目数(品项项目次数总和,使用F_ProjectNumber字段) + /// + /// 查询参数 + /// 按门店统计数据 + /// 成功返回统计数据 + /// 参数错误 + /// 服务器错误 + [HttpPost("get-activity-statistics-by-store")] + public async Task GetActivityStatisticsByStore(ActivityStatisticsInput input) + { + try + { + // 1. 获取营销活动信息 + var activity = await _db.Queryable() + .Where(x => x.Id == input.ActivityId && x.IsEffective == StatusEnum.有效.GetHashCode()) + .FirstAsync(); + + if (activity == null) + { + throw NCCException.Oh("营销活动不存在或已失效"); + } + + // 2. 设置时间范围(如果未提供,使用活动时间范围) + var startTime = input.StartTime ?? activity.StartTime; + var endTime = input.EndTime ?? activity.EndTime; + + // 3. 构建基础查询:开单记录 JOIN 门店表 + var baseQuery = _db.Queryable( + (kd, md) => kd.Djmd == md.Id) + .Where((kd, md) => kd.IsEffective == StatusEnum.有效.GetHashCode()) + .Where((kd, md) => kd.ActivityId == input.ActivityId) + .Where((kd, md) => kd.Kdrq.HasValue && kd.Kdrq.Value >= startTime && kd.Kdrq.Value <= endTime); + + // 4. 门店筛选 + if (input.StoreIds != null && input.StoreIds.Any()) + { + baseQuery = baseQuery.Where((kd, md) => input.StoreIds.Contains(kd.Djmd)); + } + + // 5. 按门店分组统计(先获取基础统计数据) + var storeStatistics = await baseQuery + .GroupBy((kd, md) => new { StoreId = kd.Djmd, StoreName = md.Dm }) + .Select((kd, md) => new + { + StoreId = kd.Djmd, + StoreName = md.Dm ?? "", + BillingCount = SqlFunc.AggregateCount(kd.Id), + BillingAmount = SqlFunc.AggregateSum(kd.Sfyj), + DebtAmount = SqlFunc.AggregateSum(kd.Qk) + }) + .ToListAsync(); + + // 6. 单独统计每个门店的人头数和项目数 + var storeList = new List(); + foreach (var stat in storeStatistics) + { + // 统计人头数(去重客户数) + var customerCountQuery = _db.Queryable() + .Where(kd => kd.Djmd == stat.StoreId + && kd.ActivityId == input.ActivityId + && kd.IsEffective == StatusEnum.有效.GetHashCode() + && kd.Kdrq.HasValue && kd.Kdrq.Value >= startTime && kd.Kdrq.Value <= endTime); + + if (input.StoreIds != null && input.StoreIds.Any()) + { + customerCountQuery = customerCountQuery.Where(kd => input.StoreIds.Contains(kd.Djmd)); + } + + var customerCount = await customerCountQuery + .GroupBy(kd => kd.Kdhy) + .Select(kd => kd.Kdhy) + .CountAsync(); + + // 统计项目数(品项项目次数总和,使用F_ProjectNumber字段) + var itemCountQuery = _db.Queryable( + (px, kd) => px.Glkdbh == kd.Id) + .Where((px, kd) => kd.Djmd == stat.StoreId + && px.IsEffective == StatusEnum.有效.GetHashCode() + && kd.IsEffective == StatusEnum.有效.GetHashCode() + && kd.ActivityId == input.ActivityId + && kd.Kdrq.HasValue && kd.Kdrq.Value >= startTime && kd.Kdrq.Value <= endTime); + + if (input.StoreIds != null && input.StoreIds.Any()) + { + itemCountQuery = itemCountQuery.Where((px, kd) => input.StoreIds.Contains(kd.Djmd)); + } + + var itemCount = await itemCountQuery + .Select((px, kd) => SqlFunc.AggregateSum(px.ProjectNumber)) + .FirstAsync(); + + storeList.Add(new StoreStatisticsItem + { + StoreId = stat.StoreId ?? "", + StoreName = stat.StoreName ?? "", + BillingCount = stat.BillingCount, + BillingAmount = stat.BillingAmount, + DebtAmount = stat.DebtAmount, + CustomerCount = customerCount, + ItemCount = itemCount + }); + } + + // 7. 排序 + storeList = storeList.OrderBy(x => x.StoreName).ToList(); + + // 7. 返回统计结果 + return new ActivityStatisticsByStoreOutput + { + ActivityId = input.ActivityId, + ActivityName = activity.ActivityName, + StoreList = storeList + }; + } + catch (Exception ex) + { + throw NCCException.Oh($"获取营销活动按门店统计数据失败: {ex.Message}"); + } + } + #endregion + + #region 营销活动按品项统计 + /// + /// 获取营销活动按品项统计数据 + /// + /// + /// 统计指定营销活动各个品项的销售情况 + /// 包括:销售数量、销售金额、开单数量、销售次数 + /// + /// 示例请求: + /// ```json + /// { + /// "activityId": "营销活动ID", + /// "startTime": "2025-10-01", + /// "endTime": "2025-10-31" + /// } + /// ``` + /// + /// 查询参数 + /// 按品项统计数据 + /// 成功返回统计数据 + /// 参数错误 + /// 服务器错误 + [HttpPost("get-activity-statistics-by-item")] + public async Task GetActivityStatisticsByItem(ActivityStatisticsInput input) + { + try + { + // 1. 获取营销活动信息 + var activity = await _db.Queryable() + .Where(x => x.Id == input.ActivityId && x.IsEffective == StatusEnum.有效.GetHashCode()) + .FirstAsync(); + + if (activity == null) + { + throw NCCException.Oh("营销活动不存在或已失效"); + } + + // 2. 设置时间范围(如果未提供,使用活动时间范围) + var startTime = input.StartTime ?? activity.StartTime; + var endTime = input.EndTime ?? activity.EndTime; + + // 3. 构建基础查询:品项明细 JOIN 开单记录(用于过滤活动ID和时间) + var baseQuery = _db.Queryable( + (px, kd) => px.Glkdbh == kd.Id) + .Where((px, kd) => px.IsEffective == StatusEnum.有效.GetHashCode()) + .Where((px, kd) => kd.IsEffective == StatusEnum.有效.GetHashCode()) + .Where((px, kd) => kd.ActivityId == input.ActivityId) + .Where((px, kd) => kd.Kdrq.HasValue && kd.Kdrq.Value >= startTime && kd.Kdrq.Value <= endTime); + + // 4. 门店筛选(如果提供) + if (input.StoreIds != null && input.StoreIds.Any()) + { + baseQuery = baseQuery.Where((px, kd) => input.StoreIds.Contains(kd.Djmd)); + } + + // 5. 按品项分组统计(先获取基础统计数据) + var itemStatistics = await baseQuery + .GroupBy((px, kd) => new { ItemId = px.Px, ItemName = px.Pxmc }) + .Select((px, kd) => new + { + ItemId = px.Px ?? "", + ItemName = px.Pxmc ?? "", + SalesQuantity = SqlFunc.AggregateSum(px.ProjectNumber), + SalesAmount = SqlFunc.AggregateSum(px.ActualPrice > 0 ? px.ActualPrice : px.TotalPrice), + SalesCount = SqlFunc.AggregateCount(px.Id) + }) + .ToListAsync(); + + // 6. 单独统计每个品项的开单数量(去重开单ID) + var itemList = new List(); + foreach (var stat in itemStatistics) + { + var billingCountQuery = _db.Queryable( + (px, kd) => px.Glkdbh == kd.Id) + .Where((px, kd) => px.Px == stat.ItemId + && px.IsEffective == StatusEnum.有效.GetHashCode() + && kd.IsEffective == StatusEnum.有效.GetHashCode() + && kd.ActivityId == input.ActivityId + && kd.Kdrq.HasValue && kd.Kdrq.Value >= startTime && kd.Kdrq.Value <= endTime); + + if (input.StoreIds != null && input.StoreIds.Any()) + { + billingCountQuery = billingCountQuery.Where((px, kd) => input.StoreIds.Contains(kd.Djmd)); + } + + var billingCount = await billingCountQuery + .GroupBy((px, kd) => px.Glkdbh) + .Select((px, kd) => px.Glkdbh) + .CountAsync(); + + itemList.Add(new ItemStatisticsItem + { + ItemId = stat.ItemId ?? "", + ItemName = stat.ItemName ?? "", + SalesQuantity = stat.SalesQuantity, + SalesAmount = stat.SalesAmount, + BillingCount = billingCount, + SalesCount = stat.SalesCount + }); + } + + // 7. 排序 + itemList = itemList.OrderBy(x => x.ItemName).ToList(); + + // 7. 返回统计结果 + return new ActivityStatisticsByItemOutput + { + ActivityId = input.ActivityId, + ActivityName = activity.ActivityName, + ItemList = itemList + }; + } + catch (Exception ex) + { + throw NCCException.Oh($"获取营销活动按品项统计数据失败: {ex.Message}"); + } + } + #endregion + + #region 营销活动按门店品项统计 + /// + /// 获取营销活动按门店品项统计数据 + /// + /// + /// 统计指定营销活动在各个门店的各个品项销售情况 + /// 包括:销售数量、销售金额、开单数量、销售次数 + /// + /// 示例请求: + /// ```json + /// { + /// "activityId": "营销活动ID", + /// "startTime": "2025-10-01", + /// "endTime": "2025-10-31", + /// "storeIds": ["门店ID1", "门店ID2"] + /// } + /// ``` + /// + /// 查询参数 + /// 按门店品项统计数据 + /// 成功返回统计数据 + /// 参数错误 + /// 服务器错误 + [HttpPost("get-activity-statistics-by-store-item")] + public async Task GetActivityStatisticsByStoreItem(ActivityStatisticsInput input) + { + try + { + // 1. 获取营销活动信息 + var activity = await _db.Queryable() + .Where(x => x.Id == input.ActivityId && x.IsEffective == StatusEnum.有效.GetHashCode()) + .FirstAsync(); + + if (activity == null) + { + throw NCCException.Oh("营销活动不存在或已失效"); + } + + // 2. 设置时间范围(如果未提供,使用活动时间范围) + var startTime = input.StartTime ?? activity.StartTime; + var endTime = input.EndTime ?? activity.EndTime; + + // 3. 构建基础查询:品项明细 JOIN 开单记录 JOIN 门店表 + var baseQuery = _db.Queryable( + (px, kd, md) => px.Glkdbh == kd.Id && kd.Djmd == md.Id) + .Where((px, kd, md) => px.IsEffective == StatusEnum.有效.GetHashCode()) + .Where((px, kd, md) => kd.IsEffective == StatusEnum.有效.GetHashCode()) + .Where((px, kd, md) => kd.ActivityId == input.ActivityId) + .Where((px, kd, md) => kd.Kdrq.HasValue && kd.Kdrq.Value >= startTime && kd.Kdrq.Value <= endTime); + + // 4. 门店筛选(如果提供) + if (input.StoreIds != null && input.StoreIds.Any()) + { + baseQuery = baseQuery.Where((px, kd, md) => input.StoreIds.Contains(kd.Djmd)); + } + + // 5. 按门店和品项分组统计(先获取基础统计数据) + var storeItemStatistics = await baseQuery + .GroupBy((px, kd, md) => new + { + StoreId = kd.Djmd, + StoreName = md.Dm, + ItemId = px.Px, + ItemName = px.Pxmc + }) + .Select((px, kd, md) => new + { + StoreId = kd.Djmd ?? "", + StoreName = md.Dm ?? "", + ItemId = px.Px ?? "", + ItemName = px.Pxmc ?? "", + SalesQuantity = SqlFunc.AggregateSum(px.ProjectNumber), + SalesAmount = SqlFunc.AggregateSum(px.ActualPrice > 0 ? px.ActualPrice : px.TotalPrice), + SalesCount = SqlFunc.AggregateCount(px.Id) + }) + .ToListAsync(); + + // 6. 单独统计每个门店品项的开单数量(去重开单ID) + var storeItemList = new List(); + foreach (var stat in storeItemStatistics) + { + var billingCountQuery = _db.Queryable( + (px, kd) => px.Glkdbh == kd.Id) + .Where((px, kd) => px.Px == stat.ItemId + && kd.Djmd == stat.StoreId + && px.IsEffective == StatusEnum.有效.GetHashCode() + && kd.IsEffective == StatusEnum.有效.GetHashCode() + && kd.ActivityId == input.ActivityId + && kd.Kdrq.HasValue && kd.Kdrq.Value >= startTime && kd.Kdrq.Value <= endTime); + + if (input.StoreIds != null && input.StoreIds.Any()) + { + billingCountQuery = billingCountQuery.Where((px, kd) => input.StoreIds.Contains(kd.Djmd)); + } + + var billingCount = await billingCountQuery + .GroupBy((px, kd) => px.Glkdbh) + .Select((px, kd) => px.Glkdbh) + .CountAsync(); + + storeItemList.Add(new StoreItemStatisticsItem + { + StoreId = stat.StoreId ?? "", + StoreName = stat.StoreName ?? "", + ItemId = stat.ItemId ?? "", + ItemName = stat.ItemName ?? "", + SalesQuantity = stat.SalesQuantity, + SalesAmount = stat.SalesAmount, + BillingCount = billingCount, + SalesCount = stat.SalesCount + }); + } + + // 7. 排序 + storeItemList = storeItemList.OrderBy(x => x.StoreName).ThenBy(x => x.ItemName).ToList(); + + // 7. 返回统计结果 + return new ActivityStatisticsByStoreItemOutput + { + ActivityId = input.ActivityId, + ActivityName = activity.ActivityName, + StoreItemList = storeItemList + }; + } + catch (Exception ex) + { + throw NCCException.Oh($"获取营销活动按门店品项统计数据失败: {ex.Message}"); + } + } + #endregion + } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs index cd79bb8..9101b8c 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs @@ -28,8 +28,11 @@ using NCC.Extend.Entitys.lq_kd_kjbsyj; using NCC.Extend.Entitys.lq_mdxx; using NCC.Extend.Entitys.lq_md_xdbhsj; using NCC.Extend.Entitys.lq_xh_kjbsyj; +using NCC.Extend.Entitys.lq_xh_hyhk; +using NCC.Extend.Entitys.lq_xh_pxmx; using NCC.Extend.Entitys.lq_ycsd_jsj; using NCC.Extend.Entitys.lq_yjmxb; +using NCC.Extend.Entitys.Enum; using NCC.Extend.Entitys.lq_statistics_gold_triangle; using NCC.Extend.Entitys.lq_statistics_personal_performance; using NCC.Extend.Entitys.lq_statistics_store_consume_performance; @@ -831,120 +834,183 @@ namespace NCC.Extend.LqStatistics /// /// 获取科技部老师业绩统计 /// + /// + /// 统计科技部老师的开单业绩、消耗业绩、手工费等相关数据 + /// + /// 示例请求: + /// ```json + /// { + /// "startDate": "2025-01-01T00:00:00", + /// "endDate": "2025-01-31T23:59:59", + /// "teacherId": "科技部老师ID(可选)", + /// "teacherName": "科技部老师姓名(可选)" + /// } + /// ``` + /// + /// 参数说明: + /// - startDate: 开始日期(可选) + /// - endDate: 结束日期(可选) + /// - teacherId: 科技部老师ID(可选) + /// - teacherName: 科技部老师姓名(可选) + /// + /// 返回数据说明: + /// - DepartmentName: 部门名称(固定为"科技部") + /// - TeacherName: 老师姓名 + /// - ConsumeProjectCount: 消耗项目数 + /// - ConsumeAchievement: 消耗业绩 + /// - OrderAchievement: 开单业绩(开卡业绩) + /// - OrderItemCount: 开单品项次数 + /// - ConsumeItemCount: 耗卡品项次数 + /// - ConsumeLaborCost: 消耗手工费(耗卡手工费) + /// /// 查询参数 - /// 科技部老师业绩统计结果 + /// 科技部老师业绩统计结果列表,包含开单业绩、消耗业绩、手工费等数据 + /// 成功返回统计数据 + /// 参数错误 + /// 服务器内部错误 [HttpPost("GetTechTeacherStatistics")] [AllowAnonymous] public async Task> GetTechTeacherStatistics(TechTeacherStatisticsInput input) { try - { // 1. 从用户表获取所有科技部老师 - var allTeachers = await _db.Queryable() - .Where(x => x.Gw == "科技老师") + { + // 1. 验证必须传入科技老师ID + if (string.IsNullOrEmpty(input.TeacherId)) + { + return new List + { + new TechTeacherSimpleStatisticsOutput + { + DepartmentName = "科技部", + TeacherName = "", + OrderAchievement = 0m, + OrderItemCount = 0, + ConsumeAchievement = 0m, + ConsumeItemCount = 0, + ConsumeProjectCount = 0, + ConsumeLaborCost = 0m, + } + }; + } + + // 2. 获取科技老师信息 + var teacher = await _db.Queryable() + .Where(x => x.Gw == "科技老师" && x.Id == input.TeacherId) .Select(x => new { TeacherId = x.Id, TeacherName = x.RealName, TeacherAccount = x.Account, }) - .ToListAsync(); - - // 2. 获取业绩流水数据 - var flowQuery = _db.Queryable(); + .FirstAsync(); - // 老师过滤 - if (!string.IsNullOrEmpty(input.TeacherId)) + if (teacher == null) { - flowQuery = flowQuery.Where(x => x.TeacherId == input.TeacherId); + return new List + { + new TechTeacherSimpleStatisticsOutput + { + DepartmentName = "科技部", + TeacherName = "", + OrderAchievement = 0m, + OrderItemCount = 0, + ConsumeAchievement = 0m, + ConsumeItemCount = 0, + ConsumeProjectCount = 0, + ConsumeLaborCost = 0m, + } + }; } - if (!string.IsNullOrEmpty(input.TeacherName)) - { - flowQuery = flowQuery.Where(x => x.TeacherName.Contains(input.TeacherName)); - } + // 3. 查询开单业绩(从 lq_kd_kjbsyj 关联 lq_kd_kdjlb 和 lq_kd_pxmx) + var orderQuery = _db.Queryable( + (kjbsyj, kdjlb, pxmx) => kjbsyj.Glkdbh == kdjlb.Id && kjbsyj.Kdpxid == pxmx.Id) + .Where((kjbsyj, kdjlb, pxmx) => kjbsyj.IsEffective == StatusEnum.有效.GetHashCode()) + .Where((kjbsyj, kdjlb, pxmx) => kdjlb.IsEffective == StatusEnum.有效.GetHashCode()) + .Where((kjbsyj, kdjlb, pxmx) => kjbsyj.Kjblszh == teacher.TeacherAccount); // 日期过滤 if (input.StartDate.HasValue) { - flowQuery = flowQuery.Where(x => x.BusinessDate >= input.StartDate.Value); + orderQuery = orderQuery.Where((kjbsyj, kdjlb, pxmx) => kjbsyj.Yjsj >= input.StartDate.Value); } if (input.EndDate.HasValue) { - flowQuery = flowQuery.Where(x => x.BusinessDate <= input.EndDate.Value); + orderQuery = orderQuery.Where((kjbsyj, kdjlb, pxmx) => kjbsyj.Yjsj <= input.EndDate.Value); } - var flowRecords = await flowQuery.ToListAsync(); - - // 3. 按老师分组统计业绩数据 - var teacherStatsDict = flowRecords - .GroupBy(x => new + var orderStats = await orderQuery + .Select((kjbsyj, kdjlb, pxmx) => new { - x.TeacherId, - x.TeacherName, - x.TeacherAccount, + OrderAchievement = SqlFunc.ToDecimal(kjbsyj.Kjblsyj), + OrderItemCount = SqlFunc.ToInt32(pxmx.ProjectNumber), }) - .ToDictionary( - g => g.Key, - g => new - { - ConsumeProjectCount = (int)g.Where(x => x.BusinessType == "耗卡").Sum(x => x.ProjectCount), - ConsumeAchievement = g.Where(x => x.BusinessType == "耗卡").Sum(x => x.Achievement), - OrderAchievement = g.Where(x => x.BusinessType == "开卡").Sum(x => x.Achievement), - OrderItemCount = g.Where(x => x.BusinessType == "开卡").Sum(x => x.ItemCount), - ConsumeItemCount = g.Where(x => x.BusinessType == "耗卡").Sum(x => x.ItemCount), - } - ); + .ToListAsync(); - // 4. 构建结果,包含所有老师 - var result = new List(); + // 4. 查询耗卡业绩(从 lq_xh_kjbsyj 关联 lq_xh_hyhk 和 lq_xh_pxmx) + // 注意:lq_xh_kjbsyj.kjbls 字段存储的是健康师id,不是科技部老师id + // 科技部老师信息在 kjblszh(账号)和 kjblsxm(姓名)字段 + var consumeQuery = _db.Queryable( + (kjbsyj, hyhk, pxmx) => kjbsyj.Glkdbh == hyhk.Id && kjbsyj.Hkpxid == pxmx.Id) + .Where((kjbsyj, hyhk, pxmx) => kjbsyj.IsEffective == StatusEnum.有效.GetHashCode()) + .Where((kjbsyj, hyhk, pxmx) => hyhk.IsEffective == StatusEnum.有效.GetHashCode()) + .Where((kjbsyj, hyhk, pxmx) => kjbsyj.Kjblszh == teacher.TeacherAccount); - foreach (var teacher in allTeachers) + // 日期过滤 + if (input.StartDate.HasValue) { - // 应用过滤条件 - if (!string.IsNullOrEmpty(input.TeacherId) && teacher.TeacherId != input.TeacherId) - continue; - - if (!string.IsNullOrEmpty(input.TeacherName) && !teacher.TeacherName.Contains(input.TeacherName)) - continue; + consumeQuery = consumeQuery.Where((kjbsyj, hyhk, pxmx) => kjbsyj.Yjsj >= input.StartDate.Value); + } - var stats = teacherStatsDict.GetValueOrDefault( - new - { - TeacherId = teacher.TeacherId, - TeacherName = teacher.TeacherName, - TeacherAccount = teacher.TeacherAccount, - }, - new - { - ConsumeProjectCount = 0, - ConsumeAchievement = 0m, - OrderAchievement = 0m, - OrderItemCount = 0, - ConsumeItemCount = 0, - } - ); + if (input.EndDate.HasValue) + { + consumeQuery = consumeQuery.Where((kjbsyj, hyhk, pxmx) => kjbsyj.Yjsj <= input.EndDate.Value); + } - var teacherStats = new TechTeacherSimpleStatisticsOutput + var consumeStats = await consumeQuery + .Select((kjbsyj, hyhk, pxmx) => new { - DepartmentName = "科技部", // 固定为科技部 - TeacherName = teacher.TeacherName, - ConsumeProjectCount = stats.ConsumeProjectCount, - ConsumeAchievement = stats.ConsumeAchievement, - OrderAchievement = stats.OrderAchievement, - OrderItemCount = stats.OrderItemCount, - ConsumeItemCount = stats.ConsumeItemCount, - }; + ConsumeAchievement = kjbsyj.Kjblsyj, + ConsumeItemCount = SqlFunc.ToInt32(pxmx.ProjectNumber), + ConsumeProjectCount = SqlFunc.ToInt32(kjbsyj.HdpxNumber), + ConsumeLaborCost = kjbsyj.LaborCost, + }) + .ToListAsync(); - result.Add(teacherStats); - } + // 5. 统计并返回结果 + var result = new TechTeacherSimpleStatisticsOutput + { + DepartmentName = "科技部", + TeacherName = teacher.TeacherName, + OrderAchievement = orderStats.Sum(x => x.OrderAchievement != null && decimal.TryParse(x.OrderAchievement.ToString(), out var val) ? val : 0m), + OrderItemCount = orderStats.Sum(x => x.OrderItemCount), + ConsumeAchievement = consumeStats.Sum(x => x.ConsumeAchievement ?? 0m), + ConsumeItemCount = consumeStats.Sum(x => x.ConsumeItemCount), + ConsumeProjectCount = consumeStats.Sum(x => x.ConsumeProjectCount), + ConsumeLaborCost = consumeStats.Sum(x => x.ConsumeLaborCost ?? 0m), + }; - return result; + return new List { result }; } catch (Exception ex) { _logger.LogError(ex, "获取科技部老师业绩统计时发生错误"); - throw NCCException.Oh("获取科技部老师业绩统计失败", ex); + // 发生错误时返回全0的结果,而不是抛出异常 + return new List + { + new TechTeacherSimpleStatisticsOutput + { + DepartmentName = "科技部", + TeacherName = "", + OrderAchievement = 0m, + OrderItemCount = 0, + ConsumeAchievement = 0m, + ConsumeItemCount = 0, + ConsumeProjectCount = 0, + ConsumeLaborCost = 0m, + } + }; } } @@ -3672,6 +3738,5 @@ namespace NCC.Extend.LqStatistics } #endregion - } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs index ff2ed7d..63bccf5 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs @@ -1043,12 +1043,18 @@ namespace NCC.Extend.LqXhHyhk Kjblsyj = ikjbs_tem.kjblsyj, Yjsj = DateTime.Now, Hkpxid = lqXhPxmxEntity.Id, + // OriginalHdpxNumber = ikjbs_tem.hdpxNumber, + // OvertimeHdpxNumber = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0)), + // HdpxNumber = (decimal)((ikjbs_tem.hdpxNumber ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0))), OriginalHdpxNumber = ikjbs_tem.hdpxNumber, - OvertimeHdpxNumber = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0)), - HdpxNumber = (decimal)((ikjbs_tem.hdpxNumber ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0))), + OvertimeHdpxNumber = 0, + HdpxNumber = ikjbs_tem.hdpxNumber, + // OriginalLaborCost = ikjbs_tem.laborCost, + // OvertimeLaborCost = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0)), + // LaborCost = (decimal)((ikjbs_tem.laborCost ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0))), OriginalLaborCost = ikjbs_tem.laborCost, - OvertimeLaborCost = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0)), - LaborCost = (decimal)((ikjbs_tem.laborCost ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0))), + OvertimeLaborCost = 0, + LaborCost = ikjbs_tem.laborCost, IsEffective = StatusEnum.有效.GetHashCode(), } ); @@ -1328,12 +1334,18 @@ namespace NCC.Extend.LqXhHyhk Kjblsyj = ikjbs_tem.kjblsyj, Yjsj = DateTime.Now, Hkpxid = lqXhPxmxEntity.Id, + // OriginalHdpxNumber = ikjbs_tem.hdpxNumber, + // OvertimeHdpxNumber = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0)), + // HdpxNumber = (decimal)((ikjbs_tem.hdpxNumber ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0))), + // OriginalLaborCost = ikjbs_tem.laborCost, + // OvertimeLaborCost = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0)), + // LaborCost = (decimal)((ikjbs_tem.laborCost ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0))), OriginalHdpxNumber = ikjbs_tem.hdpxNumber, - OvertimeHdpxNumber = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0)), - HdpxNumber = (decimal)((ikjbs_tem.hdpxNumber ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.hdpxNumber ?? 0))), + OvertimeHdpxNumber = 0, + HdpxNumber = ikjbs_tem.hdpxNumber, OriginalLaborCost = ikjbs_tem.laborCost, - OvertimeLaborCost = (decimal)(entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0)), - LaborCost = (decimal)((ikjbs_tem.laborCost ?? 0) + (entity.OvertimeCoefficient * (ikjbs_tem.laborCost ?? 0))), + OvertimeLaborCost = 0, + LaborCost = ikjbs_tem.laborCost, IsEffective = StatusEnum.有效.GetHashCode(), }); } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqYaoyjlService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqYaoyjlService.cs index 3b45e75..dd1d95d 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqYaoyjlService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqYaoyjlService.cs @@ -93,6 +93,7 @@ namespace NCC.Extend.LqYaoyjl .WhereIF(queryLxsj != null, p => p.Lxsj >= new DateTime(startLxsj.ToDate().Year, startLxsj.ToDate().Month, startLxsj.ToDate().Day, 0, 0, 0)) .WhereIF(queryLxsj != null, p => p.Lxsj <= new DateTime(endLxsj.ToDate().Year, endLxsj.ToDate().Month, endLxsj.ToDate().Day, 23, 59, 59)) .WhereIF(!string.IsNullOrEmpty(input.lxjl), p => p.Lxjl.Contains(input.lxjl)) + .WhereIF(!string.IsNullOrEmpty(input.storeId), p => p.StoreId.Equals(input.storeId)) .Select(it => new LqYaoyjlListOutput { id = it.Id, @@ -158,6 +159,7 @@ namespace NCC.Extend.LqYaoyjl .WhereIF(queryLxsj != null, p => p.Lxsj >= new DateTime(startLxsj.ToDate().Year, startLxsj.ToDate().Month, startLxsj.ToDate().Day, 0, 0, 0)) .WhereIF(queryLxsj != null, p => p.Lxsj <= new DateTime(endLxsj.ToDate().Year, endLxsj.ToDate().Month, endLxsj.ToDate().Day, 23, 59, 59)) .WhereIF(!string.IsNullOrEmpty(input.lxjl), p => p.Lxjl.Contains(input.lxjl)) + .WhereIF(!string.IsNullOrEmpty(input.storeId), p => p.StoreId.Equals(input.storeId)) .Select(it => new LqYaoyjlListOutput { id = it.Id, diff --git a/netcore/src/Modularity/Extend/NCC.Extend/Utils/WeChatBotService.cs b/netcore/src/Modularity/Extend/NCC.Extend/Utils/WeChatBotService.cs index 88c785a..7dc6b81 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/Utils/WeChatBotService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/Utils/WeChatBotService.cs @@ -3,6 +3,7 @@ using System.Net.Http; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; +using NCC; namespace NCC.Extend.Utils { @@ -12,17 +13,28 @@ namespace NCC.Extend.Utils public class WeChatBotService { private readonly HttpClient _httpClient; - private const string BOT_API_URL = "http://wx.lvqianmeiye.com/api/Bot/send-text"; - //正式地址 - //https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=581c22a6-cb67-42e5-8c76-b8e90052e188 - //测试地址 - //https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=6f8686ec-5011-4c1d-bae9-d82a2a2f4d83 - private const string WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=496f1add-122b-43fc-9e38-0ca79c48b33f"; - private const string WEBHOOK_URL_TEST = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=6f8686ec-5011-4c1d-bae9-d82a2a2f4d83"; + private readonly string _botApiUrl; + private readonly string _webhookUrl; + /// + /// 初始化企业微信机器人服务 + /// + /// HTTP客户端 public WeChatBotService(HttpClient httpClient) { _httpClient = httpClient; + + // 从配置文件中读取企业微信机器人配置 + _botApiUrl = App.Configuration["WeChatBot:BotApiUrl"] ?? "http://wx.lvqianmeiye.com/api/Bot/send-text"; + + // 从配置文件中读取Webhook地址(正式或测试地址,通过配置文件切换) + _webhookUrl = App.Configuration["WeChatBot:WebhookUrl"]; + + // 如果配置文件中没有配置,使用默认值 + if (string.IsNullOrEmpty(_webhookUrl)) + { + _webhookUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=496f1add-122b-43fc-9e38-0ca79c48b33f"; + } } /// @@ -36,8 +48,7 @@ namespace NCC.Extend.Utils { var requestData = new { - webhookUrl = WEBHOOK_URL, - // webhookUrl = WEBHOOK_URL_TEST, + webhookUrl = _webhookUrl, content = content, mentionedList = (string)null, mentionedMobileList = (string)null, @@ -46,7 +57,7 @@ namespace NCC.Extend.Utils var json = JsonConvert.SerializeObject(requestData); var httpContent = new StringContent(json, Encoding.UTF8, "application/json"); - var response = await _httpClient.PostAsync(BOT_API_URL, httpContent); + var response = await _httpClient.PostAsync(_botApiUrl, httpContent); if (response.IsSuccessStatusCode) {