diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitPerformanceCompletionInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitPerformanceCompletionInput.cs new file mode 100644 index 0000000..341cca3 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitPerformanceCompletionInput.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 事业部业绩完成情况输入参数 + /// + public class BusinessUnitPerformanceCompletionInput + { + /// + /// 开始时间(可选,不传则默认为当月1号) + /// + public DateTime? StartTime { get; set; } + + /// + /// 结束时间(可选,不传则默认为今天) + /// + public DateTime? EndTime { get; set; } + + /// + /// 事业部ID列表(可选,为空则查询所有事业部) + /// + public List BusinessUnitIds { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitPerformanceCompletionOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitPerformanceCompletionOutput.cs new file mode 100644 index 0000000..1209cba --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitPerformanceCompletionOutput.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 事业部业绩完成情况输出结果 + /// + public class BusinessUnitPerformanceCompletionOutput + { + /// + /// 事业部ID + /// + public string BusinessUnitId { get; set; } + + /// + /// 事业部名称 + /// + public string BusinessUnitName { get; set; } + + /// + /// 目标业绩(管理门店的生命线总和) + /// + public decimal TargetPerformance { get; set; } + + /// + /// 完成业绩(管理门店的开单业绩总和) + /// + public decimal CompletedPerformance { get; set; } + + /// + /// 完成率(百分比) + /// + public decimal CompletionRate { get; set; } + + /// + /// 门店数量 + /// + public int StoreCount { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/ManagerPerformanceCompletionInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/ManagerPerformanceCompletionInput.cs new file mode 100644 index 0000000..e8f12d2 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/ManagerPerformanceCompletionInput.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 经理业绩完成情况输入参数 + /// + public class ManagerPerformanceCompletionInput + { + /// + /// 开始时间(可选,不传则默认为当月1号) + /// + public DateTime? StartTime { get; set; } + + /// + /// 结束时间(可选,不传则默认为今天) + /// + public DateTime? EndTime { get; set; } + + /// + /// 经理用户ID(可选) + /// + public string ManagerId { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/ManagerPerformanceCompletionOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/ManagerPerformanceCompletionOutput.cs new file mode 100644 index 0000000..3f01cc4 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/ManagerPerformanceCompletionOutput.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 经理业绩完成情况输出结果 + /// + public class ManagerPerformanceCompletionOutput + { + /// + /// 经理用户ID + /// + public string ManagerId { get; set; } + + /// + /// 经理姓名 + /// + public string ManagerName { get; set; } + + /// + /// 门店ID + /// + public string StoreId { get; set; } + + /// + /// 门店名称 + /// + public string StoreName { get; set; } + + /// + /// 目标业绩一阶段(smx1) + /// + public decimal Target1 { get; set; } + + /// + /// 目标业绩二阶段(smx2) + /// + public decimal? Target2 { get; set; } + + /// + /// 目标业绩三阶段(smx3) + /// + public decimal? Target3 { get; set; } + + /// + /// 完成业绩 + /// + public decimal CompletedPerformance { get; set; } + + /// + /// 完成率一阶段(%) + /// + public decimal CompletionRate1 { get; set; } + + /// + /// 完成率二阶段(%) + /// + public decimal? CompletionRate2 { get; set; } + + /// + /// 完成率三阶段(%) + /// + public decimal? CompletionRate3 { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/ManagerSummaryPerformanceCompletionOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/ManagerSummaryPerformanceCompletionOutput.cs new file mode 100644 index 0000000..20b8242 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/ManagerSummaryPerformanceCompletionOutput.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 经理汇总业绩完成情况输出结果 + /// + public class ManagerSummaryPerformanceCompletionOutput + { + /// + /// 经理用户ID + /// + public string ManagerId { get; set; } + + /// + /// 经理姓名 + /// + public string ManagerName { get; set; } + + /// + /// 总目标业绩一阶段 + /// + public decimal TotalTarget1 { get; set; } + + /// + /// 总目标业绩二阶段 + /// + public decimal TotalTarget2 { get; set; } + + /// + /// 总目标业绩三阶段 + /// + public decimal TotalTarget3 { get; set; } + + /// + /// 总完成业绩 + /// + public decimal TotalCompletedPerformance { get; set; } + + /// + /// 总完成率一阶段(%) + /// + public decimal TotalCompletionRate1 { get; set; } + + /// + /// 总完成率二阶段(%) + /// + public decimal TotalCompletionRate2 { get; set; } + + /// + /// 总完成率三阶段(%) + /// + public decimal TotalCompletionRate3 { get; set; } + + /// + /// 管理门店数量 + /// + public int StoreCount { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StoreDailyStatisticsInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StoreDailyStatisticsInput.cs new file mode 100644 index 0000000..d25c47d --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StoreDailyStatisticsInput.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 门店每日统计输入参数 + /// + public class StoreDailyStatisticsInput + { + /// + /// 开始时间(可选,不传则默认为当月1号) + /// + public DateTime? StartTime { get; set; } + + /// + /// 结束时间(可选,不传则默认为今天) + /// + public DateTime? EndTime { get; set; } + + /// + /// 门店ID列表(可选,为空则查询所有门店) + /// + public List StoreIds { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StoreDailyStatisticsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StoreDailyStatisticsOutput.cs new file mode 100644 index 0000000..c1830e9 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StoreDailyStatisticsOutput.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 门店每日统计输出结果 + /// + public class StoreDailyStatisticsOutput + { + /// + /// 门店ID + /// + public string StoreId { get; set; } + + /// + /// 门店名称 + /// + public string StoreName { get; set; } + + /// + /// 在职员工数 + /// + public int EmployeeCount { get; set; } + + /// + /// 人头数(去重后的消费会员数) + /// + public int HeadCount { get; set; } + + /// + /// 人次(日度去重客户数) + /// + public int PersonCount { get; set; } + + /// + /// 项目数(消耗的项目总数) + /// + public int ProjectCount { get; set; } + + /// + /// 消耗业绩(总金额) + /// + public decimal ConsumePerformance { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StorePerformanceCompletionInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StorePerformanceCompletionInput.cs new file mode 100644 index 0000000..2d833a2 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StorePerformanceCompletionInput.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 门店业绩完成情况输入参数 + /// + public class StorePerformanceCompletionInput + { + /// + /// 开始时间(可选,不传则默认为当月1号) + /// + public DateTime? StartTime { get; set; } + + /// + /// 结束时间(可选,不传则默认为今天) + /// + public DateTime? EndTime { get; set; } + + /// + /// 门店ID列表(可选,为空则查询所有门店) + /// + public List StoreIds { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StorePerformanceCompletionOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StorePerformanceCompletionOutput.cs new file mode 100644 index 0000000..29b0936 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/StorePerformanceCompletionOutput.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 门店业绩完成情况输出结果 + /// + public class StorePerformanceCompletionOutput + { + /// + /// 门店ID + /// + public string StoreId { get; set; } + + /// + /// 门店名称 + /// + public string StoreName { get; set; } + + /// + /// 目标业绩(生命线) + /// + public decimal TargetPerformance { get; set; } + + /// + /// 完成业绩(开单业绩) + /// + public decimal CompletedPerformance { get; set; } + + /// + /// 完成率(百分比) + /// + public decimal CompletionRate { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/TechTeacherDailyStatisticsInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/TechTeacherDailyStatisticsInput.cs new file mode 100644 index 0000000..60c77b2 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/TechTeacherDailyStatisticsInput.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 科技部老师统计输入参数 + /// + public class TechTeacherDailyStatisticsInput + { + /// + /// 开始时间(可选,不传则默认为当月1号) + /// + public DateTime? StartTime { get; set; } + + /// + /// 结束时间(可选,不传则默认为今天) + /// + public DateTime? EndTime { get; set; } + + /// + /// 科技部ID(可选,不传则查询所有科技部) + /// + public string TechDepartmentId { get; set; } + + /// + /// 老师ID列表(可选) + /// + public List TeacherIds { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/TechTeacherDailyStatisticsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/TechTeacherDailyStatisticsOutput.cs new file mode 100644 index 0000000..ac3290a --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/TechTeacherDailyStatisticsOutput.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 科技部老师统计输出结果 + /// + public class TechTeacherDailyStatisticsOutput + { + /// + /// 科技部ID + /// + public string TechDepartmentId { get; set; } + + /// + /// 科技部名称 + /// + public string TechDepartmentName { get; set; } + + /// + /// 老师ID + /// + public string TeacherId { get; set; } + + /// + /// 老师姓名 + /// + public string TeacherName { get; set; } + + /// + /// 见客数(不同客户数量) + /// + public int CustomerCount { get; set; } + + /// + /// 消耗项目数 + /// + public int ConsumeProjectCount { get; set; } + + /// + /// 消耗业绩 + /// + public decimal ConsumeAchievement { get; set; } + + /// + /// 开单业绩 + /// + public decimal OrderAchievement { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/TianwangGroupPerformanceCompletionInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/TianwangGroupPerformanceCompletionInput.cs new file mode 100644 index 0000000..567f81b --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/TianwangGroupPerformanceCompletionInput.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 天王团业绩完成情况输入参数 + /// + public class TianwangGroupPerformanceCompletionInput + { + /// + /// 开始时间(可选,不传则默认为当月1号) + /// + public DateTime? StartTime { get; set; } + + /// + /// 结束时间(可选,不传则默认为今天) + /// + public DateTime? EndTime { get; set; } + + /// + /// 天王团部门ID列表(可选,为空则查询所有天王团) + /// + public List DepartmentIds { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/TianwangGroupPerformanceCompletionOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/TianwangGroupPerformanceCompletionOutput.cs new file mode 100644 index 0000000..b033c17 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/TianwangGroupPerformanceCompletionOutput.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqDailyReport +{ + /// + /// 天王团业绩完成情况输出结果 + /// + public class TianwangGroupPerformanceCompletionOutput + { + /// + /// 部门ID + /// + public string DepartmentId { get; set; } + + /// + /// 部门名称 + /// + public string DepartmentName { get; set; } + + /// + /// 目标业绩(管理门店的生命线总和) + /// + public decimal TargetPerformance { get; set; } + + /// + /// 完成业绩(管理门店的开单业绩总和) + /// + public decimal CompletedPerformance { get; set; } + + /// + /// 完成率(百分比) + /// + public decimal CompletionRate { get; set; } + + /// + /// 门店数量 + /// + public int StoreCount { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsInput.cs index be246de..e958e3a 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsInput.cs @@ -28,5 +28,15 @@ namespace NCC.Extend.Entitys.Dto.LqPackageInfo /// 门店ID列表(可选) /// public string[] StoreIds { get; set; } + + /// + /// 页码(默认1) + /// + public int PageIndex { get; set; } = 1; + + /// + /// 每页数量(默认20) + /// + public int PageSize { get; set; } = 20; } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsOutput.cs index 2cc73dc..7f81c61 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqPackageInfo/ActivityStatisticsOutput.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace NCC.Extend.Entitys.Dto.LqPackageInfo { @@ -28,28 +29,59 @@ namespace NCC.Extend.Entitys.Dto.LqPackageInfo public decimal BillingAmount { get; set; } /// - /// 退卡数量 + /// 欠款金额(所有开单的欠款总和) /// - public int RefundCount { get; set; } + public decimal DebtAmount { get; set; } /// - /// 退卡金额 + /// 开单列表 /// - public decimal RefundAmount { get; set; } + public List BillingList { get; set; } + } + + /// + /// 活动开单项 + /// + public class ActivityBillingItem + { + /// + /// 开单ID + /// + public string BillingId { get; set; } + + /// + /// 开单日期 + /// + public DateTime? BillingDate { get; set; } /// - /// 净开单数量(开单数量 - 退卡数量) + /// 客户名称 /// - public int NetBillingCount { get; set; } + public string CustomerName { get; set; } /// - /// 净开单金额(开单金额 - 退卡金额) + /// 客户电话 + /// + public string CustomerPhone { get; set; } + + /// + /// 门店ID + /// + public string StoreId { get; set; } + + /// + /// 门店名称 + /// + public string StoreName { get; set; } + + /// + /// 开单金额 /// - public decimal NetBillingAmount { get; set; } + public decimal Amount { get; set; } /// - /// 退卡率(退卡数量 / 开单数量) + /// 欠款金额 /// - public decimal RefundRate { get; set; } + public decimal DebtAmount { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReport/BusinessStatisticsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReport/BusinessStatisticsOutput.cs index 5f59484..5288ed5 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReport/BusinessStatisticsOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReport/BusinessStatisticsOutput.cs @@ -34,5 +34,30 @@ namespace NCC.Extend.Entitys.Dto.LqReport /// 退卡人数 /// public int RefundCount { get; set; } + + /// + /// 消耗目标业绩(所有门店xhyj字段的总和) + /// + public decimal TargetConsumeAmount { get; set; } + + /// + /// 消耗完成率(耗卡总金额 / 消耗目标业绩 * 100) + /// + public decimal ConsumeCompletionRate { get; set; } + + /// + /// 开单目标业绩(所有门店xsyj字段的总和) + /// + public decimal TargetBillingAmount { get; set; } + + /// + /// 开单完成业绩(开单总金额 - 退卡总金额) + /// + public decimal CompletedBillingAmount { get; set; } + + /// + /// 开单完成率(完成业绩 / 开单目标业绩 * 100) + /// + public decimal BillingCompletionRate { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/EmployeePerformanceStatisticsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/EmployeePerformanceStatisticsOutput.cs index f86697b..3ded29a 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/EmployeePerformanceStatisticsOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/EmployeePerformanceStatisticsOutput.cs @@ -69,5 +69,15 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics /// 人次(日度去重客户数) /// public int PersonCount { get; set; } + + /// + /// 开单项目数(项目次数总和) + /// + public int BillingProjectCount { get; set; } + + /// + /// 消耗项目数(项目次数总和) + /// + public int ConsumeProjectCount { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTkjlb/TkStatisticsInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTkjlb/TkStatisticsInput.cs new file mode 100644 index 0000000..3850358 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTkjlb/TkStatisticsInput.cs @@ -0,0 +1,26 @@ +using System; + +namespace NCC.Extend.Entitys.Dto.LqTkjlb +{ + /// + /// 拓客统计数据输入 + /// + public class TkStatisticsInput + { + /// + /// 开始时间(可选) + /// + public DateTime? StartTime { get; set; } + + /// + /// 结束时间(可选) + /// + public DateTime? EndTime { get; set; } + + /// + /// 活动ID(可选) + /// + public string EventId { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTkjlb/TkStatisticsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTkjlb/TkStatisticsOutput.cs new file mode 100644 index 0000000..9bee31c --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTkjlb/TkStatisticsOutput.cs @@ -0,0 +1,51 @@ +using System; + +namespace NCC.Extend.Entitys.Dto.LqTkjlb +{ + /// + /// 拓客统计数据输出 + /// + public class TkStatisticsOutput + { + /// + /// 拓客人数(去重后的人数) + /// + public int TkCount { get; set; } + + /// + /// 邀约人头(已邀约人数) + /// + public int YaoyCount { get; set; } + + /// + /// 预约人头(已预约人数) + /// + public int YyCount { get; set; } + + /// + /// 到店人头(已到店人数) + /// + public int DdCount { get; set; } + + /// + /// 开单人头(已开单人数) + /// + public int KdCount { get; set; } + + /// + /// 开单金额 + /// + public decimal KdAmount { get; set; } + + /// + /// 消费人头(已消费人数) + /// + public int XfCount { get; set; } + + /// + /// 消费金额 + /// + public decimal XfAmount { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/ILqTkjlbService.cs b/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/ILqTkjlbService.cs index 4a5be4d..d651f5b 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/ILqTkjlbService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/ILqTkjlbService.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using NCC.Extend.Entitys.Dto.LqTkjlb; namespace NCC.Extend.Interfaces.LqTkjlb { @@ -15,5 +16,12 @@ namespace NCC.Extend.Interfaces.LqTkjlb /// /// Task GetTeamDetail(); + + /// + /// 获取拓客统计数据 + /// + /// 查询参数 + /// 拓客统计数据 + Task GetTkStatistics(TkStatisticsInput input); } } \ No newline at end of file diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqDailyReport/ILqDailyReportService.cs b/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqDailyReport/ILqDailyReportService.cs new file mode 100644 index 0000000..2ef49a6 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqDailyReport/ILqDailyReportService.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using NCC.Extend.Entitys.Dto.LqDailyReport; + +namespace NCC.Extend.Interfaces.LqDailyReport +{ + /// + /// 日报服务接口 + /// + public interface ILqDailyReportService + { + /// + /// 获取门店每日运营统计数据 + /// + /// 查询参数 + /// 门店统计数据列表 + Task> GetStoreDailyStatistics(StoreDailyStatisticsInput input); + + /// + /// 获取门店业绩完成情况 + /// + /// 查询参数 + /// 门店业绩完成情况列表 + Task> GetStorePerformanceCompletion(StorePerformanceCompletionInput input); + + /// + /// 获取事业部业绩完成情况 + /// + /// 查询参数 + /// 事业部业绩完成情况列表 + Task> GetBusinessUnitPerformanceCompletion(BusinessUnitPerformanceCompletionInput input); + + /// + /// 获取天王团业绩完成情况 + /// + /// 查询参数 + /// 天王团业绩完成情况列表 + Task> GetTianwangGroupPerformanceCompletion(TianwangGroupPerformanceCompletionInput input); + + /// + /// 获取经理业绩完成情况 + /// + /// 查询参数 + /// 经理业绩完成情况列表 + Task> GetManagerPerformanceCompletion(ManagerPerformanceCompletionInput input); + + /// + /// 获取经理汇总业绩完成情况 + /// + /// 查询参数 + /// 经理汇总业绩完成情况列表 + Task> GetManagerSummaryPerformanceCompletion(ManagerPerformanceCompletionInput input); + + /// + /// 获取科技部老师日报统计 + /// + /// 查询参数 + /// 科技部老师统计列表 + Task> GetTechTeacherDailyStatistics(TechTeacherDailyStatisticsInput input); + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs new file mode 100644 index 0000000..3f1b0a9 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs @@ -0,0 +1,921 @@ +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.FriendlyException; +using NCC.Extend.Interfaces.LqDailyReport; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using NCC.Common.Helper; +using NCC.JsonSerialization; +using NCC.Common.Model.NPOI; +using NCC.Common.Configuration; +using NCC.DataEncryption; +using NCC.ClayObject; +using NCC.Extend.Entitys.Dto.LqDailyReport; +using NCC.Extend.Entitys.lq_kd_kdjlb; + +namespace NCC.Extend +{ + /// + /// 日报服务 + /// + [ApiDescriptionSettings(Tag = "绿纤日报服务", Name = "LqDailyReport", Order = 200)] + [Route("api/Extend/[controller]")] + public class LqDailyReportService : ILqDailyReportService, IDynamicApiController, ITransient + { + private readonly ISqlSugarRepository _repository; + private readonly SqlSugarScope _db; + private readonly IUserManager _userManager; + + /// + /// 初始化一个类型的新实例 + /// + public LqDailyReportService( + ISqlSugarRepository repository, + IUserManager userManager) + { + _repository = repository; + _db = _repository.Context; + _userManager = userManager; + } + + /// + /// 获取时间范围,如果未传入则默认为本月 + /// + private (DateTime startDate, DateTime endDate) GetTimeRange(DateTime? startTime, DateTime? endTime) + { + var now = DateTime.Now; + var start = startTime ?? new DateTime(now.Year, now.Month, 1); + var end = endTime ?? now; + + // 确保开始时间不晚于结束时间 + if (start > end) + { + var temp = start; + start = end; + end = temp; + } + + return (start, end); + } + + #region 获取门店每日运营统计数据 + /// + /// 获取门店每日运营统计数据 + /// + /// + /// 根据指定时间范围统计各门店的运营数据,包括在职员工数、人头数、人次、项目数、消耗业绩等信息 + /// + /// 示例请求: + /// ```json + /// { + /// "startTime": "2025-10-01", + /// "endTime": "2025-10-27", + /// "storeIds": ["门店ID1", "门店ID2"] + /// } + /// ``` + /// + /// 参数说明: + /// - startTime: 开始时间,可选,不传则默认为当月1号 + /// - endTime: 结束时间,可选,不传则默认为今天 + /// - storeIds: 门店ID列表,可选,不传则查询所有门店 + /// + /// 返回说明: + /// - StoreId: 门店ID + /// - StoreName: 门店名称 + /// - EmployeeCount: 在职员工数(F_EnabledMark=1且有岗位) + /// - HeadCount: 人头数(去重后的消费会员数) + /// - PersonCount: 人次(日度去重客户数,同一天同一客户只算一次) + /// - ProjectCount: 项目数(消耗的项目总数) + /// - ConsumePerformance: 消耗业绩(总金额) + /// + /// 查询参数 + /// 门店统计数据列表 + /// 成功返回门店统计列表 + /// 日期格式错误或参数无效 + /// 服务器内部错误 + [HttpPost("get-store-daily-statistics")] + public async Task> GetStoreDailyStatistics(StoreDailyStatisticsInput input) + { + // 获取时间范围 + var (startDate, endDate) = GetTimeRange(input.StartTime, input.EndTime); + + // 构建门店过滤条件 + var storeFilter = ""; + if (input.StoreIds != null && input.StoreIds.Any()) + { + var storeIdsStr = string.Join("','", input.StoreIds); + storeFilter = $"AND consume.Md IN ('{storeIdsStr}')"; + } + + // SQL查询:获取门店每日运营数据 + var sql = $@" + SELECT + consume.Md as StoreId, + MAX(store.dm) as StoreName, + -- 在职员工数 + COALESCE(( + SELECT COUNT(DISTINCT u.F_Id) + FROM BASE_USER u + WHERE u.F_MDID = consume.Md + AND u.F_EnabledMark = 1 + AND (u.F_DeleteMark IS NULL OR u.F_DeleteMark = 0) + AND u.F_GW IS NOT NULL + ), 0) as EmployeeCount, + -- 人头数(去重后的消费会员数) + COALESCE(COUNT(DISTINCT consume.Hy), 0) as HeadCount, + -- 人次(日度去重客户数) + COALESCE(COUNT(DISTINCT CONCAT(consume.Hy, '-', DATE(consume.Hksj))), 0) as PersonCount, + -- 项目数(消耗的项目总数) + COALESCE(SUM(project.F_ProjectNumber), 0) as ProjectCount, + -- 消耗业绩(总金额) + COALESCE(SUM(project.F_TotalPrice), 0) as ConsumePerformance + FROM lq_xh_hyhk consume + LEFT JOIN lq_mdxx store ON consume.Md = store.F_Id + LEFT JOIN lq_xh_pxmx project ON consume.F_Id = project.F_ConsumeInfoId AND project.F_IsEffective = 1 + WHERE consume.F_IsEffective = 1 + AND DATE(consume.Hksj) >= '{startDate:yyyy-MM-dd}' + AND DATE(consume.Hksj) <= '{endDate:yyyy-MM-dd}' + {storeFilter} + GROUP BY consume.Md + ORDER BY ConsumePerformance DESC"; + + var result = await _db.Ado.SqlQueryAsync(sql); + + var outputList = result.Select(item => new StoreDailyStatisticsOutput + { + StoreId = item.StoreId, + StoreName = item.StoreName, + EmployeeCount = Convert.ToInt32(item.EmployeeCount), + HeadCount = Convert.ToInt32(item.HeadCount), + PersonCount = Convert.ToInt32(item.PersonCount), + ProjectCount = Convert.ToInt32(item.ProjectCount), + ConsumePerformance = Convert.ToDecimal(item.ConsumePerformance) + }).ToList(); + return outputList; + } + #endregion + + #region 获取门店业绩完成情况 + /// + /// 获取门店业绩完成情况 + /// + /// + /// 根据指定日期统计各门店的业绩完成情况,包括目标业绩、完成业绩、完成率 + /// + /// 示例请求: + /// ```json + /// { + /// "startTime": "2025-10-01", + /// "endTime": "2025-10-22", + /// "storeIds": ["门店ID1", "门店ID2"] + /// } + /// ``` + /// + /// 参数说明: + /// - startTime: 开始时间,可选,不传则默认为当月1号 + /// - endTime: 结束时间,可选,不传则默认为今天 + /// - storeIds: 门店ID列表,可选,不传则查询所有门店 + /// + /// 返回说明: + /// - StoreId: 门店ID + /// - StoreName: 门店名称 + /// - TargetPerformance: 目标业绩(生命线,来自门店信息表) + /// - CompletedPerformance: 完成业绩(当月1号至统计日期的开单业绩总和) + /// - CompletionRate: 完成率(百分比,CompletedPerformance / TargetPerformance * 100) + /// + /// 查询参数 + /// 门店业绩完成情况列表 + /// 成功返回门店业绩完成情况列表 + /// 日期格式错误或参数无效 + /// 服务器内部错误 + [HttpPost("get-store-performance-completion")] + public async Task> GetStorePerformanceCompletion(StorePerformanceCompletionInput input) + { + // 获取时间范围 + var (startDate, endDate) = GetTimeRange(input.StartTime, input.EndTime); + + // 构建门店过滤条件 + var storeFilter = ""; + if (input.StoreIds != null && input.StoreIds.Any()) + { + var storeIdsStr = string.Join("','", input.StoreIds); + storeFilter = $"AND store.F_Id IN ('{storeIdsStr}')"; + } + + // SQL查询:获取门店业绩完成情况 + var sql = $@" + SELECT + store.F_Id as StoreId, + store.dm as StoreName, + -- 目标业绩(生命线) + COALESCE(store.xsyj, 0) as TargetPerformance, + -- 完成业绩(开单业绩总和) + COALESCE(( + SELECT SUM(billing.sfyj) + FROM lq_kd_kdjlb billing + WHERE billing.djmd = store.F_Id + AND billing.F_IsEffective = 1 + AND DATE(billing.kdrq) >= '{startDate:yyyy-MM-dd}' + AND DATE(billing.kdrq) <= '{endDate:yyyy-MM-dd}' + ), 0) as CompletedPerformance + FROM lq_mdxx store + WHERE 1=1 {storeFilter} + ORDER BY CompletedPerformance DESC"; + + var result = await _db.Ado.SqlQueryAsync(sql); + + var outputList = result.Select(item => + { + var targetPerformance = Convert.ToDecimal(item.TargetPerformance); + var completedPerformance = Convert.ToDecimal(item.CompletedPerformance); + var completionRate = targetPerformance > 0 ? (completedPerformance / targetPerformance * 100m) : 0m; + + return new StorePerformanceCompletionOutput + { + StoreId = item.StoreId, + StoreName = item.StoreName, + TargetPerformance = targetPerformance, + CompletedPerformance = completedPerformance, + CompletionRate = decimal.Round(completionRate, 2) + }; + }).ToList(); + + return outputList; + } + #endregion + + #region 获取事业部业绩完成情况 + /// + /// 获取事业部业绩完成情况 + /// + /// + /// 根据指定日期统计各事业部的业绩完成情况,包括目标业绩、完成业绩、完成率 + /// + /// 示例请求: + /// ```json + /// { + /// "startTime": "2025-10-01", + /// "endTime": "2025-10-22", + /// "businessUnitIds": ["事业部ID1", "事业部ID2"] + /// } + /// ``` + /// + /// 参数说明: + /// - startTime: 开始时间,可选,不传则默认为当月1号 + /// - endTime: 结束时间,可选,不传则默认为今天 + /// - businessUnitIds: 事业部ID列表,可选,不传则查询所有事业部 + /// + /// 返回说明: + /// - BusinessUnitId: 事业部ID + /// - BusinessUnitName: 事业部名称 + /// - TargetPerformance: 目标业绩(管理门店的生命线总和) + /// - CompletedPerformance: 完成业绩(指定时间范围内的开单业绩总和) + /// - CompletionRate: 完成率(百分比,CompletedPerformance / TargetPerformance * 100) + /// - StoreCount: 门店数量 + /// + /// 查询参数 + /// 事业部业绩完成情况列表 + /// 成功返回事业部业绩完成情况列表 + /// 日期格式错误或参数无效 + /// 服务器内部错误 + [HttpPost("get-business-unit-performance-completion")] + public async Task> GetBusinessUnitPerformanceCompletion(BusinessUnitPerformanceCompletionInput input) + { + // 获取时间范围 + var (startDate, endDate) = GetTimeRange(input.StartTime, input.EndTime); + + // 构建事业部过滤条件 + var businessUnitFilter = ""; + if (input.BusinessUnitIds != null && input.BusinessUnitIds.Any()) + { + var filterUnitIdsStr = string.Join("','", input.BusinessUnitIds); + businessUnitFilter = $"AND o.F_Id IN ('{filterUnitIdsStr}')"; + } + + // 分步查询,提高效率 + // 第一步:获取事业部列表及目标业绩(只统计事业一部到事业六部) + var businessUnitSql = $@" + SELECT + o.F_Id as BusinessUnitId, + o.F_FullName as BusinessUnitName, + COALESCE(SUM(store.xsyj), 0) as TargetPerformance, + COUNT(DISTINCT store.F_Id) as StoreCount + FROM base_organize o + LEFT JOIN lq_mdxx store ON store.syb = o.F_Id + WHERE o.F_Category = 'department' + AND (o.F_DeleteMark IS NULL OR o.F_DeleteMark != 1) + AND o.F_FullName IN ('事业一部', '事业二部', '事业三部', '事业四部', '事业五部', '事业六部') + {businessUnitFilter} + GROUP BY o.F_Id, o.F_FullName"; + + var businessUnits = await _db.Ado.SqlQueryAsync(businessUnitSql); + + if (businessUnits == null || !businessUnits.Any()) + { + return new List(); + } + + var businessUnitDict = new Dictionary(); + + foreach (var unit in businessUnits) + { + businessUnitDict[unit.BusinessUnitId.ToString()] = new BusinessUnitPerformanceCompletionOutput + { + BusinessUnitId = unit.BusinessUnitId.ToString(), + BusinessUnitName = unit.BusinessUnitName.ToString(), + TargetPerformance = Convert.ToDecimal(unit.TargetPerformance), + CompletedPerformance = 0, + CompletionRate = 0, + StoreCount = Convert.ToInt32(unit.StoreCount) + }; + } + + // 第二步:统计各事业部的完成业绩 + var businessUnitIds = businessUnitDict.Keys.ToList(); + var unitIdsStr = string.Join("','", businessUnitIds); + + var completedPerformanceSql = $@" + SELECT + store.syb as BusinessUnitId, + COALESCE(SUM(billing.sfyj), 0) as CompletedPerformance + FROM lq_kd_kdjlb billing + INNER JOIN lq_mdxx store ON billing.djmd = store.F_Id + INNER JOIN base_organize o ON store.syb = o.F_Id + WHERE billing.F_IsEffective = 1 + AND o.F_Category = 'department' + AND (o.F_DeleteMark IS NULL OR o.F_DeleteMark != 1) + AND o.F_FullName IN ('事业一部', '事业二部', '事业三部', '事业四部', '事业五部', '事业六部') + AND DATE(billing.kdrq) >= '{startDate:yyyy-MM-dd}' + AND DATE(billing.kdrq) <= '{endDate:yyyy-MM-dd}' + AND store.syb IN ('{unitIdsStr}') + GROUP BY store.syb"; + + var completedPerformanceData = await _db.Ado.SqlQueryAsync(completedPerformanceSql); + + // 第三步:合并数据并计算完成率 + foreach (var item in completedPerformanceData) + { + var businessUnitId = item.BusinessUnitId.ToString(); + if (businessUnitDict.ContainsKey(businessUnitId)) + { + var completedPerformance = Convert.ToDecimal(item.CompletedPerformance); + var unit = businessUnitDict[businessUnitId]; + unit.CompletedPerformance = completedPerformance; + + var completionRate = unit.TargetPerformance > 0 + ? (completedPerformance / unit.TargetPerformance * 100m) + : 0m; + unit.CompletionRate = decimal.Round(completionRate, 2); + } + } + + var outputList = businessUnitDict.Values + .OrderByDescending(x => x.CompletedPerformance) + .ToList(); + + return outputList; + } + #endregion + + #region 获取天王团业绩完成情况 + /// + /// 获取天王团业绩完成情况 + /// + /// + /// 根据指定日期统计各天王团的业绩完成情况,包括目标业绩、完成业绩、完成率 + /// + /// 示例请求: + /// ```json + /// { + /// "startTime": "2025-10-01", + /// "endTime": "2025-10-22", + /// "departmentIds": ["部门ID1", "部门ID2"] + /// } + /// ``` + /// + /// 参数说明: + /// - startTime: 开始时间,可选,不传则默认为当月1号 + /// - endTime: 结束时间,可选,不传则默认为今天 + /// - departmentIds: 天王团部门ID列表,可选,不传则查询所有天王团 + /// + /// 返回说明: + /// - DepartmentId: 部门ID + /// - DepartmentName: 部门名称(教育一部、教育二部、科技一部、科技二部、大项目一部、大项目二部) + /// - TargetPerformance: 目标业绩(管理门店的生命线总和) + /// - CompletedPerformance: 完成业绩(指定时间范围内的开单业绩总和) + /// - CompletionRate: 完成率(百分比,CompletedPerformance / TargetPerformance * 100) + /// - StoreCount: 门店数量 + /// + /// 查询参数 + /// 天王团业绩完成情况列表 + /// 成功返回天王团业绩完成情况列表 + /// 日期格式错误或参数无效 + /// 服务器内部错误 + [HttpPost("get-tianwang-group-performance-completion")] + public async Task> GetTianwangGroupPerformanceCompletion(TianwangGroupPerformanceCompletionInput input) + { + // 获取时间范围 + var (startDate, endDate) = GetTimeRange(input.StartTime, input.EndTime); + + // 构建部门过滤条件 + var departmentFilter = ""; + if (input.DepartmentIds != null && input.DepartmentIds.Any()) + { + var filterDeptIdsStr = string.Join("','", input.DepartmentIds); + departmentFilter = $"AND o.F_Id IN ('{filterDeptIdsStr}')"; + } + + // 天王团部门信息(字段名和部门名称的映射) + var tianwangDepartments = new Dictionary + { + { "jyb", ("jyb", new[] { "教育一部", "教育二部" }) }, + { "kjb", ("kjb", new[] { "科技一部", "科技二部" }) }, + { "dxmb", ("dxmb", new[] { "大项目一部", "大项目二部" }) } + }; + + // 分步查询,提高效率 + var departmentDict = new Dictionary(); + var allDeptNames = new List(); + + // 循环查询每个天王团类型 + foreach (var deptType in tianwangDepartments) + { + var deptNamesStr = string.Join("','", deptType.Value.departmentNames); + allDeptNames.AddRange(deptType.Value.departmentNames); + + // 第一步:获取天王团列表及目标业绩 + var departmentSql = $@" + SELECT + o.F_Id as DepartmentId, + o.F_FullName as DepartmentName, + COALESCE(SUM(store.xsyj), 0) as TargetPerformance, + COUNT(DISTINCT store.F_Id) as StoreCount + FROM base_organize o + LEFT JOIN lq_mdxx store ON store.{deptType.Key} = o.F_Id + WHERE o.F_Category = 'department' + AND (o.F_DeleteMark IS NULL OR o.F_DeleteMark != 1) + AND o.F_FullName IN ('{deptNamesStr}') + {departmentFilter} + GROUP BY o.F_Id, o.F_FullName"; + + var departments = await _db.Ado.SqlQueryAsync(departmentSql); + + foreach (var dept in departments ?? Enumerable.Empty()) + { + if (!departmentDict.ContainsKey(dept.DepartmentId.ToString())) + { + departmentDict[dept.DepartmentId.ToString()] = new TianwangGroupPerformanceCompletionOutput + { + DepartmentId = dept.DepartmentId.ToString(), + DepartmentName = dept.DepartmentName.ToString(), + TargetPerformance = Convert.ToDecimal(dept.TargetPerformance), + CompletedPerformance = 0, + CompletionRate = 0, + StoreCount = Convert.ToInt32(dept.StoreCount) + }; + } + } + } + + if (!departmentDict.Any()) + { + return new List(); + } + + // 第二步:统计各天王团的完成业绩(分类型统计) + var completedPerformanceDataList = new List(); + + foreach (var deptType in tianwangDepartments) + { + var deptIdsStrForQuery = string.Join("','", departmentDict.Keys); + + var completedPerformanceSql = $@" + SELECT + o.F_Id as DepartmentId, + COALESCE(SUM(billing.sfyj), 0) as CompletedPerformance + FROM lq_kd_kdjlb billing + INNER JOIN lq_mdxx store ON billing.djmd = store.F_Id + INNER JOIN base_organize o ON store.{deptType.Key} = o.F_Id + WHERE billing.F_IsEffective = 1 + AND o.F_Category = 'department' + AND (o.F_DeleteMark IS NULL OR o.F_DeleteMark != 1) + AND DATE(billing.kdrq) >= '{startDate:yyyy-MM-dd}' + AND DATE(billing.kdrq) <= '{endDate:yyyy-MM-dd}' + AND o.F_Id IN ('{deptIdsStrForQuery}') + GROUP BY o.F_Id"; + + var completedPerformanceData = await _db.Ado.SqlQueryAsync(completedPerformanceSql); + if (completedPerformanceData != null) + { + completedPerformanceDataList.AddRange(completedPerformanceData); + } + } + + // 第三步:合并数据并计算完成率(按部门ID去重累加) + var departmentPerformanceDict = new Dictionary(); + foreach (var item in completedPerformanceDataList) + { + var departmentId = item.DepartmentId.ToString(); + var completedPerformance = Convert.ToDecimal(item.CompletedPerformance); + + if (departmentPerformanceDict.ContainsKey(departmentId)) + { + departmentPerformanceDict[departmentId] += completedPerformance; + } + else + { + departmentPerformanceDict[departmentId] = completedPerformance; + } + } + + // 计算完成率 + foreach (var kvp in departmentPerformanceDict) + { + if (departmentDict.ContainsKey(kvp.Key)) + { + var dept = departmentDict[kvp.Key]; + dept.CompletedPerformance = kvp.Value; + + var completionRate = dept.TargetPerformance > 0 + ? (kvp.Value / dept.TargetPerformance * 100m) + : 0m; + dept.CompletionRate = decimal.Round(completionRate, 2); + } + } + + var outputList = departmentDict.Values + .OrderByDescending(x => x.CompletedPerformance) + .ToList(); + + return outputList; + } + #endregion + + #region 获取经理业绩完成情况 + /// + /// 获取经理业绩完成情况 + /// + /// + /// 根据指定日期统计各经理在各门店的业绩完成情况,包括目标业绩(三个阶段)、完成业绩、完成率 + /// + /// 示例请求: + /// ```json + /// { + /// "startTime": "2025-10-01", + /// "endTime": "2025-10-22", + /// "managerId": "经理ID" + /// } + /// ``` + /// + /// 参数说明: + /// - startTime: 开始时间,可选,不传则默认为当月1号 + /// - endTime: 结束时间,可选,不传则默认为今天 + /// - managerId: 经理用户ID,可选,不传则查询所有经理 + /// + /// 返回说明: + /// - ManagerId: 经理用户ID + /// - ManagerName: 经理姓名 + /// - StoreId/StoreName: 门店信息 + /// - Target1/2/3: 目标业绩一/二/三阶段(smx1/smx2/smx3) + /// - CompletedPerformance: 完成业绩(指定时间范围内的开单业绩总和) + /// - CompletionRate1/2/3: 完成率各阶段(百分比) + /// + /// 查询参数 + /// 经理业绩完成情况列表 + /// 成功返回经理业绩完成情况列表 + /// 日期格式错误或参数无效 + /// 服务器内部错误 + [HttpPost("get-manager-performance-completion")] + public async Task> GetManagerPerformanceCompletion(ManagerPerformanceCompletionInput input) + { + // 获取时间范围 + var (startDate, endDate) = GetTimeRange(input.StartTime, input.EndTime); + + // 构建经理过滤条件 + var managerFilter = ""; + if (!string.IsNullOrWhiteSpace(input.ManagerId)) + { + managerFilter = $"AND target.zjl_userid = '{input.ManagerId}'"; + } + + // SQL查询:获取经理在各门店的目标业绩和完成业绩 + var sql = $@" + SELECT + target.zjl_userid as ManagerId, + u.F_RealName as ManagerName, + target.md_id as StoreId, + store.dm as StoreName, + target.smx1 as Target1, + target.smx2 as Target2, + target.smx3 as Target3, + -- 完成业绩 + COALESCE(( + SELECT SUM(billing.sfyj) + FROM lq_kd_kdjlb billing + WHERE billing.djmd = target.md_id + AND billing.F_IsEffective = 1 + AND DATE(billing.kdrq) >= '{startDate:yyyy-MM-dd}' + AND DATE(billing.kdrq) <= '{endDate:yyyy-MM-dd}' + ), 0) as CompletedPerformance + FROM lq_zjl_mdsmxsz target + INNER JOIN BASE_USER u ON target.zjl_userid = u.F_Id + INNER JOIN lq_mdxx store ON target.md_id = store.F_Id + WHERE target.deletemark = 0 + {managerFilter} + ORDER BY target.zjl_userid, store.dm"; + + var result = await _db.Ado.SqlQueryAsync(sql); + + var outputList = result.Select(item => + { + var target1 = Convert.ToDecimal(item.Target1); + var target2 = item.Target2 != null ? Convert.ToDecimal(item.Target2) : 0; + var target3 = item.Target3 != null ? Convert.ToDecimal(item.Target3) : 0; + var completed = Convert.ToDecimal(item.CompletedPerformance); + + var rate1 = target1 > 0 ? (completed / target1 * 100m) : 0m; + var rate2 = target2 > 0 ? (completed / target2 * 100m) : 0m; + var rate3 = target3 > 0 ? (completed / target3 * 100m) : 0m; + + return new ManagerPerformanceCompletionOutput + { + ManagerId = item.ManagerId.ToString(), + ManagerName = item.ManagerName.ToString(), + StoreId = item.StoreId.ToString(), + StoreName = item.StoreName.ToString(), + Target1 = target1, + Target2 = target2 > 0 ? target2 : (decimal?)null, + Target3 = target3 > 0 ? target3 : (decimal?)null, + CompletedPerformance = completed, + CompletionRate1 = decimal.Round(rate1, 2), + CompletionRate2 = target2 > 0 ? decimal.Round(rate2, 2) : (decimal?)null, + CompletionRate3 = target3 > 0 ? decimal.Round(rate3, 2) : (decimal?)null + }; + }).ToList(); + + return outputList; + } + + /// + /// 获取经理汇总业绩完成情况 + /// + /// + /// 根据指定日期统计各经理的总业绩完成情况,汇总所有管理门店的数据 + /// + /// 示例请求: + /// ```json + /// { + /// "startTime": "2025-10-01", + /// "endTime": "2025-10-22", + /// "managerId": "经理ID" + /// } + /// ``` + /// + /// 参数说明: + /// - startTime: 开始时间,可选,不传则默认为当月1号 + /// - endTime: 结束时间,可选,不传则默认为今天 + /// - managerId: 经理用户ID,可选,不传则查询所有经理 + /// + /// 返回说明: + /// - ManagerId: 经理用户ID + /// - ManagerName: 经理姓名 + /// - TotalTarget1/2/3: 总目标业绩一/二/三阶段 + /// - TotalCompletedPerformance: 总完成业绩(指定时间范围内的开单业绩总和) + /// - TotalCompletionRate1/2/3: 总完成率各阶段 + /// - StoreCount: 管理门店数量 + /// + /// 查询参数 + /// 经理汇总业绩完成情况列表 + /// 成功返回经理汇总业绩完成情况列表 + /// 日期格式错误或参数无效 + /// 服务器内部错误 + [HttpPost("get-manager-summary-performance-completion")] + public async Task> GetManagerSummaryPerformanceCompletion(ManagerPerformanceCompletionInput input) + { + // 获取时间范围 + var (startDate, endDate) = GetTimeRange(input.StartTime, input.EndTime); + + // 构建经理过滤条件 + var managerFilter = ""; + if (!string.IsNullOrWhiteSpace(input.ManagerId)) + { + managerFilter = $"AND target.zjl_userid = '{input.ManagerId}'"; + } + + // SQL查询:获取经理汇总业绩 + var sql = $@" + SELECT + target.zjl_userid as ManagerId, + u.F_RealName as ManagerName, + SUM(target.smx1) as TotalTarget1, + COALESCE(SUM(target.smx2), 0) as TotalTarget2, + COALESCE(SUM(target.smx3), 0) as TotalTarget3, + COUNT(DISTINCT target.md_id) as StoreCount, + -- 总完成业绩 + SUM(COALESCE(( + SELECT SUM(billing.sfyj) + FROM lq_kd_kdjlb billing + WHERE billing.djmd = target.md_id + AND billing.F_IsEffective = 1 + AND DATE(billing.kdrq) >= '{startDate:yyyy-MM-dd}' + AND DATE(billing.kdrq) <= '{endDate:yyyy-MM-dd}' + ), 0)) as TotalCompletedPerformance + FROM lq_zjl_mdsmxsz target + INNER JOIN BASE_USER u ON target.zjl_userid = u.F_Id + INNER JOIN lq_mdxx store ON target.md_id = store.F_Id + WHERE target.deletemark = 0 + {managerFilter} + GROUP BY target.zjl_userid, u.F_RealName + ORDER BY TotalCompletedPerformance DESC"; + + var result = await _db.Ado.SqlQueryAsync(sql); + + var outputList = result.Select(item => + { + var totalTarget1 = Convert.ToDecimal(item.TotalTarget1); + var totalTarget2 = Convert.ToDecimal(item.TotalTarget2); + var totalTarget3 = Convert.ToDecimal(item.TotalTarget3); + var totalCompleted = Convert.ToDecimal(item.TotalCompletedPerformance); + + var rate1 = totalTarget1 > 0 ? (totalCompleted / totalTarget1 * 100m) : 0m; + var rate2 = totalTarget2 > 0 ? (totalCompleted / totalTarget2 * 100m) : 0m; + var rate3 = totalTarget3 > 0 ? (totalCompleted / totalTarget3 * 100m) : 0m; + + return new ManagerSummaryPerformanceCompletionOutput + { + ManagerId = item.ManagerId.ToString(), + ManagerName = item.ManagerName.ToString(), + TotalTarget1 = totalTarget1, + TotalTarget2 = totalTarget2, + TotalTarget3 = totalTarget3, + TotalCompletedPerformance = totalCompleted, + TotalCompletionRate1 = decimal.Round(rate1, 2), + TotalCompletionRate2 = decimal.Round(rate2, 2), + TotalCompletionRate3 = decimal.Round(rate3, 2), + StoreCount = Convert.ToInt32(item.StoreCount) + }; + }).ToList(); + + return outputList; + } + #endregion + + #region 获取科技部老师统计 + /// + /// 获取科技部老师统计 + /// + /// + /// 根据指定日期统计科技部老师的业绩情况,包括见客数、消耗项目数、消耗业绩、开单业绩 + /// + /// 示例请求: + /// ```json + /// { + /// "startTime": "2025-10-01", + /// "endTime": "2025-10-22", + /// "techDepartmentId": "科技部ID", + /// "teacherIds": ["老师ID1", "老师ID2"] + /// } + /// ``` + /// + /// 参数说明: + /// - startTime: 开始时间,可选,不传则默认为当月1号 + /// - endTime: 结束时间,可选,不传则默认为今天 + /// - techDepartmentId: 科技部ID,可选,不传则查询所有科技部 + /// - teacherIds: 老师ID列表,可选 + /// + /// 返回说明: + /// - TechDepartmentId: 科技部ID + /// - TechDepartmentName: 科技部名称 + /// - TeacherId: 老师ID + /// - TeacherName: 老师姓名 + /// - CustomerCount: 见客数(不同客户数量) + /// - ConsumeProjectCount: 消耗项目数 + /// - ConsumeAchievement: 消耗业绩 + /// - OrderAchievement: 开单业绩 + /// + /// 查询参数 + /// 科技部老师统计列表 + /// 成功返回科技部老师统计列表 + /// 日期格式错误或参数无效 + /// 服务器内部错误 + [HttpPost("get-tech-teacher-daily-statistics")] + public async Task> GetTechTeacherDailyStatistics(TechTeacherDailyStatisticsInput input) + { + // 获取时间范围 + var (startDate, endDate) = GetTimeRange(input.StartTime, input.EndTime); + + // 构建过滤条件 + var techFilter = ""; + if (!string.IsNullOrWhiteSpace(input.TechDepartmentId)) + { + techFilter = $"AND techDept.F_Id = '{input.TechDepartmentId}'"; + } + + var teacherFilter = ""; + if (input.TeacherIds != null && input.TeacherIds.Any()) + { + var teacherIdsStr = string.Join("','", input.TeacherIds); + teacherFilter = $"AND consume.kjbls IN ('{teacherIdsStr}')"; + } + + var teacherFilterForOrder = ""; + if (input.TeacherIds != null && input.TeacherIds.Any()) + { + var teacherIdsStr = string.Join("','", input.TeacherIds); + teacherFilterForOrder = $"AND ord.kjbls IN ('{teacherIdsStr}')"; + } + + // SQL查询:统计科技部老师的消耗业绩、见客数、项目数 + var consumeSql = $@" + SELECT + techDept.F_Id as TechDepartmentId, + techDept.F_FullName as TechDepartmentName, + consume.kjbls as TeacherId, + consume.kjblsxm as TeacherName, + COUNT(DISTINCT hyhk.hy) as CustomerCount, + SUM(consume.F_hdpxNumber) as ConsumeProjectCount, + SUM(consume.kjblsyj) as ConsumeAchievement + FROM lq_xh_kjbsyj consume + INNER JOIN lq_xh_hyhk hyhk ON consume.glkdbh = hyhk.F_Id + INNER JOIN lq_mdxx store ON hyhk.md = store.F_Id + LEFT JOIN base_organize techDept ON store.kjb = techDept.F_Id + WHERE consume.F_IsEffective = 1 + AND hyhk.F_IsEffective = 1 + AND DATE(hyhk.hksj) >= '{startDate:yyyy-MM-dd}' + AND DATE(hyhk.hksj) <= '{endDate:yyyy-MM-dd}' + {techFilter} + {teacherFilter} + GROUP BY techDept.F_Id, techDept.F_FullName, consume.kjbls, consume.kjblsxm"; + + var consumeResult = await _db.Ado.SqlQueryAsync(consumeSql); + + // 查询开单业绩 + var orderSql = $@" + SELECT + techDept.F_Id as TechDepartmentId, + ord.kjbls as TeacherId, + SUM(ord.kjblsyj) as OrderAchievement + FROM lq_kd_kjbsyj ord + INNER JOIN lq_kd_kdjlb kdjlb ON ord.glkdbh = kdjlb.F_Id + INNER JOIN lq_mdxx store ON kdjlb.djmd = store.F_Id + LEFT JOIN base_organize techDept ON store.kjb = techDept.F_Id + WHERE ord.F_IsEffective = 1 + AND kdjlb.F_IsEffective = 1 + AND DATE(kdjlb.kdrq) >= '{startDate:yyyy-MM-dd}' + AND DATE(kdjlb.kdrq) <= '{endDate:yyyy-MM-dd}' + {techFilter} + {teacherFilterForOrder} + GROUP BY techDept.F_Id, ord.kjbls"; + + var orderResult = await _db.Ado.SqlQueryAsync(orderSql); + + // 合并数据 + var teacherDict = new Dictionary(); + + foreach (var item in consumeResult ?? Enumerable.Empty()) + { + var key = $"{item.TechDepartmentId}_{item.TeacherId}"; + teacherDict[key] = new TechTeacherDailyStatisticsOutput + { + TechDepartmentId = item.TechDepartmentId?.ToString(), + TechDepartmentName = item.TechDepartmentName?.ToString(), + TeacherId = item.TeacherId?.ToString(), + TeacherName = item.TeacherName?.ToString(), + CustomerCount = Convert.ToInt32(item.CustomerCount), + ConsumeProjectCount = Convert.ToInt32(item.ConsumeProjectCount), + ConsumeAchievement = Convert.ToDecimal(item.ConsumeAchievement), + OrderAchievement = 0 + }; + } + + // 合并开单业绩 + foreach (var item in orderResult ?? Enumerable.Empty()) + { + var key = $"{item.TechDepartmentId}_{item.TeacherId}"; + if (teacherDict.ContainsKey(key)) + { + teacherDict[key].OrderAchievement = Convert.ToDecimal(item.OrderAchievement); + } + } + + var outputList = teacherDict.Values + .OrderBy(x => x.TechDepartmentName) + .ThenBy(x => x.TeacherName) + .ToList(); + + return outputList; + } + #endregion + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqEventService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqEventService.cs index 333e74d..eab0601 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqEventService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqEventService.cs @@ -800,6 +800,8 @@ namespace NCC.Extend.LqEvent } #endregion + + #region 根据活动ID获取人员统计数据 /// diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqPackageInfoService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqPackageInfoService.cs index 2b4aff6..4ad743a 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqPackageInfoService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqPackageInfoService.cs @@ -557,8 +557,8 @@ namespace NCC.Extend.LqPackageInfo /// 获取营销活动统计数据 /// /// - /// 统计指定营销活动的开单、退卡相关数据 - /// 包括:开单数量、开单金额、退卡数量、退卡金额、净开单数量、净开单金额、退卡率 + /// 统计指定营销活动的开单数据,支持分页 + /// 包括:总记录数、开单总金额、欠款总金额、开单列表 /// /// 示例请求: /// ```json @@ -566,7 +566,9 @@ namespace NCC.Extend.LqPackageInfo /// "activityId": "营销活动ID", /// "startTime": "2025-10-01", /// "endTime": "2025-10-31", - /// "storeIds": ["门店ID1", "门店ID2"] + /// "storeIds": ["门店ID1", "门店ID2"], + /// "pageIndex": 1, + /// "pageSize": 20 /// } /// ``` /// @@ -575,17 +577,16 @@ namespace NCC.Extend.LqPackageInfo /// - startTime: 开始时间(可选,默认为活动开始时间) /// - endTime: 结束时间(可选,默认为活动结束时间) /// - storeIds: 门店ID列表(可选) + /// - pageIndex: 页码(默认1) + /// - pageSize: 每页数量(默认20) /// /// 返回字段说明: /// - ActivityId: 营销活动ID /// - ActivityName: 营销活动名称 /// - BillingCount: 开单数量 - /// - BillingAmount: 开单金额 - /// - RefundCount: 退卡数量 - /// - RefundAmount: 退卡金额 - /// - NetBillingCount: 净开单数量(开单数量 - 退卡数量) - /// - NetBillingAmount: 净开单金额(开单金额 - 退卡金额) - /// - RefundRate: 退卡率(退卡数量 / 开单数量) + /// - BillingAmount: 开单总金额 + /// - DebtAmount: 欠款总金额 + /// - BillingList: 开单列表(包含开单ID、日期、客户信息、门店信息、金额、欠款等) /// /// 查询参数 /// 营销活动统计数据 @@ -611,95 +612,78 @@ namespace NCC.Extend.LqPackageInfo var startTime = input.StartTime ?? activity.StartTime; var endTime = input.EndTime ?? activity.EndTime; - // 3. 获取营销活动关联的品项ID列表 - var itemIds = await _db.Queryable() - .Where(x => x.ActivityId == input.ActivityId && x.IsEffective == StatusEnum.有效.GetHashCode()) - .Select(x => x.ItemId) - .ToListAsync(); - - if (!itemIds.Any()) - { - return new ActivityStatisticsOutput - { - ActivityId = input.ActivityId, - ActivityName = activity.ActivityName, - BillingCount = 0, - BillingAmount = 0, - RefundCount = 0, - RefundAmount = 0, - NetBillingCount = 0, - NetBillingAmount = 0, - RefundRate = 0 - }; - } - - // 4. 构建品项ID过滤条件 - var itemIdsStr = string.Join("','", itemIds); - var itemIdsFilter = $"AND px.px IN ('{itemIdsStr}')"; - var itemIdsFilterRefund = $"AND hytkmx.px IN ('{itemIdsStr}')"; - - // 5. 构建门店过滤条件 + // 3. 构建门店过滤条件 string storeFilter = ""; - string storeFilterRefund = ""; if (input.StoreIds != null && input.StoreIds.Any()) { var storeIdsStr = string.Join("','", input.StoreIds); storeFilter = $"AND kd.djmd IN ('{storeIdsStr}')"; - storeFilterRefund = $"AND hytk.md IN ('{storeIdsStr}')"; } - // 6. 开单统计 - var billingSql = $@" + // 4. 获取总记录数和总金额 + var totalSql = $@" SELECT - COUNT(DISTINCT kd.F_Id) as billing_count, - SUM(CAST(px.F_ActualPrice AS DECIMAL(18,2))) as billing_amount - FROM lq_kd_pxmx px - LEFT JOIN lq_kd_kdjlb kd ON px.glkdbh = kd.F_Id - WHERE px.F_IsEffective = 1 - {itemIdsFilter} - AND px.yjsj >= '{startTime:yyyy-MM-dd HH:mm:ss}' - AND px.yjsj <= '{endTime:yyyy-MM-dd HH:mm:ss}' + COUNT(*) as total, + COALESCE(SUM(CAST(kd.sfyj AS DECIMAL(18,2))), 0) as billing_amount, + COALESCE(SUM(CAST(kd.qk AS DECIMAL(18,2))), 0) as debt_amount + FROM lq_kd_kdjlb kd + WHERE kd.F_IsEffective = 1 + AND kd.F_ActivityId = '{input.ActivityId}' + AND kd.kdrq >= '{startTime:yyyy-MM-dd HH:mm:ss}' + AND kd.kdrq <= '{endTime:yyyy-MM-dd HH:mm:ss}' {storeFilter}"; - var billingData = await _db.Ado.SqlQueryAsync(billingSql); - var billingCount = Convert.ToInt32(billingData.FirstOrDefault()?.billing_count ?? 0); - var billingAmount = Convert.ToDecimal(billingData.FirstOrDefault()?.billing_amount ?? 0); + var totalData = await _db.Ado.SqlQueryAsync(totalSql); + var billingCount = Convert.ToInt32(totalData.FirstOrDefault()?.total ?? 0); + var billingAmount = Convert.ToDecimal(totalData.FirstOrDefault()?.billing_amount ?? 0); + var debtAmount = Convert.ToDecimal(totalData.FirstOrDefault()?.debt_amount ?? 0); - // 7. 退卡统计 - var refundSql = $@" + // 5. 分页查询开单列表 + var offset = (input.PageIndex - 1) * input.PageSize; + var billingListSql = $@" SELECT - COUNT(DISTINCT hytk.F_Id) as refund_count, - SUM(CAST(hytkmx.tkje AS DECIMAL(18,2))) as refund_amount - FROM lq_hytk_mx hytkmx - LEFT JOIN lq_hytk_hytk hytk ON hytkmx.F_RefundInfoId = hytk.F_Id - WHERE hytkmx.F_IsEffective = 1 - {itemIdsFilterRefund} - AND hytkmx.tksj >= '{startTime:yyyy-MM-dd HH:mm:ss}' - AND hytkmx.tksj <= '{endTime:yyyy-MM-dd HH:mm:ss}' - {storeFilterRefund}"; - - var refundData = await _db.Ado.SqlQueryAsync(refundSql); - var refundCount = Convert.ToInt32(refundData.FirstOrDefault()?.refund_count ?? 0); - var refundAmount = Convert.ToDecimal(refundData.FirstOrDefault()?.refund_amount ?? 0); - - // 8. 计算净值和退卡率 - var netBillingCount = billingCount - refundCount; - var netBillingAmount = billingAmount - refundAmount; - var refundRate = billingCount > 0 ? Math.Round((decimal)refundCount / billingCount * 100, 2) : 0; - - // 9. 返回统计结果 + kd.F_Id as BillingId, + kd.kdrq as BillingDate, + COALESCE(kh.khmc, '') as CustomerName, + COALESCE(kh.sjh, '') as CustomerPhone, + kd.djmd as StoreId, + COALESCE(md.dm, '') as StoreName, + CAST(kd.sfyj AS DECIMAL(18,2)) as Amount, + CAST(kd.qk AS DECIMAL(18,2)) as DebtAmount + FROM lq_kd_kdjlb kd + LEFT JOIN lq_khxx kh ON kd.kdhy = kh.F_Id + LEFT JOIN lq_mdxx md ON kd.djmd = md.F_Id + WHERE kd.F_IsEffective = 1 + AND kd.F_ActivityId = '{input.ActivityId}' + AND kd.kdrq >= '{startTime:yyyy-MM-dd HH:mm:ss}' + AND kd.kdrq <= '{endTime:yyyy-MM-dd HH:mm:ss}' + {storeFilter} + ORDER BY kd.kdrq DESC + LIMIT {input.PageSize} OFFSET {offset}"; + + var billingListData = await _db.Ado.SqlQueryAsync(billingListSql); + var billingList = billingListData?.Select(item => new ActivityBillingItem + { + BillingId = item.BillingId?.ToString(), + BillingDate = item.BillingDate != null ? (DateTime?)item.BillingDate : null, + CustomerName = item.CustomerName?.ToString(), + CustomerPhone = item.CustomerPhone?.ToString(), + StoreId = item.StoreId?.ToString(), + StoreName = item.StoreName?.ToString(), + Amount = Convert.ToDecimal(item.Amount ?? 0), + DebtAmount = Convert.ToDecimal(item.DebtAmount ?? 0) + }).ToList() ?? new List(); + + // 6. 返回统计结果 return new ActivityStatisticsOutput { ActivityId = input.ActivityId, ActivityName = activity.ActivityName, BillingCount = billingCount, BillingAmount = billingAmount, - RefundCount = refundCount, - RefundAmount = refundAmount, - NetBillingCount = netBillingCount, - NetBillingAmount = netBillingAmount, - RefundRate = refundRate + DebtAmount = debtAmount, + BillingList = billingList }; } catch (Exception ex) diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqReportService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqReportService.cs index d440254..ba5ec9e 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqReportService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqReportService.cs @@ -715,12 +715,17 @@ namespace NCC.Extend /// - storeIds: 门店ID列表(可选) /// /// 返回字段说明: - /// - TotalBillingAmount: 开单总金额 + /// - TotalBillingAmount: 开单总金额(未扣除退卡) /// - TotalConsumeAmount: 耗卡总金额 /// - TotalRefundAmount: 退卡总金额 /// - BillingCount: 开单人数(按客户去重) /// - ConsumeCount: 耗卡人数(按客户去重) /// - RefundCount: 退卡人数(按客户去重) + /// - TargetConsumeAmount: 消耗目标业绩(所有门店xhyj字段的总和) + /// - ConsumeCompletionRate: 消耗完成率(百分比) + /// - TargetBillingAmount: 开单目标业绩(所有门店xsyj字段的总和) + /// - CompletedBillingAmount: 开单完成业绩(开单总金额 - 退卡总金额) + /// - BillingCompletionRate: 开单完成率(百分比) /// /// 查询参数 /// 业务统计数据 @@ -749,7 +754,7 @@ namespace NCC.Extend object billingParameters; if (input.StoreIds != null && input.StoreIds.Any()) { - billingSql += " AND kd.F_StoreId IN @storeIds"; + billingSql += " AND kd.djmd IN @storeIds"; billingParameters = new { startTime, endTime, storeIds = input.StoreIds }; } else @@ -774,7 +779,7 @@ namespace NCC.Extend object consumeParameters; if (input.StoreIds != null && input.StoreIds.Any()) { - consumeSql += " AND xh.F_StoreId IN @storeIds"; + consumeSql += " AND xh.md IN @storeIds"; consumeParameters = new { startTime, endTime, storeIds = input.StoreIds }; } else @@ -799,7 +804,7 @@ namespace NCC.Extend object refundParameters; if (input.StoreIds != null && input.StoreIds.Any()) { - refundSql += " AND hytk.F_StoreId IN @storeIds"; + refundSql += " AND hytk.md IN @storeIds"; refundParameters = new { startTime, endTime, storeIds = input.StoreIds }; } else @@ -811,6 +816,50 @@ namespace NCC.Extend var refundCount = Convert.ToInt32(refundResult?.FirstOrDefault()?.refund_count ?? 0); var refundAmount = Convert.ToDecimal(refundResult?.FirstOrDefault()?.refund_amount ?? 0m); + // 第四步:获取消耗目标业绩(所有门店xhyj字段的总和) + var targetConsumeSql = "SELECT COALESCE(SUM(CAST(md.xhyj AS DECIMAL(18,2))), 0) as target_consume_amount FROM lq_mdxx md WHERE 1=1"; + object targetConsumeParameters = null; + + if (input.StoreIds != null && input.StoreIds.Any()) + { + targetConsumeSql += " AND md.F_Id IN @storeIds"; + targetConsumeParameters = new { storeIds = input.StoreIds }; + } + + var targetConsumeResult = await _db.Ado.SqlQueryAsync(targetConsumeSql, targetConsumeParameters); + var targetConsumeAmount = Convert.ToDecimal(targetConsumeResult?.FirstOrDefault()?.target_consume_amount ?? 0m); + + // 第五步:获取开单目标业绩(所有门店xsyj字段的总和) + var targetBillingSql = "SELECT COALESCE(SUM(CAST(md.xsyj AS DECIMAL(18,2))), 0) as target_billing_amount FROM lq_mdxx md WHERE 1=1"; + object targetBillingParameters = null; + + if (input.StoreIds != null && input.StoreIds.Any()) + { + targetBillingSql += " AND md.F_Id IN @storeIds"; + targetBillingParameters = new { storeIds = input.StoreIds }; + } + + var targetBillingResult = await _db.Ado.SqlQueryAsync(targetBillingSql, targetBillingParameters); + var targetBillingAmount = Convert.ToDecimal(targetBillingResult?.FirstOrDefault()?.target_billing_amount ?? 0m); + + // 计算开单完成业绩(开单总金额 - 退卡总金额) + var completedBillingAmount = billingAmount - refundAmount; + + // 计算完成率 + var consumeCompletionRate = 0m; + if (targetConsumeAmount > 0) + { + consumeCompletionRate = (consumeAmount / targetConsumeAmount) * 100m; + consumeCompletionRate = decimal.Round(consumeCompletionRate, 2); + } + + var billingCompletionRate = 0m; + if (targetBillingAmount > 0) + { + billingCompletionRate = (completedBillingAmount / targetBillingAmount) * 100m; + billingCompletionRate = decimal.Round(billingCompletionRate, 2); + } + var result = new BusinessStatisticsOutput { TotalBillingAmount = billingAmount, @@ -818,7 +867,12 @@ namespace NCC.Extend TotalRefundAmount = refundAmount, BillingCount = billingCount, ConsumeCount = consumeCount, - RefundCount = refundCount + RefundCount = refundCount, + TargetConsumeAmount = targetConsumeAmount, + ConsumeCompletionRate = consumeCompletionRate, + TargetBillingAmount = targetBillingAmount, + CompletedBillingAmount = completedBillingAmount, + BillingCompletionRate = billingCompletionRate }; return result; @@ -878,6 +932,7 @@ namespace NCC.Extend var endTime = input.EndTime ?? DateTime.Now; // 第一步:获取客户类型统计 + // 注意:lq_khxx表没有门店字段,无法按门店过滤 var customerTypeSql = $@" SELECT SUM(CASE WHEN kh.khlx = '{MemberTypeEnum.线索.GetHashCode()}' THEN 1 ELSE 0 END) as lead_count, @@ -888,16 +943,7 @@ namespace NCC.Extend WHERE kh.F_CreateTime >= @startTime AND kh.F_CreateTime <= @endTime"; - object customerTypeParameters; - if (input.StoreIds != null && input.StoreIds.Any()) - { - customerTypeSql += " AND kh.F_StoreId IN @storeIds"; - customerTypeParameters = new { startTime, endTime, storeIds = input.StoreIds }; - } - else - { - customerTypeParameters = new { startTime, endTime }; - } + object customerTypeParameters = new { startTime, endTime }; var customerTypeResult = await _db.Ado.SqlQueryAsync(customerTypeSql, customerTypeParameters); var leadCount = Convert.ToInt32(customerTypeResult?.FirstOrDefault()?.lead_count ?? 0); @@ -938,7 +984,7 @@ namespace NCC.Extend object consumeParameters; if (input.StoreIds != null && input.StoreIds.Any()) { - consumeSql += " AND xh.F_StoreId IN @storeIds"; + consumeSql += " AND xh.md IN @storeIds"; consumeParameters = new { startTime, endTime, storeIds = input.StoreIds }; } else diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs index 797600e..4ead485 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs @@ -3389,7 +3389,7 @@ namespace NCC.Extend.LqStatistics /// /// /// 根据员工ID和月份统计员工的完整业绩数据 - /// 包括:拓客人数、邀约人数、预约人数、开单、消耗、退卡、人头、人次 + /// 包括:拓客人数、邀约人数、预约人数、开单、消耗、退卡、人头、人次、项目数 /// /// 示例请求: /// ```json @@ -3411,8 +3411,10 @@ namespace NCC.Extend.LqStatistics /// - AppointmentCount: 预约人数 /// - BillingCount: 开单数量 /// - BillingAmount: 开单金额 + /// - BillingProjectCount: 开单项目数(项目次数总和) /// - ConsumeCount: 消耗数量 /// - ConsumeAmount: 消耗金额 + /// - ConsumeProjectCount: 消耗项目数(项目次数总和) /// - RefundCount: 退卡数量 /// - RefundAmount: 退卡金额 /// - HeadCount: 人头(月度去重客户数) @@ -3461,6 +3463,12 @@ namespace NCC.Extend.LqStatistics // 8. 人次统计 var personCount = await GetPersonCount(input.UserId, statisticsMonth); + // 9. 开单项目数统计 + var billingProjectCount = await GetBillingProjectCount(input.UserId, statisticsMonth); + + // 10. 消耗项目数统计 + var consumeProjectCount = await GetConsumeProjectCount(input.UserId, statisticsMonth); + return new EmployeePerformanceStatisticsOutput { UserId = input.UserId, @@ -3475,7 +3483,9 @@ namespace NCC.Extend.LqStatistics RefundCount = refundStats.Count, RefundAmount = refundStats.Amount, HeadCount = headCount, - PersonCount = personCount + PersonCount = personCount, + BillingProjectCount = billingProjectCount, + ConsumeProjectCount = consumeProjectCount }; } catch (Exception ex) @@ -3625,6 +3635,42 @@ namespace NCC.Extend.LqStatistics return Convert.ToInt32(result.FirstOrDefault()?.Count ?? 0); } + /// + /// 统计开单项目数(项目次数总和) + /// + private async Task GetBillingProjectCount(string userId, string month) + { + var sql = $@" + SELECT COALESCE(SUM(pxmx.F_ProjectNumber), 0) as Count + FROM lq_kd_jksyj jksyj + INNER JOIN lq_kd_pxmx pxmx ON jksyj.F_kdpxid = pxmx.F_Id + WHERE jksyj.jkszh = '{userId}' + AND jksyj.F_IsEffective = 1 + AND DATE_FORMAT(jksyj.yjsj, '%Y%m') = '{month}'"; + + var result = await _db.Ado.SqlQueryAsync(sql); + return Convert.ToInt32(result.FirstOrDefault()?.Count ?? 0); + } + + /// + /// 统计消耗项目数(项目次数总和) + /// + private async Task GetConsumeProjectCount(string userId, string month) + { + var sql = $@" + SELECT COALESCE(SUM(pxmx.F_ProjectNumber), 0) as Count + FROM lq_xh_jksyj jksyj + INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id + INNER JOIN lq_xh_pxmx pxmx ON pxmx.F_ConsumeInfoId = hyhk.F_Id + WHERE jksyj.jkszh = '{userId}' + AND jksyj.F_IsEffective = 1 + AND hyhk.F_IsEffective = 1 + AND DATE_FORMAT(hyhk.hksj, '%Y%m') = '{month}'"; + + var result = await _db.Ado.SqlQueryAsync(sql); + return Convert.ToInt32(result.FirstOrDefault()?.Count ?? 0); + } + #endregion } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs index 12f8fc7..2d709db 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs @@ -960,5 +960,159 @@ namespace NCC.Extend.LqTkjlb } #endregion + #region 拓客统计数据 + /// + /// 获取拓客统计数据 + /// + /// + /// 统计拓客相关的各项数据,包括拓客人数、邀约人头、预约人头、到店人头、开单人头、开单金额、消费人头、消费金额 + /// + /// 示例请求: + /// ```json + /// { + /// "startTime": "2025-10-01", + /// "endTime": "2025-10-31", + /// "eventId": "活动ID" + /// } + /// ``` + /// + /// 参数说明: + /// - startTime: 开始时间(可选) + /// - endTime: 结束时间(可选) + /// - eventId: 活动ID(可选) + /// + /// 返回字段说明: + /// - TkCount: 拓客人数 + /// - YaoyCount: 邀约人头 + /// - YyCount: 预约人头 + /// - DdCount: 到店人头 + /// - KdCount: 开单人头 + /// - KdAmount: 开单金额 + /// - XfCount: 消费人头 + /// - XfAmount: 消费金额 + /// + /// 查询参数 + /// 拓客统计数据 + /// 成功返回统计数据 + /// 参数错误 + /// 服务器内部错误 + [HttpPost("get-tk-statistics")] + public async Task GetTkStatistics(TkStatisticsInput input) + { + try + { + // 构建基本过滤条件 + string timeFilter = ""; + if (input.StartTime.HasValue && input.EndTime.HasValue) + { + timeFilter = $@" + AND tk.F_CreateTime >= '{input.StartTime:yyyy-MM-dd HH:mm:ss}' + AND tk.F_CreateTime <= '{input.EndTime:yyyy-MM-dd HH:mm:ss}'"; + } + else if (input.StartTime.HasValue) + { + timeFilter = $"AND tk.F_CreateTime >= '{input.StartTime:yyyy-MM-dd HH:mm:ss}'"; + } + else if (input.EndTime.HasValue) + { + timeFilter = $"AND tk.F_CreateTime <= '{input.EndTime:yyyy-MM-dd HH:mm:ss}'"; + } + + string eventFilter = ""; + if (!string.IsNullOrWhiteSpace(input.EventId)) + { + eventFilter = $"AND tk.F_EventId = '{input.EventId}'"; + } + + // 第一步:获取拓客人数(去重会员ID) + var tkSql = $@" + SELECT COUNT(DISTINCT tk.F_MemberId) as tk_count + FROM lq_tkjlb tk + WHERE 1=1 {timeFilter} {eventFilter}"; + + var tkResult = await _db.Ado.SqlQueryAsync(tkSql); + var tkCount = Convert.ToInt32(tkResult?.FirstOrDefault()?.tk_count ?? 0); + + // 第二步:获取邀约人头(去重会员ID) + var yaoySql = $@" + SELECT COUNT(DISTINCT tk.F_MemberId) as yaoy_count + FROM lq_tkjlb tk + INNER JOIN lq_yaoyjl yy ON tk.F_MemberId = yy.yykh + AND yy.F_StoreId = tk.F_StoreId + WHERE 1=1 {timeFilter} {eventFilter}"; + + var yaoyResult = await _db.Ado.SqlQueryAsync(yaoySql); + var yaoyCount = Convert.ToInt32(yaoyResult?.FirstOrDefault()?.yaoy_count ?? 0); + + // 第三步:获取预约人头(去重会员ID) + var yySql = $@" + SELECT COUNT(DISTINCT tk.F_MemberId) as yy_count + FROM lq_tkjlb tk + INNER JOIN lq_yyjl yyjl ON tk.F_MemberId = yyjl.gk + AND yyjl.F_Status = '已确认' + WHERE 1=1 {timeFilter} {eventFilter}"; + + var yyResult = await _db.Ado.SqlQueryAsync(yySql); + var yyCount = Convert.ToInt32(yyResult?.FirstOrDefault()?.yy_count ?? 0); + + // 第四步:获取到店人头(预约且状态为已确认,假设预约表有到店时间字段) + var ddSql = $@" + SELECT COUNT(DISTINCT tk.F_MemberId) as dd_count + FROM lq_tkjlb tk + INNER JOIN lq_yyjl yyjl ON tk.F_MemberId = yyjl.gk + AND yyjl.F_Status = '已确认' + WHERE yyjl.yysj <= NOW() + AND 1=1 {timeFilter} {eventFilter}"; + + var ddResult = await _db.Ado.SqlQueryAsync(ddSql); + var ddCount = Convert.ToInt32(ddResult?.FirstOrDefault()?.dd_count ?? 0); + + // 第五步:获取开单人头和金额(去重会员ID,金额累加) + var kdSql = $@" + SELECT + COUNT(DISTINCT tk.F_MemberId) as kd_count, + COALESCE(SUM(kd.sfyj), 0) as kd_amount + FROM lq_tkjlb tk + INNER JOIN lq_kd_kdjlb kd ON tk.F_MemberId = kd.kdhy + AND kd.F_IsEffective = 1 + WHERE 1=1 {timeFilter} {eventFilter}"; + + var kdResult = await _db.Ado.SqlQueryAsync(kdSql); + var kdCount = Convert.ToInt32(kdResult?.FirstOrDefault()?.kd_count ?? 0); + var kdAmount = Convert.ToDecimal(kdResult?.FirstOrDefault()?.kd_amount ?? 0); + + // 第六步:获取消费人头和金额(去重会员ID,金额累加) + var xfSql = $@" + SELECT + COUNT(DISTINCT tk.F_MemberId) as xf_count, + COALESCE(SUM(xh.xfje), 0) as xf_amount + FROM lq_tkjlb tk + INNER JOIN lq_xh_hyhk xh ON tk.F_MemberId = xh.hy + AND xh.F_IsEffective = 1 + WHERE 1=1 {timeFilter} {eventFilter}"; + + var xfResult = await _db.Ado.SqlQueryAsync(xfSql); + var xfCount = Convert.ToInt32(xfResult?.FirstOrDefault()?.xf_count ?? 0); + var xfAmount = Convert.ToDecimal(xfResult?.FirstOrDefault()?.xf_amount ?? 0); + + return new TkStatisticsOutput + { + TkCount = tkCount, + YaoyCount = yaoyCount, + YyCount = yyCount, + DdCount = ddCount, + KdCount = kdCount, + KdAmount = kdAmount, + XfCount = xfCount, + XfAmount = xfAmount + }; + } + catch (Exception ex) + { + throw NCCException.Oh($"获取拓客统计数据失败: {ex.Message}"); + } + } + #endregion + } }