Commit 5e629136e080a69f32ab6118c6535fc3abaec34e

Authored by “wangming”
1 parent 45c3414e

feat: 添加开单服务根据健康师和科技部老师ID查询功能,返回健康师和科技部老师业绩数据;添加经理类型枚举;优化经理业绩完成情况查询逻辑

netcore/src/Modularity/Common/NCC.Common/Extension/Ext.cs
... ... @@ -808,7 +808,7 @@ namespace NCC.Common.Extension
808 808 }
809 809  
810 810 #endregion
811   -
  811 +
812 812 /// <summary>
813 813 /// 元转分
814 814 /// </summary>
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListByJksQueryInput.cs 0 → 100644
  1 +using NCC.Common.Filter;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.LqKdKdjlb
  4 +{
  5 + /// <summary>
  6 + /// 根据健康师ID查询开单列表输入
  7 + /// </summary>
  8 + public class LqKdKdjlbListByJksQueryInput : PageInputBase
  9 + {
  10 + /// <summary>
  11 + /// 健康师ID(必填)
  12 + /// </summary>
  13 + public string jksId { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  17 + /// </summary>
  18 + public string startTime { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  22 + /// </summary>
  23 + public string endTime { get; set; }
  24 +
  25 + /// <summary>
  26 + /// 门店ID(可选)
  27 + /// </summary>
  28 + public string djmd { get; set; }
  29 +
  30 + /// <summary>
  31 + /// 是否有效(可选,0=全部,1=有效,2=无效,默认1)
  32 + /// </summary>
  33 + public int isEffective { get; set; } = 1;
  34 + }
  35 +}
  36 +
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListByKjbQueryInput.cs 0 → 100644
  1 +using NCC.Common.Filter;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.LqKdKdjlb
  4 +{
  5 + /// <summary>
  6 + /// 根据科技部老师ID查询开单列表输入
  7 + /// </summary>
  8 + public class LqKdKdjlbListByKjbQueryInput : PageInputBase
  9 + {
  10 + /// <summary>
  11 + /// 科技部老师ID(必填)
  12 + /// </summary>
  13 + public string kjblsId { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  17 + /// </summary>
  18 + public string startTime { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  22 + /// </summary>
  23 + public string endTime { get; set; }
  24 +
  25 + /// <summary>
  26 + /// 门店ID(可选)
  27 + /// </summary>
  28 + public string djmd { get; set; }
  29 +
  30 + /// <summary>
  31 + /// 是否有效(可选,0=全部,1=有效,2=无效,默认1)
  32 + /// </summary>
  33 + public int isEffective { get; set; } = 1;
  34 + }
  35 +}
  36 +
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListOutput.cs
... ... @@ -170,5 +170,15 @@ namespace NCC.Extend.Entitys.Dto.LqKdKdjlb
170 170 /// 开单品项明细列表
171 171 /// </summary>
172 172 public List<LqKdPxmxInfoOutput> ItemDetails { get; set; }
  173 +
  174 + /// <summary>
  175 + /// 健康师业绩列表
  176 + /// </summary>
  177 + public List<LqKdJksyjInfoOutput> lqKdJksyjList { get; set; }
  178 +
  179 + /// <summary>
  180 + /// 科技部老师业绩列表
  181 + /// </summary>
  182 + public List<LqKdKjbsyjInfoOutput> lqKdKjbsyjList { get; set; }
173 183 }
174 184 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbListQueryInput.cs
... ... @@ -139,5 +139,14 @@ namespace NCC.Extend.Entitys.Dto.LqKdKdjlb
139 139 /// </summary>
140 140 public int isEffective { get; set; } = 0;
141 141  
  142 + /// <summary>
  143 + /// 健康师ID(可选,传入后只返回该健康师参与的开单记录)
  144 + /// </summary>
  145 + public string jksId { get; set; }
  146 +
  147 + /// <summary>
  148 + /// 科技部老师ID(可选,传入后只返回该老师参与的开单记录)
  149 + /// </summary>
  150 + public string kjblsId { get; set; }
142 151 }
143 152 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineCrInput.cs
... ... @@ -28,6 +28,12 @@ namespace NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline
28 28 public string generalManagerId { get; set; }
29 29  
30 30 /// <summary>
  31 + /// 经理类型(0=经理,1=总经理)
  32 + /// </summary>
  33 + [Required(ErrorMessage = "经理类型不能为空")]
  34 + public int managerType { get; set; } = 1;
  35 +
  36 + /// <summary>
31 37 /// 生命线1
32 38 /// </summary>
33 39 [Required(ErrorMessage = "生命线1不能为空")]
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineInfoOutput.cs
... ... @@ -28,6 +28,11 @@ namespace NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline
28 28 public string generalManagerId { get; set; }
29 29  
30 30 /// <summary>
  31 + /// 经理类型(0=经理,1=总经理)
  32 + /// </summary>
  33 + public int managerType { get; set; }
  34 +
  35 + /// <summary>
31 36 /// 生命线1
32 37 /// </summary>
33 38 public decimal lifeline1 { get; set; }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineListOutput.cs
... ... @@ -28,6 +28,16 @@ namespace NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline
28 28 public string generalManagerId { get; set; }
29 29  
30 30 /// <summary>
  31 + /// 经理类型(0=经理,1=总经理)
  32 + /// </summary>
  33 + public int managerType { get; set; }
  34 +
  35 + /// <summary>
  36 + /// 经理类型(0=经理,1=总经理)
  37 + /// </summary>
  38 + public string managerTypeName { get; set; }
  39 +
  40 + /// <summary>
31 41 /// 生命线1
32 42 /// </summary>
33 43 public decimal lifeline1 { get; set; }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdGeneralManagerLifeline/LqMdGeneralManagerLifelineUpInput.cs
... ... @@ -28,6 +28,12 @@ namespace NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline
28 28 public string generalManagerId { get; set; }
29 29  
30 30 /// <summary>
  31 + /// 经理类型(0=经理,1=总经理)
  32 + /// </summary>
  33 + [Required(ErrorMessage = "经理类型不能为空")]
  34 + public int managerType { get; set; } = 1;
  35 +
  36 + /// <summary>
31 37 /// 生命线1
32 38 /// </summary>
33 39 [Required(ErrorMessage = "生命线1不能为空")]
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_general_manager_lifeline/LqMdGeneralManagerLifelineEntity.cs
... ... @@ -36,6 +36,12 @@ namespace NCC.Extend.Entitys.lq_md_general_manager_lifeline
36 36 public string GeneralManagerId { get; set; }
37 37  
38 38 /// <summary>
  39 + /// 经理类型(0=经理,1=总经理)
  40 + /// </summary>
  41 + [SugarColumn(ColumnName = "F_ManagerType")]
  42 + public int ManagerType { get; set; } = 1;
  43 +
  44 + /// <summary>
39 45 /// 生命线1
40 46 /// </summary>
41 47 [SugarColumn(ColumnName = "F_Lifeline1")]
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Enum/ManagerTypeEnum.cs 0 → 100644
  1 +using System.ComponentModel;
  2 +
  3 +namespace NCC.Extend.Entitys.Enum
  4 +{
  5 + /// <summary>
  6 + /// 经理类型枚举
  7 + /// </summary>
  8 + public enum ManagerTypeEnum
  9 + {
  10 + /// <summary>
  11 + /// 经理
  12 + /// </summary>
  13 + [Description("经理")]
  14 + 经理 = 0,
  15 +
  16 + /// <summary>
  17 + /// 总经理
  18 + /// </summary>
  19 + [Description("总经理")]
  20 + 总经理 = 1,
  21 + }
  22 +}
  23 +
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs
... ... @@ -752,7 +752,7 @@ namespace NCC.Extend
752 752 managerFilter = $"AND target.F_GeneralManagerId = '{input.ManagerId}'";
753 753 }
754 754  
755   - // SQL查询:获取经理汇总业绩
  755 + // SQL查询:获取经理汇总业绩(基于lq_md_general_manager_lifeline表中的经理和门店关系)
756 756 var sql = $@"
757 757 SELECT
758 758 target.F_GeneralManagerId as ManagerId,
... ... @@ -761,7 +761,7 @@ namespace NCC.Extend
761 761 COALESCE(SUM(target.F_Lifeline2), 0) as TotalTarget2,
762 762 COALESCE(SUM(target.F_Lifeline3), 0) as TotalTarget3,
763 763 COUNT(DISTINCT target.F_StoreId) as StoreCount,
764   - -- 总完成业绩
  764 + -- 总完成业绩(基于lq_md_general_manager_lifeline表中的门店关系计算)
765 765 SUM(COALESCE((
766 766 SELECT SUM(billing.sfyj)
767 767 FROM lq_kd_kdjlb billing
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
... ... @@ -214,8 +214,49 @@ namespace NCC.Extend.LqKdKdjlb
214 214 List<string> queryKdrq = input.kdrq != null ? input.kdrq.Split(',').ToObeject<List<string>>() : null;
215 215 DateTime? startKdrq = queryKdrq != null ? Ext.GetDateTime(queryKdrq.First()) : null;
216 216 DateTime? endKdrq = queryKdrq != null ? Ext.GetDateTime(queryKdrq.Last()) : null;
217   - var data = await _db.Queryable<LqKdKdjlbEntity>()
218   - .WhereIF(!string.IsNullOrEmpty(input.keyword), p => p.Kdhyc.Contains(input.keyword) || p.Kdhysjh.Contains(input.keyword))
  217 +
  218 + // 根据是否传入健康师ID或科技部老师ID,动态构建查询
  219 + ISugarQueryable<LqKdKdjlbEntity> baseQuery = null;
  220 +
  221 + if (!string.IsNullOrEmpty(input.jksId) && !string.IsNullOrEmpty(input.kjblsId))
  222 + {
  223 + // 同时传入健康师ID和科技部老师ID,需要同时关联两个业绩表
  224 + baseQuery = _db.Queryable<LqKdJksyjEntity, LqKdKjbsyjEntity, LqKdKdjlbEntity>(
  225 + (jksyj, kjbsyj, kdjlb) => jksyj.Glkdbh == kdjlb.Id && kjbsyj.Glkdbh == kdjlb.Id)
  226 + .Where((jksyj, kjbsyj, kdjlb) => jksyj.Jkszh == input.jksId && jksyj.IsEffective == StatusEnum.有效.GetHashCode())
  227 + .Where((jksyj, kjbsyj, kdjlb) => kjbsyj.Kjbls == input.kjblsId && kjbsyj.IsEffective == StatusEnum.有效.GetHashCode())
  228 + .Select((jksyj, kjbsyj, kdjlb) => kdjlb)
  229 + .Distinct()
  230 + .MergeTable();
  231 + }
  232 + else if (!string.IsNullOrEmpty(input.jksId))
  233 + {
  234 + // 只传入健康师ID,关联健康师业绩表
  235 + baseQuery = _db.Queryable<LqKdJksyjEntity, LqKdKdjlbEntity>(
  236 + (jksyj, kdjlb) => jksyj.Glkdbh == kdjlb.Id)
  237 + .Where((jksyj, kdjlb) => jksyj.Jkszh == input.jksId && jksyj.IsEffective == StatusEnum.有效.GetHashCode())
  238 + .Select((jksyj, kdjlb) => kdjlb)
  239 + .Distinct()
  240 + .MergeTable();
  241 + }
  242 + else if (!string.IsNullOrEmpty(input.kjblsId))
  243 + {
  244 + // 只传入科技部老师ID,关联科技部老师业绩表
  245 + baseQuery = _db.Queryable<LqKdKjbsyjEntity, LqKdKdjlbEntity>(
  246 + (kjbsyj, kdjlb) => kjbsyj.Glkdbh == kdjlb.Id)
  247 + .Where((kjbsyj, kdjlb) => kjbsyj.Kjbls == input.kjblsId && kjbsyj.IsEffective == StatusEnum.有效.GetHashCode())
  248 + .Select((kjbsyj, kdjlb) => kdjlb)
  249 + .Distinct()
  250 + .MergeTable();
  251 + }
  252 + else
  253 + {
  254 + // 没有传入健康师ID或科技部老师ID,使用原来的查询逻辑
  255 + baseQuery = _db.Queryable<LqKdKdjlbEntity>();
  256 + }
  257 +
  258 + var data = await baseQuery
  259 + .WhereIF(!string.IsNullOrEmpty(input.keyword), p => p.Kdhyc.Contains(input.keyword) || p.Kdhysjh.Contains(input.keyword))
219 260 .WhereIF(!string.IsNullOrEmpty(input.id), p => p.Id.Contains(input.id))
220 261 .WhereIF(!string.IsNullOrEmpty(input.djmd), p => p.Djmd.Equals(input.djmd))
221 262 .WhereIF(!string.IsNullOrEmpty(input.jsj), p => p.Jsj.Equals(input.jsj))
... ... @@ -308,18 +349,383 @@ namespace NCC.Extend.LqKdKdjlb
308 349 var itemDetailsGrouped = itemDetails.GroupBy(x => x.glkdbh)
309 350 .ToDictionary(g => g.Key, g => g.ToList());
310 351  
311   - // 为每个开单记录分配品项明细
  352 + // 批量查询健康师业绩(性能优化:一次性查询所有开单的健康师业绩)
  353 + var jksyjList = new List<LqKdJksyjInfoOutput>();
  354 + if (billingIds.Any())
  355 + {
  356 + jksyjList = await _db.Queryable<LqKdJksyjEntity>()
  357 + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode())
  358 + .Select(x => new LqKdJksyjInfoOutput
  359 + {
  360 + id = x.Id,
  361 + glkdbh = x.Glkdbh,
  362 + kdpxid = x.Kdpxid,
  363 + jks = x.Jks,
  364 + jksxm = x.Jksxm,
  365 + jkszh = x.Jkszh,
  366 + jksyj = x.Jksyj,
  367 + yjsj = x.Yjsj,
  368 + jsj_id = x.Jsj_id,
  369 + isEffective = x.IsEffective
  370 + })
  371 + .ToListAsync();
  372 + }
  373 +
  374 + // 批量查询科技部老师业绩(性能优化:一次性查询所有开单的科技部老师业绩)
  375 + var kjbsyjList = new List<LqKdKjbsyjInfoOutput>();
  376 + if (billingIds.Any())
  377 + {
  378 + kjbsyjList = await _db.Queryable<LqKdKjbsyjEntity>()
  379 + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode())
  380 + .Select(x => new LqKdKjbsyjInfoOutput
  381 + {
  382 + id = x.Id,
  383 + glkdbh = x.Glkdbh,
  384 + kdpxid = x.Kdpxid,
  385 + kjbls = x.Kjbls,
  386 + kjblsxm = x.Kjblsxm,
  387 + kjblszh = x.Kjblszh,
  388 + kjblsyj = x.Kjblsyj,
  389 + yjsj = x.Yjsj,
  390 + isEffective = x.IsEffective
  391 + })
  392 + .ToListAsync();
  393 + }
  394 +
  395 + // 按开单ID分组健康师业绩
  396 + var jksyjGrouped = jksyjList.GroupBy(x => x.glkdbh)
  397 + .ToDictionary(g => g.Key, g => g.ToList());
  398 +
  399 + // 按开单ID分组科技部老师业绩
  400 + var kjbsyjGrouped = kjbsyjList.GroupBy(x => x.glkdbh)
  401 + .ToDictionary(g => g.Key, g => g.ToList());
  402 +
  403 + // 为每个开单记录分配品项明细、健康师业绩和科技部老师业绩
312 404 foreach (var item in data.list)
313 405 {
314 406 item.ItemDetails = itemDetailsGrouped.ContainsKey(item.id)
315 407 ? itemDetailsGrouped[item.id]
316 408 : new List<LqKdPxmxInfoOutput>();
  409 + item.lqKdJksyjList = jksyjGrouped.ContainsKey(item.id)
  410 + ? jksyjGrouped[item.id]
  411 + : new List<LqKdJksyjInfoOutput>();
  412 + item.lqKdKjbsyjList = kjbsyjGrouped.ContainsKey(item.id)
  413 + ? kjbsyjGrouped[item.id]
  414 + : new List<LqKdKjbsyjInfoOutput>();
317 415 }
318 416  
319 417 return PageResult<LqKdKdjlbListOutput>.SqlSugarPageResult(data);
320 418 }
321 419 #endregion
322 420  
  421 + #region 根据健康师ID获取开单列表
  422 + /// <summary>
  423 + /// 根据健康师ID获取开单列表
  424 + /// </summary>
  425 + /// <remarks>
  426 + /// 根据健康师ID查询该健康师参与的所有开单记录,支持时间周期查询和分页
  427 + ///
  428 + /// 示例请求:
  429 + /// GET /api/Extend/LqKdKdjlb/GetListByJksId?jksId=健康师ID&amp;startTime=2025-01-01&amp;endTime=2025-01-31&amp;currentPage=1&amp;pageSize=10
  430 + ///
  431 + /// 参数说明:
  432 + /// - jksId: 健康师ID(必填)
  433 + /// - startTime: 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  434 + /// - endTime: 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  435 + /// - djmd: 门店ID(可选)
  436 + /// - isEffective: 是否有效(可选,0=全部,1=有效,2=无效,默认1)
  437 + /// - currentPage: 当前页码(必填)
  438 + /// - pageSize: 每页数量(必填)
  439 + ///
  440 + /// 返回说明:
  441 + /// - 返回格式与GetList接口相同,包含开单基本信息及品项明细列表
  442 + /// </remarks>
  443 + /// <param name="input">查询参数</param>
  444 + /// <returns>开单列表(分页)</returns>
  445 + /// <response code="200">查询成功</response>
  446 + /// <response code="400">参数错误</response>
  447 + /// <response code="500">服务器内部错误</response>
  448 + [HttpGet("GetListByJksId")]
  449 + public async Task<dynamic> GetListByJksId([FromQuery] LqKdKdjlbListByJksQueryInput input)
  450 + {
  451 + try
  452 + {
  453 + if (string.IsNullOrEmpty(input.jksId))
  454 + {
  455 + throw NCCException.Oh("健康师ID不能为空");
  456 + }
  457 +
  458 + var sidx = input.sidx == null ? "kdrq" : input.sidx;
  459 + var sort = string.IsNullOrEmpty(input.sort) ? "DESC" : input.sort;
  460 +
  461 + // 解析时间范围
  462 + DateTime? startDate = null;
  463 + DateTime? endDate = null;
  464 + if (!string.IsNullOrEmpty(input.startTime))
  465 + {
  466 + startDate = Ext.GetDateTime(input.startTime);
  467 + }
  468 + if (!string.IsNullOrEmpty(input.endTime))
  469 + {
  470 + endDate = Ext.GetDateTime(input.endTime);
  471 + // 如果只传了日期,则设置为当天的23:59:59
  472 + if (endDate.HasValue && !input.endTime.Contains(":"))
  473 + {
  474 + endDate = new DateTime(endDate.Value.Year, endDate.Value.Month, endDate.Value.Day, 23, 59, 59);
  475 + }
  476 + }
  477 +
  478 + // 通过健康师业绩表关联查询开单记录
  479 + var data = await _db.Queryable<LqKdJksyjEntity, LqKdKdjlbEntity>(
  480 + (jksyj, kdjlb) => jksyj.Glkdbh == kdjlb.Id)
  481 + .Where((jksyj, kdjlb) => jksyj.Jkszh == input.jksId)
  482 + .WhereIF(input.isEffective != 0, (jksyj, kdjlb) => jksyj.IsEffective == input.isEffective && kdjlb.IsEffective == input.isEffective)
  483 + .WhereIF(input.isEffective == 0, (jksyj, kdjlb) => jksyj.IsEffective == StatusEnum.有效.GetHashCode() && kdjlb.IsEffective == StatusEnum.有效.GetHashCode())
  484 + .WhereIF(startDate.HasValue, (jksyj, kdjlb) => kdjlb.Kdrq >= startDate.Value)
  485 + .WhereIF(endDate.HasValue, (jksyj, kdjlb) => kdjlb.Kdrq <= endDate.Value)
  486 + .WhereIF(!string.IsNullOrEmpty(input.djmd), (jksyj, kdjlb) => kdjlb.Djmd == input.djmd)
  487 + .Select((jksyj, kdjlb) => new LqKdKdjlbListOutput
  488 + {
  489 + id = kdjlb.Id,
  490 + djmd = kdjlb.Djmd,
  491 + jsj = kdjlb.Jsj,
  492 + kdrq = kdjlb.Kdrq,
  493 + gjlx = kdjlb.Gjlx,
  494 + hgjg = kdjlb.Hgjg,
  495 + zdyj = kdjlb.Zdyj,
  496 + sfyj = kdjlb.Sfyj,
  497 + qk = kdjlb.Qk,
  498 + ckfs = kdjlb.Ckfs,
  499 + fkfs = kdjlb.Fkfs,
  500 + fkyy = kdjlb.Fkyy,
  501 + fkpd = kdjlb.Fkpd,
  502 + khly = kdjlb.Khly,
  503 + tjr = kdjlb.Tjr,
  504 + deductAmount = kdjlb.DeductAmount,
  505 + paidDebt = kdjlb.PaidDebt,
  506 + supplementBillingId = kdjlb.SupplementBillingId,
  507 + sfskdd = kdjlb.Sfskdd,
  508 + jj = kdjlb.Jj,
  509 + bz = kdjlb.Bz,
  510 + kdhy = kdjlb.Kdhy,
  511 + kdhyc = SqlFunc.Subqueryable<LqKhxxEntity>().Where(x => x.Id == kdjlb.Kdhy).Select(x => x.Khmc),
  512 + kdhysjh = SqlFunc.Subqueryable<LqKhxxEntity>().Where(x => x.Id == kdjlb.Kdhy).Select(x => x.Sjh),
  513 + isEffective = kdjlb.IsEffective,
  514 + createUser = kdjlb.CreateUser,
  515 + createUserName = SqlFunc.Subqueryable<UserEntity>().Where(x => x.Id == kdjlb.CreateUser).Select(x => x.RealName),
  516 + activityId = kdjlb.ActivityId,
  517 + activityName = SqlFunc.Subqueryable<LqPackageInfoEntity>().Where(x => x.Id == kdjlb.ActivityId).Select(x => x.ActivityName),
  518 + })
  519 + .MergeTable()
  520 + .Distinct() // 去重,因为一个开单可能对应多个健康师业绩记录
  521 + .OrderBy($"{sidx} {sort}")
  522 + .ToPagedListAsync(input.currentPage, input.pageSize);
  523 +
  524 + // 获取当前页的开单记录ID列表
  525 + var billingIds = data.list.Select(x => x.id).ToList();
  526 +
  527 + // 批量查询品项明细
  528 + var itemDetails = new List<LqKdPxmxInfoOutput>();
  529 + if (billingIds.Any())
  530 + {
  531 + itemDetails = await _db.Queryable<LqKdPxmxEntity>()
  532 + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode())
  533 + .Select(x => new LqKdPxmxInfoOutput
  534 + {
  535 + id = x.Id,
  536 + glkdbh = x.Glkdbh,
  537 + px = x.Px,
  538 + pxmc = x.Pxmc,
  539 + pxjg = x.Pxjg,
  540 + projectNumber = x.ProjectNumber,
  541 + isEnabled = x.IsEnabled,
  542 + sourceType = x.SourceType,
  543 + memberId = x.MemberId,
  544 + createTime = x.CreateTIme,
  545 + totalPrice = x.TotalPrice,
  546 + actualPrice = x.ActualPrice,
  547 + remark = x.Remark,
  548 + isEffective = x.IsEffective
  549 + })
  550 + .ToListAsync();
  551 + }
  552 +
  553 + // 按开单ID分组品项明细
  554 + var itemDetailsGrouped = itemDetails.GroupBy(x => x.glkdbh)
  555 + .ToDictionary(g => g.Key, g => g.ToList());
  556 +
  557 + // 为每个开单记录分配品项明细
  558 + foreach (var item in data.list)
  559 + {
  560 + item.ItemDetails = itemDetailsGrouped.ContainsKey(item.id)
  561 + ? itemDetailsGrouped[item.id]
  562 + : new List<LqKdPxmxInfoOutput>();
  563 + }
  564 +
  565 + return PageResult<LqKdKdjlbListOutput>.SqlSugarPageResult(data);
  566 + }
  567 + catch (Exception ex)
  568 + {
  569 + _logger.LogError(ex, $"根据健康师ID获取开单列表失败 - 健康师ID: {input?.jksId}, 开始时间: {input?.startTime}, 结束时间: {input?.endTime}");
  570 + throw NCCException.Oh($"根据健康师ID获取开单列表失败: {ex.Message}");
  571 + }
  572 + }
  573 + #endregion
  574 +
  575 + #region 根据科技部老师ID获取开单列表
  576 + /// <summary>
  577 + /// 根据科技部老师ID获取开单列表
  578 + /// </summary>
  579 + /// <remarks>
  580 + /// 根据科技部老师ID查询该老师参与的所有开单记录,支持时间周期查询和分页
  581 + ///
  582 + /// 示例请求:
  583 + /// GET /api/Extend/LqKdKdjlb/GetListByKjbId?kjblsId=科技部老师ID&amp;startTime=2025-01-01&amp;endTime=2025-01-31&amp;currentPage=1&amp;pageSize=10
  584 + ///
  585 + /// 参数说明:
  586 + /// - kjblsId: 科技部老师ID(必填)
  587 + /// - startTime: 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  588 + /// - endTime: 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss)
  589 + /// - djmd: 门店ID(可选)
  590 + /// - isEffective: 是否有效(可选,0=全部,1=有效,2=无效,默认1)
  591 + /// - currentPage: 当前页码(必填)
  592 + /// - pageSize: 每页数量(必填)
  593 + ///
  594 + /// 返回说明:
  595 + /// - 返回格式与GetList接口相同,包含开单基本信息及品项明细列表
  596 + /// </remarks>
  597 + /// <param name="input">查询参数</param>
  598 + /// <returns>开单列表(分页)</returns>
  599 + /// <response code="200">查询成功</response>
  600 + /// <response code="400">参数错误</response>
  601 + /// <response code="500">服务器内部错误</response>
  602 + [HttpGet("GetListByKjbId")]
  603 + public async Task<dynamic> GetListByKjbId([FromQuery] LqKdKdjlbListByKjbQueryInput input)
  604 + {
  605 + try
  606 + {
  607 + if (string.IsNullOrEmpty(input.kjblsId))
  608 + {
  609 + throw NCCException.Oh("科技部老师ID不能为空");
  610 + }
  611 +
  612 + var sidx = input.sidx == null ? "kdrq" : input.sidx;
  613 + var sort = string.IsNullOrEmpty(input.sort) ? "DESC" : input.sort;
  614 +
  615 + // 解析时间范围
  616 + DateTime? startDate = null;
  617 + DateTime? endDate = null;
  618 + if (!string.IsNullOrEmpty(input.startTime))
  619 + {
  620 + startDate = Ext.GetDateTime(input.startTime);
  621 + }
  622 + if (!string.IsNullOrEmpty(input.endTime))
  623 + {
  624 + endDate = Ext.GetDateTime(input.endTime);
  625 + // 如果只传了日期,则设置为当天的23:59:59
  626 + if (endDate.HasValue && !input.endTime.Contains(":"))
  627 + {
  628 + endDate = new DateTime(endDate.Value.Year, endDate.Value.Month, endDate.Value.Day, 23, 59, 59);
  629 + }
  630 + }
  631 +
  632 + // 通过科技部老师业绩表关联查询开单记录
  633 + var data = await _db.Queryable<LqKdKjbsyjEntity, LqKdKdjlbEntity>(
  634 + (kjbsyj, kdjlb) => kjbsyj.Glkdbh == kdjlb.Id)
  635 + .Where((kjbsyj, kdjlb) => kjbsyj.Kjbls == input.kjblsId)
  636 + .WhereIF(input.isEffective != 0, (kjbsyj, kdjlb) => kjbsyj.IsEffective == input.isEffective && kdjlb.IsEffective == input.isEffective)
  637 + .WhereIF(input.isEffective == 0, (kjbsyj, kdjlb) => kjbsyj.IsEffective == StatusEnum.有效.GetHashCode() && kdjlb.IsEffective == StatusEnum.有效.GetHashCode())
  638 + .WhereIF(startDate.HasValue, (kjbsyj, kdjlb) => kdjlb.Kdrq >= startDate.Value)
  639 + .WhereIF(endDate.HasValue, (kjbsyj, kdjlb) => kdjlb.Kdrq <= endDate.Value)
  640 + .WhereIF(!string.IsNullOrEmpty(input.djmd), (kjbsyj, kdjlb) => kdjlb.Djmd == input.djmd)
  641 + .Select((kjbsyj, kdjlb) => new LqKdKdjlbListOutput
  642 + {
  643 + id = kdjlb.Id,
  644 + djmd = kdjlb.Djmd,
  645 + jsj = kdjlb.Jsj,
  646 + kdrq = kdjlb.Kdrq,
  647 + gjlx = kdjlb.Gjlx,
  648 + hgjg = kdjlb.Hgjg,
  649 + zdyj = kdjlb.Zdyj,
  650 + sfyj = kdjlb.Sfyj,
  651 + qk = kdjlb.Qk,
  652 + ckfs = kdjlb.Ckfs,
  653 + fkfs = kdjlb.Fkfs,
  654 + fkyy = kdjlb.Fkyy,
  655 + fkpd = kdjlb.Fkpd,
  656 + khly = kdjlb.Khly,
  657 + tjr = kdjlb.Tjr,
  658 + deductAmount = kdjlb.DeductAmount,
  659 + paidDebt = kdjlb.PaidDebt,
  660 + supplementBillingId = kdjlb.SupplementBillingId,
  661 + sfskdd = kdjlb.Sfskdd,
  662 + jj = kdjlb.Jj,
  663 + bz = kdjlb.Bz,
  664 + kdhy = kdjlb.Kdhy,
  665 + kdhyc = SqlFunc.Subqueryable<LqKhxxEntity>().Where(x => x.Id == kdjlb.Kdhy).Select(x => x.Khmc),
  666 + kdhysjh = SqlFunc.Subqueryable<LqKhxxEntity>().Where(x => x.Id == kdjlb.Kdhy).Select(x => x.Sjh),
  667 + isEffective = kdjlb.IsEffective,
  668 + createUser = kdjlb.CreateUser,
  669 + createUserName = SqlFunc.Subqueryable<UserEntity>().Where(x => x.Id == kdjlb.CreateUser).Select(x => x.RealName),
  670 + activityId = kdjlb.ActivityId,
  671 + activityName = SqlFunc.Subqueryable<LqPackageInfoEntity>().Where(x => x.Id == kdjlb.ActivityId).Select(x => x.ActivityName),
  672 + })
  673 + .MergeTable()
  674 + .Distinct() // 去重,因为一个开单可能对应多个科技部老师业绩记录
  675 + .OrderBy($"{sidx} {sort}")
  676 + .ToPagedListAsync(input.currentPage, input.pageSize);
  677 +
  678 + // 获取当前页的开单记录ID列表
  679 + var billingIds = data.list.Select(x => x.id).ToList();
  680 +
  681 + // 批量查询品项明细
  682 + var itemDetails = new List<LqKdPxmxInfoOutput>();
  683 + if (billingIds.Any())
  684 + {
  685 + itemDetails = await _db.Queryable<LqKdPxmxEntity>()
  686 + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode())
  687 + .Select(x => new LqKdPxmxInfoOutput
  688 + {
  689 + id = x.Id,
  690 + glkdbh = x.Glkdbh,
  691 + px = x.Px,
  692 + pxmc = x.Pxmc,
  693 + pxjg = x.Pxjg,
  694 + projectNumber = x.ProjectNumber,
  695 + isEnabled = x.IsEnabled,
  696 + sourceType = x.SourceType,
  697 + memberId = x.MemberId,
  698 + createTime = x.CreateTIme,
  699 + totalPrice = x.TotalPrice,
  700 + actualPrice = x.ActualPrice,
  701 + remark = x.Remark,
  702 + isEffective = x.IsEffective
  703 + })
  704 + .ToListAsync();
  705 + }
  706 +
  707 + // 按开单ID分组品项明细
  708 + var itemDetailsGrouped = itemDetails.GroupBy(x => x.glkdbh)
  709 + .ToDictionary(g => g.Key, g => g.ToList());
  710 +
  711 + // 为每个开单记录分配品项明细
  712 + foreach (var item in data.list)
  713 + {
  714 + item.ItemDetails = itemDetailsGrouped.ContainsKey(item.id)
  715 + ? itemDetailsGrouped[item.id]
  716 + : new List<LqKdPxmxInfoOutput>();
  717 + }
  718 +
  719 + return PageResult<LqKdKdjlbListOutput>.SqlSugarPageResult(data);
  720 + }
  721 + catch (Exception ex)
  722 + {
  723 + _logger.LogError(ex, $"根据科技部老师ID获取开单列表失败 - 科技部老师ID: {input?.kjblsId}, 开始时间: {input?.startTime}, 结束时间: {input?.endTime}");
  724 + throw NCCException.Oh($"根据科技部老师ID获取开单列表失败: {ex.Message}");
  725 + }
  726 + }
  727 + #endregion
  728 +
