diff --git a/antis-ncc-admin/.env.development b/antis-ncc-admin/.env.development index bd6266d..2f8e237 100644 --- a/antis-ncc-admin/.env.development +++ b/antis-ncc-admin/.env.development @@ -1,5 +1,6 @@ # 开发 VUE_CLI_BABEL_TRANSPILE_MODULES = true -VUE_APP_BASE_API = 'http://lvqian.antissoft.com' +# VUE_APP_BASE_API = 'http://lvqian.antissoft.com' +VUE_APP_BASE_API = 'http://localhost:2011' VUE_APP_BASE_WSS = 'ws://192.168.110.45:2011/websocket' diff --git a/antis-ncc-admin/src/api/extend/salaryCalculation.js b/antis-ncc-admin/src/api/extend/salaryCalculation.js new file mode 100644 index 0000000..77ce7a3 --- /dev/null +++ b/antis-ncc-admin/src/api/extend/salaryCalculation.js @@ -0,0 +1,28 @@ +import request from '@/utils/request' + +// 保存金三角开卡业绩统计数据 +export function saveGoldTriangleStatistics(statisticsMonth) { + return request({ + url: '/api/Extend/LqStatistics/save-gold-triangle-stats', + method: 'POST', + data: { statisticsMonth } + }) +} + +// 保存健康师个人开单业绩统计数据 +export function savePersonalPerformanceStatistics(statisticsMonth) { + return request({ + url: '/api/Extend/LqStatistics/save-personal-performance-stats', + method: 'POST', + data: { statisticsMonth } + }) +} + +// 保存科技部开单业绩统计数据 +export function saveTechPerformanceStatistics(statisticsMonth) { + return request({ + url: '/api/Extend/LqStatistics/save-tech-performance-stats', + method: 'POST', + data: { statisticsMonth } + }) +} diff --git a/antis-ncc-admin/src/utils/define.js b/antis-ncc-admin/src/utils/define.js index 63c75ae..0b81f74 100644 --- a/antis-ncc-admin/src/utils/define.js +++ b/antis-ncc-admin/src/utils/define.js @@ -1,7 +1,7 @@ // 开发环境接口配置 // JAVA Boot版本对应后端接口地址 // JAVA Cloud对应网关地址 -const APIURl = 'http://localhost:8061' +const APIURl = 'http://localhost:2011' module.exports = { APIURl: APIURl, diff --git a/antis-ncc-admin/src/views/salaryCalculation/index.vue b/antis-ncc-admin/src/views/salaryCalculation/index.vue new file mode 100644 index 0000000..d52a753 --- /dev/null +++ b/antis-ncc-admin/src/views/salaryCalculation/index.vue @@ -0,0 +1,786 @@ + + + + + 工资计算与统计系统 + 智能生成各类业绩统计数据,一键完成工资计算 + + + + + + 选择统计月份 + 重置 + + + + + + + + + + + + + + + 一键计算工资 + + + 按顺序执行所有统计方法,生成完整的工资数据 + + + {{ isCalculating ? '计算中...' : '一键计算工资' }} + + + 计算进度: + + + + {{ step.name }} + + + + + + + + + + 单独统计操作 + + + + + + 金三角开卡业绩 + + + 立即统计 + + + + + + + 健康师个人开单业绩 + + + 立即统计 + + + + + + + 科技部开单业绩 + + + 立即统计 + + + + + + + + 更多统计方法 + + + 敬请期待 + + + + + + + + + + + 统计结果 + + + 导出 + + + 清空 + + + + + + + 暂无统计结果 + 请选择月份并点击上方按钮进行统计 + + + + + {{ result.title }} + {{ result.time }} + + {{ formatJson(result.data) }} + + + + + + + + + + + \ No newline at end of file diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdDeductinfo/LqKdDeductinfoCrInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdDeductinfo/LqKdDeductinfoCrInput.cs index 1c76346..9be1f65 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdDeductinfo/LqKdDeductinfoCrInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdDeductinfo/LqKdDeductinfoCrInput.cs @@ -9,6 +9,11 @@ namespace NCC.Extend.Entitys.Dto.LqKdDeductinfo public class LqKdDeductinfoCrInput { /// + /// 扣减编号 + /// + public string id { get; set; } + + /// /// 扣减类型 /// [Required(ErrorMessage = "扣减类型不能为空")] diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/SalaryStatisticsInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/SalaryStatisticsInput.cs new file mode 100644 index 0000000..d3787f8 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/SalaryStatisticsInput.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqStatistics +{ + /// + /// 工资统计输入参数 + /// + public class SalaryStatisticsInput + { + /// + /// 统计月份(YYYYMM格式) + /// + [Required(ErrorMessage = "统计月份不能为空")] + [StringLength(6, MinimumLength = 6, ErrorMessage = "统计月份格式错误,请使用YYYYMM格式")] + public string StatisticsMonth { get; set; } + } +} 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_kd_jksyj/LqKdJksyjEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_jksyj/LqKdJksyjEntity.cs index 7a75e90..441dbaa 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_jksyj/LqKdJksyjEntity.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_jksyj/LqKdJksyjEntity.cs @@ -64,5 +64,11 @@ namespace NCC.Extend.Entitys.lq_kd_jksyj /// [SugarColumn(ColumnName = "F_kdpxid")] public string Kdpxid { get; set; } + + /// + /// 是否有效 + /// + [SugarColumn(ColumnName = "F_IsEffective")] + public int IsEffective { get; set; } = 1; } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kdjlb/LqKdKdjlbEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kdjlb/LqKdKdjlbEntity.cs index d50cb3a..309e905 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kdjlb/LqKdKdjlbEntity.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kdjlb/LqKdKdjlbEntity.cs @@ -52,7 +52,7 @@ namespace NCC.Extend.Entitys.lq_kd_kdjlb /// [SugarColumn(ColumnName = "zdyj")] public decimal Zdyj { get; set; } - + /// /// 实付业绩 @@ -197,5 +197,12 @@ namespace NCC.Extend.Entitys.lq_kd_kdjlb /// [SugarColumn(ColumnName = "F_UpdateTime")] public DateTime UpdateTime { get; set; } + + /// + /// 是否有效 + /// + [SugarColumn(ColumnName = "F_IsEffective")] + public int IsEffective { get; set; } = 1; + } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kjbsyj/LqKdKjbsyjEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kjbsyj/LqKdKjbsyjEntity.cs index 4efc633..97cadbb 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kjbsyj/LqKdKjbsyjEntity.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kjbsyj/LqKdKjbsyjEntity.cs @@ -64,5 +64,11 @@ namespace NCC.Extend.Entitys.lq_kd_kjbsyj /// [SugarColumn(ColumnName = "F_LaborCost")] public decimal? LaborCost { get; set; } + + /// + /// 是否有效 + /// + [SugarColumn(ColumnName = "F_IsEffective")] + public int IsEffective { get; set; } = 1; } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_pxmx/LqKdPxmxEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_pxmx/LqKdPxmxEntity.cs index 791cefa..d4ec98a 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_pxmx/LqKdPxmxEntity.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_pxmx/LqKdPxmxEntity.cs @@ -82,5 +82,11 @@ namespace NCC.Extend.Entitys.lq_kd_pxmx /// [SugarColumn(ColumnName = "F_ActualPrice")] public decimal ActualPrice { get; set; } + + /// + /// 是否有效 + /// + [SugarColumn(ColumnName = "F_IsEffective")] + public int IsEffective { get; set; } = 1; } } 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/LqKdKdjlbService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs index 5ad398a..bed0bac 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs @@ -799,5 +799,270 @@ namespace NCC.Extend.LqKdKdjlb .ToList(); } #endregion + + #region 修改开单记录,不做删除,仅健康师业绩、科技部老师业绩信息 + /// + /// 修改开单记录,不做删除,仅健康师业绩、科技部老师业绩信息 + /// + /// + /// 更新开单记录及其关联的品项明细、健康师业绩、科技部老师业绩信息 + /// + /// 示例请求: + /// ```json + /// { + /// "id": "开单编号", + /// "djmd": "单据门店", + /// "jsj": "金三角", + /// "kdrq": "2025-01-11", + /// "lqKdPxmxList": [ + /// { + /// "px": "品项编号", + /// "pxmc": "品项名称", + /// "pxjg": 100.00, + /// "projectNumber": 1, + /// "sourceType": "购买", + /// "lqKdJksyjList": [ + /// { + /// "jks": "健康师", + /// "jksxm": "健康师姓名", + /// "jksyj": "100" + /// } + /// ] + /// } + /// ] + /// } + /// ``` + /// + /// 参数说明: + /// - id: 开单记录主键ID + /// - input: 开单记录更新参数,包含品项明细和业绩信息 + /// + /// 开单记录主键ID + /// 开单记录更新参数 + /// 无返回值 + /// 更新成功 + /// 参数错误或数据验证失败 + /// 服务器内部错误 + [HttpPut("UpdateForNoDelete/{id}")] + public async Task UpdateForNoDelete(string id, [FromBody] LqKdKdjlbUpInput input) + { + var entity = input.Adapt(); + entity.Id = id; // 确保ID正确设置 + + try + { + //开启事务 + _db.BeginTran(); + + // 更新开单记录主表 + await _db.Updateable(entity) + .IgnoreColumns(ignoreAllNullColumns: true) + .IgnoreColumns(x => x.CreateTime) // 不更新创建时间 + .ExecuteCommandAsync(); + + // 处理品项明细列表 - 更新或插入 + if (input.lqKdPxmxList != null && input.lqKdPxmxList.Any()) + { + foreach (var item in input.lqKdPxmxList) + { + // 检查品项明细是否已存在 + var existingPxmx = await _db.Queryable() + .Where(x => x.Glkdbh == id && x.Px == item.px) + .FirstAsync(); + + if (existingPxmx != null) + { + // 更新现有品项明细 + existingPxmx.ProjectNumber = item.projectNumber == 0 ? 1 : item.projectNumber; + existingPxmx.TotalPrice = (decimal)(item.pxjg * (item.projectNumber == 0 ? 1 : item.projectNumber)); + existingPxmx.Pxmc = item.pxmc; + existingPxmx.Pxjg = item.pxjg; + existingPxmx.SourceType = item.sourceType; + await _db.Updateable(existingPxmx).ExecuteCommandAsync(); + + // 更新该品项关联的健康师业绩 + if (item.lqKdJksyjList != null && item.lqKdJksyjList.Any()) + { + // 先删除该品项的所有健康师业绩 + await _db.Deleteable() + .Where(x => x.Kdpxid == existingPxmx.Id) + .ExecuteCommandAsync(); + + // 重新插入健康师业绩 + var jksyjEntities = item.lqKdJksyjList.Select(ijks_tem => new LqKdJksyjEntity + { + Id = YitIdHelper.NextId().ToString(), + Glkdbh = entity.Id, + Jks = ijks_tem.jks, + Jksxm = ijks_tem.jksxm, + Jkszh = ijks_tem.jkszh, + Jksyj = ijks_tem.jksyj, + Yjsj = DateTime.Now, + Jsj_id = ijks_tem.jsj_id, + Kdpxid = existingPxmx.Id, + }).ToList(); + + if (jksyjEntities.Any()) + { + await _db.Insertable(jksyjEntities).ExecuteCommandAsync(); + } + } + + // 更新该品项关联的科技部老师业绩 + if (item.lqKdKjbsyjList != null && item.lqKdKjbsyjList.Any()) + { + // 先删除该品项的所有科技部老师业绩 + await _db.Deleteable() + .Where(x => x.Kdpxid == existingPxmx.Id) + .ExecuteCommandAsync(); + + // 重新插入科技部老师业绩 + var kjbsyjEntities = item.lqKdKjbsyjList.Select(ikjbs_tem => new LqKdKjbsyjEntity + { + Id = YitIdHelper.NextId().ToString(), + Glkdbh = entity.Id, + Kjbls = ikjbs_tem.kjbls, + Kjblsxm = ikjbs_tem.kjblsxm, + Kjblszh = ikjbs_tem.kjblszh, + Kjblsyj = ikjbs_tem.kjblsyj, + Yjsj = DateTime.Now, + Kdpxid = existingPxmx.Id, + }).ToList(); + + if (kjbsyjEntities.Any()) + { + await _db.Insertable(kjbsyjEntities).ExecuteCommandAsync(); + } + } + } + else + { + // 插入新的品项明细 + var newPxmxEntity = new LqKdPxmxEntity + { + Id = YitIdHelper.NextId().ToString(), + Glkdbh = entity.Id, + CreateTIme = DateTime.Now, + MemberId = entity.Kdhy, + IsEnabled = 0, + ProjectNumber = item.projectNumber == 0 ? 1 : item.projectNumber, + TotalPrice = (decimal)(item.pxjg * (item.projectNumber == 0 ? 1 : item.projectNumber)), + Px = item.px, + Pxmc = item.pxmc, + Pxjg = item.pxjg, + SourceType = item.sourceType, + }; + await _db.Insertable(newPxmxEntity).ExecuteCommandAsync(); + + // 插入该品项关联的健康师业绩 + if (item.lqKdJksyjList != null && item.lqKdJksyjList.Any()) + { + var jksyjEntities = item.lqKdJksyjList.Select(ijks_tem => new LqKdJksyjEntity + { + Id = YitIdHelper.NextId().ToString(), + Glkdbh = entity.Id, + Jks = ijks_tem.jks, + Jksxm = ijks_tem.jksxm, + Jkszh = ijks_tem.jkszh, + Jksyj = ijks_tem.jksyj, + Yjsj = DateTime.Now, + Jsj_id = ijks_tem.jsj_id, + Kdpxid = newPxmxEntity.Id, + }).ToList(); + + await _db.Insertable(jksyjEntities).ExecuteCommandAsync(); + } + + // 插入该品项关联的科技部老师业绩 + if (item.lqKdKjbsyjList != null && item.lqKdKjbsyjList.Any()) + { + var kjbsyjEntities = item.lqKdKjbsyjList.Select(ikjbs_tem => new LqKdKjbsyjEntity + { + Id = YitIdHelper.NextId().ToString(), + Glkdbh = entity.Id, + Kjbls = ikjbs_tem.kjbls, + Kjblsxm = ikjbs_tem.kjblsxm, + Kjblszh = ikjbs_tem.kjblszh, + Kjblsyj = ikjbs_tem.kjblsyj, + Yjsj = DateTime.Now, + Kdpxid = newPxmxEntity.Id, + }).ToList(); + + await _db.Insertable(kjbsyjEntities).ExecuteCommandAsync(); + } + } + } + } + + //关闭事务 + _db.CommitTran(); + } + catch (Exception) + { + //回滚事务 + _db.RollbackTran(); + throw NCCException.Oh(ErrorCode.COM1001); + } + } + #endregion + + #region 作废开单记录 + /// + /// 作废开单记录 + /// + /// 开单记录主键ID + /// 无返回值 + /// 作废成功 + /// 参数错误,开单记录ID不能为空 + /// 开单记录不存在 + /// 服务器内部错误 + [HttpPut("Cancel/{id}")] + public async Task Cancel(string id) + { + if (string.IsNullOrEmpty(id)) + { + throw NCCException.Oh("开单记录ID不能为空"); + } + + try + { + //开启事务 + _db.BeginTran(); + + // 查询开单记录 + var entity = await _db.Queryable().FirstAsync(p => p.Id == id); + if (entity == null) + { + throw NCCException.Oh("开单记录不存在"); + } + + // 检查是否已经作废 + if (entity.IsEffective == 0) + { + throw NCCException.Oh("该开单记录已经作废"); + } + + // 标记开单记录为无效 + entity.IsEffective = 0; + await _db.Updateable(entity).ExecuteCommandAsync(); + // 标记对应开单明细表为无效 + await _db.Updateable().SetColumns(it => new LqKdPxmxEntity { IsEffective = 0 }).Where(it => it.Glkdbh == id).ExecuteCommandAsync(); + // 标记健康师业绩为无效 + await _db.Updateable().SetColumns(it => new LqKdJksyjEntity { IsEffective = 0 }).Where(it => it.Glkdbh == id).ExecuteCommandAsync(); + // 标记科技部老师业绩为无效 + await _db.Updateable().SetColumns(it => new LqKdKjbsyjEntity { IsEffective = 0 }).Where(it => it.Glkdbh == id).ExecuteCommandAsync(); + //关闭事务 + _db.CommitTran(); + } + catch (Exception ex) when (!(ex is NCCException)) + { + //回滚事务 + _db.RollbackTran(); + throw NCCException.Oh(ErrorCode.COM1001); + } + } + #endregion + + } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs index 1d80468..c905dc6 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】保存金三角开卡业绩统计数据 /// /// /// 根据金三角设定和开单记录统计金三角的业绩数据 @@ -1209,14 +1211,16 @@ namespace NCC.Extend.LqStatistics /// 成功保存统计数据 /// 参数错误 /// 服务器内部错误 - [HttpPost("save-gold-triangle-statistics")] - public async Task SaveGoldTriangleStatistics(string statisticsMonth) + [HttpPost("save-gold-triangle-stats")] + public async Task SaveGoldTriangleStatistics([FromBody] SalaryStatisticsInput input) { - if (string.IsNullOrEmpty(statisticsMonth) || statisticsMonth.Length != 6) + if (input == null || string.IsNullOrEmpty(input.StatisticsMonth) || input.StatisticsMonth.Length != 6) { throw NCCException.Oh("统计月份格式错误,请使用YYYYMM格式"); } + var statisticsMonth = input.StatisticsMonth; + try { // 使用数据库聚合方式,直接在数据库中完成所有统计计算 @@ -1236,6 +1240,7 @@ namespace NCC.Extend.LqStatistics jsj.F_Id = jksyj.jsj_id AND YEAR(jksyj.yjsj) = SUBSTRING(jsj.yf, 1, 4) AND MONTH(jksyj.yjsj) = SUBSTRING(jsj.yf, 5, 2) + AND jksyj.F_IsEffective = 1 ) LEFT JOIN lq_mdxx md ON jsj.md = md.F_Id WHERE jsj.yf = @statisticsMonth @@ -1366,7 +1371,7 @@ namespace NCC.Extend.LqStatistics #region 个人开单业绩统计 /// - /// 保存个人开单业绩统计数据 + /// 【2】保存健康师个人开单业绩统计数据 /// /// /// 根据开单记录统计个人的业绩数据,包括基础业绩和合作业绩 @@ -1386,14 +1391,16 @@ namespace NCC.Extend.LqStatistics /// 成功保存统计数据 /// 参数错误 /// 服务器内部错误 - [HttpPost("save-personal-performance-statistics")] - public async Task SavePersonalPerformanceStatistics(string statisticsMonth) + [HttpPost("save-personal-performance-stats")] + public async Task SavePersonalPerformanceStatistics([FromBody] SalaryStatisticsInput input) { - if (string.IsNullOrEmpty(statisticsMonth) || statisticsMonth.Length != 6) + if (input == null || string.IsNullOrEmpty(input.StatisticsMonth) || input.StatisticsMonth.Length != 6) { throw NCCException.Oh("统计月份格式错误,请使用YYYYMM格式"); } + var statisticsMonth = input.StatisticsMonth; + try { // 使用数据库聚合方式,直接在数据库中完成所有统计计算 @@ -1427,7 +1434,7 @@ namespace NCC.Extend.LqStatistics ) AS BasePerformance, SUM(CAST(jksyj.jksyj AS DECIMAL(18,2))) AS TotalPerformance FROM lq_kd_jksyj jksyj - INNER JOIN lq_kd_pxmx pxmx ON jksyj.F_kdpxid = pxmx.F_Id + INNER JOIN lq_kd_pxmx pxmx ON jksyj.F_kdpxid = pxmx.F_Id AND pxmx.F_IsEffective = 1 INNER JOIN lq_xmzl xmzl ON pxmx.px = xmzl.F_Id INNER JOIN BASE_USER u ON jksyj.jkszh = u.F_Id LEFT JOIN lq_mdxx md ON u.F_MDID = md.F_Id @@ -1444,6 +1451,7 @@ namespace NCC.Extend.LqStatistics AND jksyj.jksyj != '0' AND jksyj.F_kdpxid IS NOT NULL AND jksyj.F_kdpxid != '' + AND jksyj.F_IsEffective = 1 AND YEAR(jksyj.yjsj) = @year AND MONTH(jksyj.yjsj) = @month GROUP BY @@ -1634,6 +1642,246 @@ namespace NCC.Extend.LqStatistics #endregion + #region 科技部开单业绩统计 + + /// + /// 【3】保存科技部开单业绩统计数据 + /// + /// + /// 根据指定月份统计科技部老师的开单业绩数据,只统计开卡业绩,不包含耗卡和退卡业绩 + /// + /// 示例请求: + /// ```json + /// POST /api/Extend/LqStatistics/save-tech-performance-statistics + /// { + /// "statisticsMonth": "202401" + /// } + /// ``` + /// + /// 参数说明: + /// - statisticsMonth: 统计月份,格式为YYYYMM + /// + /// 统计月份(YYYYMM格式) + /// 保存结果 + /// 成功保存统计数据 + /// 参数错误 + /// 服务器内部错误 + [HttpPost("save-tech-performance-stats")] + public async Task SaveTechPerformanceStatistics([FromBody] SalaryStatisticsInput input) + { + if (input == null || string.IsNullOrEmpty(input.StatisticsMonth) || input.StatisticsMonth.Length != 6) + { + throw NCCException.Oh("统计月份格式错误,请使用YYYYMM格式"); + } + + var statisticsMonth = input.StatisticsMonth; + + 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 AND pm.F_IsEffective = 1 + 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 k.F_IsEffective = 1 + 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 + /// /// 部门信息 /// @@ -1654,5 +1902,6 @@ namespace NCC.Extend.LqStatistics /// public string ParentId { get; set; } } + } } 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
智能生成各类业绩统计数据,一键完成工资计算
按顺序执行所有统计方法,生成完整的工资数据
暂无统计结果
请选择月份并点击上方按钮进行统计
{{ formatJson(result.data) }}