diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatisticsTechPerformance/LqStatisticsTechPerformanceListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatisticsTechPerformance/LqStatisticsTechPerformanceListOutput.cs new file mode 100644 index 0000000..03d53ea --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatisticsTechPerformance/LqStatisticsTechPerformanceListOutput.cs @@ -0,0 +1,80 @@ +using System; + +namespace NCC.Extend.Entitys.Dto.LqStatisticsTechPerformance +{ + /// + /// 科技部开单业绩统计列表输出 + /// + public class LqStatisticsTechPerformanceListOutput + { + /// + /// 主键ID + /// + public string Id { get; set; } + + /// + /// 统计月份(YYYYMM) + /// + public string StatisticsMonth { get; set; } + + /// + /// 科技部老师ID + /// + public string TeacherId { get; set; } + + /// + /// 科技部老师姓名 + /// + public string TeacherName { get; set; } + + /// + /// 科技部老师账号 + /// + public string TeacherAccount { get; set; } + + /// + /// 门店ID + /// + public string StoreId { get; set; } + + /// + /// 门店名称 + /// + public string StoreName { get; set; } + + /// + /// 订单数量 + /// + public int OrderCount { get; set; } + + /// + /// 总业绩金额 + /// + public decimal TotalPerformance { get; set; } + + /// + /// 人工成本 + /// + public decimal LaborCost { get; set; } + + /// + /// 项目次数 + /// + public decimal ProjectCount { get; set; } + + /// + /// 最后订单日期 + /// + public DateTime? LastOrderDate { get; set; } + + /// + /// 首次订单日期 + /// + public DateTime? FirstOrderDate { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreateTime { get; set; } + } +} diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatisticsTechPerformance/LqStatisticsTechPerformanceListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatisticsTechPerformance/LqStatisticsTechPerformanceListQueryInput.cs new file mode 100644 index 0000000..e3f77aa --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatisticsTechPerformance/LqStatisticsTechPerformanceListQueryInput.cs @@ -0,0 +1,35 @@ +using NCC.Common.Filter; + +namespace NCC.Extend.Entitys.Dto.LqStatisticsTechPerformance +{ + /// + /// 科技部开单业绩统计列表查询输入 + /// + public class LqStatisticsTechPerformanceListQueryInput : PageInputBase + { + /// + /// 统计月份(YYYYMM) + /// + public string StatisticsMonth { get; set; } + + /// + /// 科技部老师ID + /// + public string TeacherId { get; set; } + + /// + /// 科技部老师姓名 + /// + public string TeacherName { get; set; } + + /// + /// 门店ID + /// + public string StoreId { get; set; } + + /// + /// 门店名称 + /// + public string StoreName { get; set; } + } +} diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_statistics_tech_performance/LqStatisticsTechPerformanceEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_statistics_tech_performance/LqStatisticsTechPerformanceEntity.cs new file mode 100644 index 0000000..1053108 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_statistics_tech_performance/LqStatisticsTechPerformanceEntity.cs @@ -0,0 +1,108 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using SqlSugar; + +namespace NCC.Extend.Entitys.lq_statistics_tech_performance +{ + /// + /// 科技部开单业绩统计数据表 + /// + [SugarTable("lq_statistics_tech_performance")] + public class LqStatisticsTechPerformanceEntity + { + /// + /// 主键ID + /// + [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true, Length = 50)] + + public string Id { get; set; } + + /// + /// 统计月份(YYYYMM) + /// + [Required] + [StringLength(6)] + [SugarColumn(ColumnName = "F_StatisticsMonth", Length = 6, IsNullable = false)] + public string StatisticsMonth { get; set; } + + /// + /// 科技部老师ID + /// + [Required] + [StringLength(50)] + [SugarColumn(ColumnName = "F_TeacherId", Length = 50, IsNullable = false)] + public string TeacherId { get; set; } + + /// + /// 科技部老师姓名 + /// + [Required] + [StringLength(100)] + [SugarColumn(ColumnName = "F_TeacherName", Length = 100, IsNullable = false)] + public string TeacherName { get; set; } + + /// + /// 科技部老师账号 + /// + [StringLength(100)] + [SugarColumn(ColumnName = "F_TeacherAccount", Length = 100, IsNullable = true)] + public string TeacherAccount { get; set; } + + /// + /// 门店ID + /// + [StringLength(50)] + [SugarColumn(ColumnName = "F_StoreId", Length = 50, IsNullable = true)] + public string StoreId { get; set; } + + /// + /// 门店名称 + /// + [StringLength(100)] + [SugarColumn(ColumnName = "F_StoreName", Length = 100, IsNullable = true)] + public string StoreName { get; set; } + + /// + /// 订单数量 + /// + [SugarColumn(ColumnName = "F_OrderCount", IsNullable = false)] + public int OrderCount { get; set; } = 0; + + /// + /// 总业绩金额 + /// + [SugarColumn(ColumnName = "F_TotalPerformance", DecimalDigits = 2, IsNullable = false)] + public decimal TotalPerformance { get; set; } = 0.00m; + + /// + /// 人工成本 + /// + [SugarColumn(ColumnName = "F_LaborCost", DecimalDigits = 2, IsNullable = false)] + public decimal LaborCost { get; set; } = 0.00m; + + /// + /// 项目次数 + /// + [SugarColumn(ColumnName = "F_ProjectCount", DecimalDigits = 2, IsNullable = false)] + public decimal ProjectCount { get; set; } = 0.00m; + + /// + /// 最后订单日期 + /// + [SugarColumn(ColumnName = "F_LastOrderDate", IsNullable = true)] + public DateTime? LastOrderDate { get; set; } + + /// + /// 首次订单日期 + /// + [SugarColumn(ColumnName = "F_FirstOrderDate", IsNullable = true)] + public DateTime? FirstOrderDate { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "F_CreateTime", IsNullable = false)] + public DateTime CreateTime { get; set; } = DateTime.Now; + } +} diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqEventService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqEventService.cs index 7185b0d..080fbad 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqEventService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqEventService.cs @@ -729,25 +729,49 @@ namespace NCC.Extend.LqEvent try { - // 使用多表查询获取门店统计数据 - var storeData = await _db.Queryable( + // 第一步:获取门店的目标数据(所有参与活动的用户目标总和) + var storeTargets = await _db.Queryable( + (eventUser, store) => eventUser.EventId == eventId && eventUser.StoreId == store.Id + ) + .GroupBy((eventUser, store) => new { StoreId = store.Id, StoreName = store.Dm }) + .Select( + (eventUser, store) => + new + { + StoreId = store.Id, + StoreName = store.Dm, + TotalTarget = SqlFunc.AggregateSum(eventUser.EventTarget) + } + ) + .ToListAsync(); + + // 第二步:获取门店的完成数据(拓客记录数量) + var storeCompletions = await _db.Queryable( (eventUser, store, tkjlb) => eventUser.EventId == eventId && eventUser.StoreId == store.Id && eventUser.UserId == tkjlb.ExpansionUserId && tkjlb.EventId == eventId ) .GroupBy((eventUser, store, tkjlb) => new { StoreId = store.Id, StoreName = store.Dm }) .Select( (eventUser, store, tkjlb) => - new StoreDataOutput + new { StoreId = store.Id, StoreName = store.Dm, - TotalTarget = SqlFunc.AggregateSum(eventUser.EventTarget), - CompletedTarget = SqlFunc.AggregateCount(tkjlb.Id), - CompletionRate = 0, // 将在内存中计算 - Ranking = 0, // 将在内存中计算 + CompletedTarget = SqlFunc.AggregateCount(tkjlb.Id) } ) .ToListAsync(); + // 第三步:合并数据 + var storeData = storeTargets.Select(target => new StoreDataOutput + { + StoreId = target.StoreId, + StoreName = target.StoreName, + TotalTarget = target.TotalTarget, + CompletedTarget = storeCompletions.FirstOrDefault(c => c.StoreId == target.StoreId)?.CompletedTarget ?? 0, + CompletionRate = 0, // 将在内存中计算 + Ranking = 0, // 将在内存中计算 + }).ToList(); + // 计算完成率和排名 foreach (var store in storeData) { diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs index 1d80468..7b4ab4f 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs @@ -13,6 +13,7 @@ using NCC.Dependency; using NCC.DynamicApiController; using NCC.Extend.Entitys.Dto.LqMdxx; using NCC.Extend.Entitys.Dto.LqStatistics; +using NCC.Extend.Entitys.Dto.LqStatisticsTechPerformance; using NCC.Extend.Entitys.Dto.LqYcsdJsj; using NCC.Extend.Entitys.lq_hytk_kjbsyj; using NCC.Extend.Entitys.lq_jinsanjiao_user; @@ -25,6 +26,7 @@ using NCC.Extend.Entitys.lq_ycsd_jsj; using NCC.Extend.Entitys.lq_yjmxb; using NCC.Extend.Entitys.lq_statistics_gold_triangle; using NCC.Extend.Entitys.lq_statistics_personal_performance; +using NCC.Extend.Entitys.lq_statistics_tech_performance; using NCC.Extend.Entitys.lq_xmzl; using NCC.Extend.Entitys.Dto.LqStatisticsPersonalPerformance; using NCC.Extend.Entitys.v_tech_teacher_flow; @@ -1190,7 +1192,7 @@ namespace NCC.Extend.LqStatistics #region 金三角统计数据保存 /// - /// 1、保存金三角开卡业绩统计数据 + /// 【1】保存金三角开卡业绩统计数据 /// /// /// 根据金三角设定和开单记录统计金三角的业绩数据 @@ -1366,7 +1368,7 @@ namespace NCC.Extend.LqStatistics #region 个人开单业绩统计 /// - /// 保存个人开单业绩统计数据 + /// 【2】保存健康师个人开单业绩统计数据 /// /// /// 根据开单记录统计个人的业绩数据,包括基础业绩和合作业绩 @@ -1654,5 +1656,242 @@ namespace NCC.Extend.LqStatistics /// public string ParentId { get; set; } } + + #region 科技部开单业绩统计 + + /// + /// 【3】保存科技部开单业绩统计数据 + /// + /// + /// 根据指定月份统计科技部老师的开单业绩数据,只统计开卡业绩,不包含耗卡和退卡业绩 + /// + /// 示例请求: + /// ```json + /// POST /api/Extend/LqStatistics/save-tech-performance-statistics + /// { + /// "statisticsMonth": "202401" + /// } + /// ``` + /// + /// 参数说明: + /// - statisticsMonth: 统计月份,格式为YYYYMM + /// + /// 统计月份(YYYYMM格式) + /// 保存结果 + /// 成功保存统计数据 + /// 参数错误 + /// 服务器内部错误 + [HttpPost("save-tech-performance-statistics")] + public async Task SaveTechPerformanceStatistics(string statisticsMonth) + { + if (string.IsNullOrEmpty(statisticsMonth) || statisticsMonth.Length != 6) + { + throw NCCException.Oh("统计月份格式错误,请使用YYYYMM格式"); + } + + try + { + // 使用数据库聚合方式,只统计开单业绩(开卡流水) + var sql = @" + SELECT + k.kjbls AS TeacherId, + k.kjblsxm AS TeacherName, + k.kjblszh AS TeacherAccount, + NULL AS StoreId, + NULL AS StoreName, + COUNT(DISTINCT k.F_kdpxid) AS OrderCount, + SUM(CAST(COALESCE(k.kjblsyj, 0) AS DECIMAL(18,2))) AS TotalPerformance, + SUM(CAST(COALESCE(k.F_LaborCost, 0) AS DECIMAL(18,2))) AS LaborCost, + SUM(CAST(COALESCE(pm.F_ProjectNumber, 0) AS DECIMAL(18,2))) AS ProjectCount, + MAX(k.yjsj) AS LastOrderDate, + MIN(k.yjsj) AS FirstOrderDate + FROM lq_kd_kjbsyj k + LEFT JOIN lq_kd_pxmx pm ON k.F_kdpxid = pm.F_Id + WHERE k.kjbls IS NOT NULL + AND k.kjblsxm IS NOT NULL + AND k.yjsj IS NOT NULL + AND k.kjblsyj IS NOT NULL + AND k.kjblsyj != '' + AND k.kjblsyj != '0' + AND YEAR(k.yjsj) = @year + AND MONTH(k.yjsj) = @month + GROUP BY + k.kjbls, + k.kjblsxm, + k.kjblszh + ORDER BY TotalPerformance DESC"; + + // 解析统计月份 + var year = int.Parse(statisticsMonth.Substring(0, 4)); + var month = int.Parse(statisticsMonth.Substring(4, 2)); + + // 执行SQL查询 + var statisticsData = await _db.Ado.SqlQueryAsync(sql, new { year, month }); + + _logger.LogInformation($"SQL查询结果数量: {statisticsData?.Count ?? 0}"); + if (statisticsData?.Any() == true) + { + var firstData = statisticsData.First(); + _logger.LogInformation($"第一条数据: TeacherId={firstData.TeacherId}, TeacherName={firstData.TeacherName}, TotalPerformance={firstData.TotalPerformance}"); + } + + if (!statisticsData.Any()) + { + return new + { + Success = true, + Message = $"未找到 {statisticsMonth} 月份的科技部开单业绩统计数据", + SavedCount = 0 + }; + } + + // 转换为实体对象 + var entities = new List(); + foreach (var data in statisticsData) + { + try + { + var entity = new LqStatisticsTechPerformanceEntity + { + Id = YitIdHelper.NextId().ToString(), + StatisticsMonth = statisticsMonth, + TeacherId = data.TeacherId?.ToString() ?? "", + TeacherName = data.TeacherName?.ToString() ?? "", + TeacherAccount = data.TeacherAccount?.ToString() ?? "", + StoreId = data.StoreId?.ToString() ?? "", + StoreName = data.StoreName?.ToString() ?? "", + OrderCount = Convert.ToInt32(data.OrderCount ?? 0), + TotalPerformance = Convert.ToDecimal(data.TotalPerformance ?? 0), + LaborCost = Convert.ToDecimal(data.LaborCost ?? 0), + ProjectCount = Convert.ToDecimal(data.ProjectCount ?? 0), + LastOrderDate = data.LastOrderDate as DateTime?, + FirstOrderDate = data.FirstOrderDate as DateTime?, + CreateTime = DateTime.Now + }; + entities.Add(entity); + _logger.LogInformation($"成功转换实体: TeacherId={entity.TeacherId}, TotalPerformance={entity.TotalPerformance}"); + } + catch (Exception ex) + { + _logger.LogError($"转换实体失败: TeacherId={data.TeacherId}, Error={ex.Message}"); + } + } + + _logger.LogInformation($"准备插入 {entities.Count} 条实体数据"); + + // 使用事务确保数据一致性 + var result = await _db.Ado.UseTranAsync(async () => + { + try + { + // 先删除该月份的历史数据 + var deleteResult = await _db.Deleteable() + .Where(x => x.StatisticsMonth == statisticsMonth) + .ExecuteCommandAsync(); + _logger.LogInformation($"删除历史数据结果: {deleteResult}"); + + // 批量插入新数据 + var insertResult = await _db.Insertable(entities).ExecuteCommandAsync(); + _logger.LogInformation($"插入新数据结果: {insertResult}"); + return insertResult; + } + catch (Exception ex) + { + _logger.LogError($"事务执行失败: {ex.Message}"); + throw; + } + }); + + _logger.LogInformation($"事务执行结果: IsSuccess={result.IsSuccess}, Data={result.Data}, ErrorMessage={result.ErrorMessage}"); + var savedCount = result.IsSuccess ? result.Data : 0; + _logger.LogInformation($"成功保存科技部开单业绩统计数据 - 月份: {statisticsMonth}, 记录数: {savedCount}"); + + return new + { + Success = true, + Message = $"成功保存 {savedCount} 条科技部开单业绩统计数据", + SavedCount = savedCount, + StatisticsMonth = statisticsMonth + }; + } + catch (Exception ex) + { + _logger.LogError(ex, $"保存科技部开单业绩统计数据失败 - 月份: {statisticsMonth}"); + throw NCCException.Oh($"保存科技部开单业绩统计数据失败: {ex.Message}"); + } + } + + /// + /// 获取科技部开单业绩统计数据 + /// + /// + /// 分页查询科技部开单业绩统计数据 + /// + /// 示例请求: + /// ```json + /// GET /api/Extend/LqStatistics/get-tech-performance-statistics?PageIndex=1&PageSize=10&StatisticsMonth=202401 + /// ``` + /// + /// 查询参数 + /// 分页数据 + /// 查询成功 + /// 参数错误 + /// 服务器内部错误 + [HttpGet("get-tech-performance-statistics")] + public async Task GetTechPerformanceStatistics([FromQuery] LqStatisticsTechPerformanceListQueryInput input) + { + try + { + var query = _db.Queryable(); + + // 添加查询条件 + query = query.WhereIF(!string.IsNullOrEmpty(input.StatisticsMonth), x => x.StatisticsMonth == input.StatisticsMonth); + query = query.WhereIF(!string.IsNullOrEmpty(input.TeacherId), x => x.TeacherId == input.TeacherId); + query = query.WhereIF(!string.IsNullOrEmpty(input.TeacherName), x => x.TeacherName.Contains(input.TeacherName)); + query = query.WhereIF(!string.IsNullOrEmpty(input.StoreId), x => x.StoreId == input.StoreId); + query = query.WhereIF(!string.IsNullOrEmpty(input.StoreName), x => x.StoreName.Contains(input.StoreName)); + + // 按业绩降序排序 + query = query.OrderBy(x => x.TotalPerformance, OrderByType.Desc); + + // 分页查询 + var result = await query.ToPagedListAsync(input.currentPage, input.pageSize); + + return new + { + Success = true, + Data = new + { + Records = result.list.Select(x => new LqStatisticsTechPerformanceListOutput + { + Id = x.Id, + StatisticsMonth = x.StatisticsMonth, + TeacherId = x.TeacherId, + TeacherName = x.TeacherName, + TeacherAccount = x.TeacherAccount, + StoreId = x.StoreId, + StoreName = x.StoreName, + OrderCount = x.OrderCount, + TotalPerformance = x.TotalPerformance, + LaborCost = x.LaborCost, + ProjectCount = x.ProjectCount, + LastOrderDate = x.LastOrderDate, + FirstOrderDate = x.FirstOrderDate, + CreateTime = x.CreateTime + }).ToList(), + Total = result.pagination.Total, + PageIndex = input.currentPage, + PageSize = input.pageSize + } + }; + } + catch (Exception ex) + { + _logger.LogError(ex, "查询科技部开单业绩统计数据失败"); + throw NCCException.Oh($"查询科技部开单业绩统计数据失败: {ex.Message}"); + } + } + + #endregion } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs index 912eceb..7c898a8 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs @@ -182,6 +182,7 @@ namespace NCC.Extend.LqTkjlb MemberInfo.Sjh = input.customerPhone; // 设置手机号 MemberInfo.Khlx = "线索"; MemberInfo.Dah = "GK" + DateTime.Now.ToString("yyyyMMddHHmmss"); + MemberInfo.Gsmd = eventUserInfo.StoreId; var memberResult = await _db.Insertable(MemberInfo).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync(); if (!(memberResult > 0)) { diff --git a/netcore/src/Modularity/Extend/NCC.Extend/Utils/LqKdKdjlbStringGenerator.cs b/netcore/src/Modularity/Extend/NCC.Extend/Utils/LqKdKdjlbStringGenerator.cs index 904a0b0..1449064 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/Utils/LqKdKdjlbStringGenerator.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/Utils/LqKdKdjlbStringGenerator.cs @@ -47,35 +47,35 @@ namespace NCC.Extend.Utils // 健康师:王维 var healthTeachers = GetHealthTeachers(entity.lqKdJksyjList); sb.AppendLine($"⏩健康师:{healthTeachers}"); - + // 活动方案:532工程 sb.AppendLine($"⏩活动方案:{entity.pxxx ?? "无"}"); - + // 跟单配合:王经理 竹主任 陈思思老师 var techTeachers = GetTechTeachers(entity.lqKdKjbsyjList); sb.AppendLine($"⏩跟单配合:{techTeachers}"); - + // 业绩:4800 sb.AppendLine($"⏩业绩:{entity.zdyj}"); - + // 实付:4800 sb.AppendLine($"⏩实付:{entity.sfyj}"); - + // 欠款: sb.AppendLine($"⏩欠款: {entity.qk}"); - + // 抵扣: sb.AppendLine($"⏩抵扣:{entity.ckmx ?? "无"}"); - + // 来源:售后 sb.AppendLine($"⏩来源:{entity.khly ?? "无"}"); - + // 是否属于升单: sb.AppendLine($"⏩是否属于升单:{entity.sfskdd ?? "无"}"); - + // 简介:高姐是我们的老客,今天邀约到犀浦店做532,维维全程陪同,陈思思老师在操作过程中给姐姐分享企业文化,找到顾客需求、邀请王经理 竹主任 给到顾客福利、顾客爽快成交,私密档案已了解到70%,感谢顾客的信任与支持 ,王经理 竹主任 陈老师辛苦了[玫瑰]维维真棒[强]龙城国际店加油!我们还在努力中!家人们给我们打气加油👏👏👏👏等待我们的捷报👍👍 sb.AppendLine($"⏩简介:{entity.jj ?? "无"}"); - + return sb.ToString(); } @@ -94,9 +94,9 @@ namespace NCC.Extend.Utils try { var store = _db.Queryable() - .Where(x => x.Mdbm == storeCode) + .Where(x => x.Id == storeCode) .First(); - + return store?.Dm ?? storeCode; } catch @@ -122,7 +122,7 @@ namespace NCC.Extend.Utils var department = _db.Queryable() .Where(x => x.Id == departmentCode) .First(); - + return department?.Jsj ?? departmentCode; } catch @@ -216,7 +216,7 @@ namespace NCC.Extend.Utils var customer = _db.Queryable() .Where(x => x.Id == customerId) .First(); - + return customer?.Khmc ?? "无"; } catch @@ -242,7 +242,7 @@ namespace NCC.Extend.Utils var user = _db.Queryable() .Where(x => x.Account == account && x.DeleteMark == null) .First(); - + return user?.RealName ?? string.Empty; } catch