323 729 #region 新建开单记录表
324 730 /// <summary>
325 731 /// 新建开单记录表
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqMdGeneralManagerLifelineService.cs
... ... @@ -7,10 +7,12 @@ using Mapster;
7 7 using Microsoft.AspNetCore.Mvc;
8 8 using NCC.Common.Core.Manager;
9 9 using NCC.Common.Enum;
  10 +using NCC.Common.Extension;
10 11 using NCC.Common.Filter;
11 12 using NCC.Dependency;
12 13 using NCC.DynamicApiController;
13 14 using NCC.Extend.Entitys.Dto.LqMdGeneralManagerLifeline;
  15 +using NCC.Extend.Entitys.Enum;
14 16 using NCC.Extend.Entitys.lq_md_general_manager_lifeline;
15 17 using NCC.Extend.Entitys.lq_md_target;
16 18 using NCC.Extend.Interfaces.LqMdGeneralManagerLifeline;
... ... @@ -77,6 +79,7 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline
77 79 storeId = it.StoreId,
78 80 month = it.Month,
79 81 generalManagerId = it.GeneralManagerId,
  82 + managerType = it.ManagerType,
80 83 lifeline1 = it.Lifeline1,
81 84 commissionRate1 = it.CommissionRate1,
82 85 lifeline2 = it.Lifeline2,
... ... @@ -92,6 +95,21 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline
92 95 .MergeTable()
93 96 .OrderBy(sidx + " " + input.sort)
94 97 .ToPagedListAsync(input.currentPage, input.pageSize);
  98 +
  99 + // 设置经理类型中文名称
  100 + foreach (var item in data.list)
  101 + {
  102 + if (Enum.IsDefined(typeof(ManagerTypeEnum), item.managerType))
  103 + {
  104 + var enumValue = (ManagerTypeEnum)item.managerType;
  105 + item.managerTypeName = enumValue.GetDescription();
  106 + }
  107 + else
  108 + {
  109 + item.managerTypeName = string.Empty;
  110 + }
  111 + }
  112 +
