Commit ae64a2f0e92baf1791ca528deb3371e38e0d83fb
1 parent
a590db84
feat: 新增拓客统计数据接口,支持按时间和活动过滤
- 新增GetTkStatistics方法,统计拓客相关数据 - 统计指标:拓客人数、邀约人头、预约人头、到店人头、开单人头、开单金额、消费人头、消费金额 - 支持开始时间、结束时间、活动ID过滤(均为可选) - 采用分步统计提高性能 - 创建TkStatisticsInput和TkStatisticsOutput DTO - 更新ILqTkjlbService接口
Showing
4 changed files
with
239 additions
and
0 deletions
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTkjlb/TkStatisticsInput.cs
0 → 100644
| 1 | +using System; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqTkjlb | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 拓客统计数据输入 | |
| 7 | + /// </summary> | |
| 8 | + public class TkStatisticsInput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 开始时间(可选) | |
| 12 | + /// </summary> | |
| 13 | + public DateTime? StartTime { get; set; } | |
| 14 | + | |
| 15 | + /// <summary> | |
| 16 | + /// 结束时间(可选) | |
| 17 | + /// </summary> | |
| 18 | + public DateTime? EndTime { get; set; } | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 活动ID(可选) | |
| 22 | + /// </summary> | |
| 23 | + public string EventId { get; set; } | |
| 24 | + } | |
| 25 | +} | |
| 26 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTkjlb/TkStatisticsOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqTkjlb | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 拓客统计数据输出 | |
| 7 | + /// </summary> | |
| 8 | + public class TkStatisticsOutput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 拓客人数(去重后的人数) | |
| 12 | + /// </summary> | |
| 13 | + public int TkCount { get; set; } | |
| 14 | + | |
| 15 | + /// <summary> | |
| 16 | + /// 邀约人头(已邀约人数) | |
| 17 | + /// </summary> | |
| 18 | + public int YaoyCount { get; set; } | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 预约人头(已预约人数) | |
| 22 | + /// </summary> | |
| 23 | + public int YyCount { get; set; } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 到店人头(已到店人数) | |
| 27 | + /// </summary> | |
| 28 | + public int DdCount { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 开单人头(已开单人数) | |
| 32 | + /// </summary> | |
| 33 | + public int KdCount { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 开单金额 | |
| 37 | + /// </summary> | |
| 38 | + public decimal KdAmount { get; set; } | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 消费人头(已消费人数) | |
| 42 | + /// </summary> | |
| 43 | + public int XfCount { get; set; } | |
| 44 | + | |
| 45 | + /// <summary> | |
| 46 | + /// 消费金额 | |
| 47 | + /// </summary> | |
| 48 | + public decimal XfAmount { get; set; } | |
| 49 | + } | |
| 50 | +} | |
| 51 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Interfaces/ILqTkjlbService.cs
| 1 | 1 | using System.Threading.Tasks; |
| 2 | +using NCC.Extend.Entitys.Dto.LqTkjlb; | |
| 2 | 3 | |
| 3 | 4 | namespace NCC.Extend.Interfaces.LqTkjlb |
| 4 | 5 | { |
| ... | ... | @@ -15,5 +16,12 @@ namespace NCC.Extend.Interfaces.LqTkjlb |
| 15 | 16 | /// </summary> |
| 16 | 17 | /// <returns></returns> |
| 17 | 18 | Task<dynamic> GetTeamDetail(); |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 获取拓客统计数据 | |
| 22 | + /// </summary> | |
| 23 | + /// <param name="input">查询参数</param> | |
| 24 | + /// <returns>拓客统计数据</returns> | |
| 25 | + Task<TkStatisticsOutput> GetTkStatistics(TkStatisticsInput input); | |
| 18 | 26 | } |
| 19 | 27 | } |
| 20 | 28 | \ No newline at end of file | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs
| ... | ... | @@ -960,5 +960,159 @@ namespace NCC.Extend.LqTkjlb |
| 960 | 960 | } |
| 961 | 961 | #endregion |
| 962 | 962 | |
| 963 | + #region 拓客统计数据 | |
| 964 | + /// <summary> | |
| 965 | + /// 获取拓客统计数据 | |
| 966 | + /// </summary> | |
| 967 | + /// <remarks> | |
| 968 | + /// 统计拓客相关的各项数据,包括拓客人数、邀约人头、预约人头、到店人头、开单人头、开单金额、消费人头、消费金额 | |
| 969 | + /// | |
| 970 | + /// 示例请求: | |
| 971 | + /// ```json | |
| 972 | + /// { | |
| 973 | + /// "startTime": "2025-10-01", | |
| 974 | + /// "endTime": "2025-10-31", | |
| 975 | + /// "eventId": "活动ID" | |
| 976 | + /// } | |
| 977 | + /// ``` | |
| 978 | + /// | |
| 979 | + /// 参数说明: | |
| 980 | + /// - startTime: 开始时间(可选) | |
| 981 | + /// - endTime: 结束时间(可选) | |
| 982 | + /// - eventId: 活动ID(可选) | |
| 983 | + /// | |
| 984 | + /// 返回字段说明: | |
| 985 | + /// - TkCount: 拓客人数 | |
| 986 | + /// - YaoyCount: 邀约人头 | |
| 987 | + /// - YyCount: 预约人头 | |
| 988 | + /// - DdCount: 到店人头 | |
| 989 | + /// - KdCount: 开单人头 | |
| 990 | + /// - KdAmount: 开单金额 | |
| 991 | + /// - XfCount: 消费人头 | |
| 992 | + /// - XfAmount: 消费金额 | |
| 993 | + /// </remarks> | |
| 994 | + /// <param name="input">查询参数</param> | |
| 995 | + /// <returns>拓客统计数据</returns> | |
| 996 | + /// <response code="200">成功返回统计数据</response> | |
| 997 | + /// <response code="400">参数错误</response> | |
| 998 | + /// <response code="500">服务器内部错误</response> | |
| 999 | + [HttpPost("get-tk-statistics")] | |
| 1000 | + public async Task<TkStatisticsOutput> GetTkStatistics(TkStatisticsInput input) | |
| 1001 | + { | |
| 1002 | + try | |
| 1003 | + { | |
| 1004 | + // 构建基本过滤条件 | |
| 1005 | + string timeFilter = ""; | |
| 1006 | + if (input.StartTime.HasValue && input.EndTime.HasValue) | |
| 1007 | + { | |
| 1008 | + timeFilter = $@" | |
| 1009 | + AND tk.F_CreateTime >= '{input.StartTime:yyyy-MM-dd HH:mm:ss}' | |
| 1010 | + AND tk.F_CreateTime <= '{input.EndTime:yyyy-MM-dd HH:mm:ss}'"; | |
| 1011 | + } | |
| 1012 | + else if (input.StartTime.HasValue) | |
| 1013 | + { | |
| 1014 | + timeFilter = $"AND tk.F_CreateTime >= '{input.StartTime:yyyy-MM-dd HH:mm:ss}'"; | |
| 1015 | + } | |
| 1016 | + else if (input.EndTime.HasValue) | |
| 1017 | + { | |
| 1018 | + timeFilter = $"AND tk.F_CreateTime <= '{input.EndTime:yyyy-MM-dd HH:mm:ss}'"; | |
| 1019 | + } | |
| 1020 | + | |
| 1021 | + string eventFilter = ""; | |
| 1022 | + if (!string.IsNullOrWhiteSpace(input.EventId)) | |
| 1023 | + { | |
| 1024 | + eventFilter = $"AND tk.F_EventId = '{input.EventId}'"; | |
| 1025 | + } | |
| 1026 | + | |
| 1027 | + // 第一步:获取拓客人数(去重会员ID) | |
| 1028 | + var tkSql = $@" | |
| 1029 | + SELECT COUNT(DISTINCT tk.F_MemberId) as tk_count | |
| 1030 | + FROM lq_tkjlb tk | |
| 1031 | + WHERE 1=1 {timeFilter} {eventFilter}"; | |
| 1032 | + | |
| 1033 | + var tkResult = await _db.Ado.SqlQueryAsync<dynamic>(tkSql); | |
| 1034 | + var tkCount = Convert.ToInt32(tkResult?.FirstOrDefault()?.tk_count ?? 0); | |
| 1035 | + | |
| 1036 | + // 第二步:获取邀约人头(去重会员ID) | |
| 1037 | + var yaoySql = $@" | |
| 1038 | + SELECT COUNT(DISTINCT tk.F_MemberId) as yaoy_count | |
| 1039 | + FROM lq_tkjlb tk | |
| 1040 | + INNER JOIN lq_yaoyjl yy ON tk.F_MemberId = yy.yykh | |
| 1041 | + AND yy.F_StoreId = tk.F_StoreId | |
| 1042 | + WHERE 1=1 {timeFilter} {eventFilter}"; | |
| 1043 | + | |
| 1044 | + var yaoyResult = await _db.Ado.SqlQueryAsync<dynamic>(yaoySql); | |
| 1045 | + var yaoyCount = Convert.ToInt32(yaoyResult?.FirstOrDefault()?.yaoy_count ?? 0); | |
| 1046 | + | |
| 1047 | + // 第三步:获取预约人头(去重会员ID) | |
| 1048 | + var yySql = $@" | |
| 1049 | + SELECT COUNT(DISTINCT tk.F_MemberId) as yy_count | |
| 1050 | + FROM lq_tkjlb tk | |
| 1051 | + INNER JOIN lq_yyjl yyjl ON tk.F_MemberId = yyjl.gk | |
| 1052 | + AND yyjl.F_Status = '已确认' | |
| 1053 | + WHERE 1=1 {timeFilter} {eventFilter}"; | |
| 1054 | + | |
| 1055 | + var yyResult = await _db.Ado.SqlQueryAsync<dynamic>(yySql); | |
| 1056 | + var yyCount = Convert.ToInt32(yyResult?.FirstOrDefault()?.yy_count ?? 0); | |
| 1057 | + | |
| 1058 | + // 第四步:获取到店人头(预约且状态为已确认,假设预约表有到店时间字段) | |
| 1059 | + var ddSql = $@" | |
| 1060 | + SELECT COUNT(DISTINCT tk.F_MemberId) as dd_count | |
| 1061 | + FROM lq_tkjlb tk | |
| 1062 | + INNER JOIN lq_yyjl yyjl ON tk.F_MemberId = yyjl.gk | |
| 1063 | + AND yyjl.F_Status = '已确认' | |
| 1064 | + WHERE yyjl.yysj <= NOW() | |
| 1065 | + AND 1=1 {timeFilter} {eventFilter}"; | |
| 1066 | + | |
| 1067 | + var ddResult = await _db.Ado.SqlQueryAsync<dynamic>(ddSql); | |
| 1068 | + var ddCount = Convert.ToInt32(ddResult?.FirstOrDefault()?.dd_count ?? 0); | |
| 1069 | + | |
| 1070 | + // 第五步:获取开单人头和金额(去重会员ID,金额累加) | |
| 1071 | + var kdSql = $@" | |
| 1072 | + SELECT | |
| 1073 | + COUNT(DISTINCT tk.F_MemberId) as kd_count, | |
| 1074 | + COALESCE(SUM(kd.sfyj), 0) as kd_amount | |
| 1075 | + FROM lq_tkjlb tk | |
| 1076 | + INNER JOIN lq_kd_kdjlb kd ON tk.F_MemberId = kd.kdhy | |
| 1077 | + AND kd.F_IsEffective = 1 | |
| 1078 | + WHERE 1=1 {timeFilter} {eventFilter}"; | |
| 1079 | + | |
| 1080 | + var kdResult = await _db.Ado.SqlQueryAsync<dynamic>(kdSql); | |
| 1081 | + var kdCount = Convert.ToInt32(kdResult?.FirstOrDefault()?.kd_count ?? 0); | |
| 1082 | + var kdAmount = Convert.ToDecimal(kdResult?.FirstOrDefault()?.kd_amount ?? 0); | |
| 1083 | + | |
| 1084 | + // 第六步:获取消费人头和金额(去重会员ID,金额累加) | |
| 1085 | + var xfSql = $@" | |
| 1086 | + SELECT | |
| 1087 | + COUNT(DISTINCT tk.F_MemberId) as xf_count, | |
| 1088 | + COALESCE(SUM(xh.xfje), 0) as xf_amount | |
| 1089 | + FROM lq_tkjlb tk | |
| 1090 | + INNER JOIN lq_xh_hyhk xh ON tk.F_MemberId = xh.hy | |
| 1091 | + AND xh.F_IsEffective = 1 | |
| 1092 | + WHERE 1=1 {timeFilter} {eventFilter}"; | |
| 1093 | + | |
| 1094 | + var xfResult = await _db.Ado.SqlQueryAsync<dynamic>(xfSql); | |
| 1095 | + var xfCount = Convert.ToInt32(xfResult?.FirstOrDefault()?.xf_count ?? 0); | |
| 1096 | + var xfAmount = Convert.ToDecimal(xfResult?.FirstOrDefault()?.xf_amount ?? 0); | |
| 1097 | + | |
| 1098 | + return new TkStatisticsOutput | |
| 1099 | + { | |
| 1100 | + TkCount = tkCount, | |
| 1101 | + YaoyCount = yaoyCount, | |
| 1102 | + YyCount = yyCount, | |
| 1103 | + DdCount = ddCount, | |
| 1104 | + KdCount = kdCount, | |
| 1105 | + KdAmount = kdAmount, | |
| 1106 | + XfCount = xfCount, | |
| 1107 | + XfAmount = xfAmount | |
| 1108 | + }; | |
| 1109 | + } | |
| 1110 | + catch (Exception ex) | |
| 1111 | + { | |
| 1112 | + throw NCCException.Oh($"获取拓客统计数据失败: {ex.Message}"); | |
| 1113 | + } | |
| 1114 | + } | |
| 1115 | + #endregion | |
| 1116 | + | |
| 963 | 1117 | } |
| 964 | 1118 | } | ... | ... |