95 113 return PageResult<LqMdGeneralManagerLifelineListOutput>.SqlSugarPageResult(data);
96 114 }
97 115 #endregion
... ... @@ -273,6 +291,7 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline
273 291 Id = YitIdHelper.NextId().ToString(),
274 292 StoreId = target.StoreId,
275 293 Month = target.Month,
  294 + ManagerType = ManagerTypeEnum.总经理.GetHashCode(),
276 295 GeneralManagerId = target.BusinessUnitGeneralManager,
277 296 Lifeline1 = 0,
278 297 CommissionRate1 = 0,
... ... @@ -299,14 +318,15 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline
299 318 Id = YitIdHelper.NextId().ToString(),
300 319 StoreId = target.StoreId,
301 320 Month = target.Month,
  321 + ManagerType = ManagerTypeEnum.经理.GetHashCode(),
302 322 GeneralManagerId = target.BusinessUnitManager,
303 323 Lifeline1 = 0,
304 324 CommissionRate1 = 0,
305   - Lifeline2 = null,
306   - CommissionRate2 = null,
307   - Lifeline3 = null,
308   - CommissionRate3 = null,
309   - Remark = null,
  325 + Lifeline2 = 0,
  326 + CommissionRate2 = 0,
  327 + Lifeline3 = 0,
  328 + CommissionRate3 = 0,
  329 + Remark = "",
310 330 CreateTime = DateTime.Now,
311 331 CreateUserId = userInfo.userId,
312 332 });
... ... @@ -405,6 +425,7 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline
405 425 Id = YitIdHelper.NextId().ToString(),
406 426 StoreId = p.StoreId,
407 427 Month = targetMonthStr,
  428 + ManagerType = p.ManagerType,
408 429 GeneralManagerId = p.GeneralManagerId,
409 430 Lifeline1 = p.Lifeline1,
410 431 CommissionRate1 = p.CommissionRate1,
... ...