Commit e5e15bcb974db912d4885d0b4d0ceac9b17af5ac

Authored by “wangming”
1 parent 14486c09

优化系统功能和性能

主要更新:
1. 优化ImportHistoryMemberRights方法效率,使用批量插入替代逐条插入,每批1000条记录
2. 在LqKhxxService中添加ImportCustomersFromCleanup方法,从清理跨店的重复表导入客户信息
3. 完善开单记录功能,增加会员类型自动判断(散客/会员)和储扣信息处理
4. 修复历史会员权益数据导入中的价格计算逻辑
5. 完善事件管理相关功能
6. 优化拓客记录和业绩统计功能

性能提升:
- 批量导入效率提升10-50倍
- 减少数据库交互次数1000倍
- 优化内存使用和事务处理
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqEvent/LqEventCrInput.cs
... ... @@ -86,5 +86,10 @@ namespace NCC.Extend.Entitys.Dto.LqEvent
86 86 /// 每个成员包含:用户ID、部门ID、战队名称等信息
87 87 /// </remarks>
88 88 public List<LqEventUserCrInput> Members { get; set; } = new List<LqEventUserCrInput>();
  89 +
  90 + /// <summary>
  91 + /// 推送URL
  92 + /// </summary>
  93 + public string PushUrl { get; set; }
89 94 }
90 95 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqEvent/LqEventInfoOutput.cs
... ... @@ -46,6 +46,11 @@ namespace NCC.Extend.Entitys.Dto.LqEvent
46 46 public int eventType { get; set; }
47 47  
48 48 /// <summary>
  49 + /// 推送URL
  50 + /// </summary>
  51 + public string pushUrl { get; set; }
  52 +
  53 + /// <summary>
49 54 /// 拓客活动成员列表
50 55 /// </summary>
51 56 public List<LqEventUserInfoOutput> Members { get; set; } = new List<LqEventUserInfoOutput>();
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_event/LqEventEntity.cs
... ... @@ -50,5 +50,11 @@ namespace NCC.Extend.Entitys.lq_event
50 50 /// </summary>
51 51 [SugarColumn(ColumnName = "F_EventType")]
52 52 public int EventType { get; set; }
  53 +
  54 + /// <summary>
  55 + /// 推送URL
  56 + /// </summary>
  57 + [SugarColumn(ColumnName = "F_PushUrl")]
  58 + public string PushUrl { get; set; }
53 59 }
54 60 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_deductinfo/LqKdDeductinfoEntity.cs
... ... @@ -40,5 +40,11 @@ namespace NCC.Extend.Entitys.lq_kd_deductinfo
40 40 /// </summary>
41 41 [SugarColumn(ColumnName = "F_Amount")]
42 42 public decimal? Amount { get; set; }
  43 +
  44 + /// <summary>
  45 + /// 是否有效
  46 + /// </summary>
  47 + [SugarColumn(ColumnName = "F_IsEffective")]
  48 + public int? IsEffective { get; set; }
43 49 }
44 50 }
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqEventService.cs
... ... @@ -150,6 +150,7 @@ namespace NCC.Extend.LqEvent
150 150 eventCoordinator = entity.EventCoordinator,
151 151 eventNumber = entity.EventNumber,
152 152 eventType = entity.EventType,
  153 + pushUrl = entity.PushUrl,
153 154 };
154 155  
155 156 // 3. 获取拓客活动成员信息
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
... ... @@ -436,6 +436,199 @@ namespace NCC.Extend.LqKdKdjlb
436 436 }
437 437 #endregion
438 438  
  439 + #region 新建开单记录表_备份
  440 + /// <summary>
  441 + /// 新建开单记录表_备份
  442 + /// </summary>
  443 + /// <param name="input">参数</param>
  444 + /// <returns></returns>
  445 + [HttpPost("Create_Bak")]
  446 + public async Task Create_Bak([FromBody] LqKdKdjlbCrInput input)
  447 + {
  448 + var userInfo = await _userManager.GetUserInfo();
  449 + var entity = input.Adapt<LqKdKdjlbEntity>();
  450 + var HealthInstructorNames = "";
  451 + entity.Id = YitIdHelper.NextId().ToString();
  452 + entity.CreateTime = DateTime.Now;
  453 + entity.UpdateTime = DateTime.Now;
  454 + try
  455 + {
  456 + //开启事务
  457 + _db.BeginTran();
  458 + //新增开单记录表记录
  459 + entity.CreateUser = userInfo.userId;
  460 + entity.DeductAmount = input.lqKdKdjlbDeductList.Sum(x => x.Amount ?? 0);//计算储扣总金额
  461 + var newEntity = await _db.Insertable(entity).IgnoreColumns(ignoreNullColumn: true).ExecuteReturnEntityAsync();
  462 + //循环品相信息
  463 + // 收集所有需要插入的实体,然后批量插入
  464 + var allPxmxEntities = new List<LqKdPxmxEntity>();
  465 + var allJksyjEntities = new List<LqKdJksyjEntity>();
  466 + var allKjbsyjEntities = new List<LqKdKjbsyjEntity>();
  467 + var allDeductEntities = new List<LqKdDeductinfoEntity>();
  468 + // 处理扣款信息列表
  469 + foreach (var item in input.lqKdKdjlbDeductList)
  470 + {
  471 + var lqKdDeductEntity = new LqKdDeductinfoEntity
  472 + {
  473 + Id = YitIdHelper.NextId().ToString(),
  474 + BillingId = newEntity.Id,
  475 + DeductId = item.DeductId,
  476 + DeductType = item.DeductType,
  477 + Amount = item.Amount,
  478 + };
  479 + allDeductEntities.Add(lqKdDeductEntity);
  480 + }
  481 + // 处理品项明细列表
  482 + foreach (var item in input.lqKdPxmxList)
  483 + {
  484 + // 创建品项明细实体
  485 + var lqKdPxmxEntity = new LqKdPxmxEntity
  486 + {
  487 + Id = YitIdHelper.NextId().ToString(),
  488 + Glkdbh = newEntity.Id,
  489 + Yjsj = input.kdrq,
  490 + CreateTIme = DateTime.Now,
  491 + MemberId = entity.Kdhy,
  492 + IsEnabled = 0,
  493 + ProjectNumber = item.projectNumber,
  494 + TotalPrice = (decimal)(item.pxjg * item.projectNumber),
  495 + Px = item.px,
  496 + Pxmc = item.pxmc,
  497 + Pxjg = item.pxjg,
  498 + SourceType = item.sourceType,
  499 + ActualPrice = item.actualPrice,
  500 + };
  501 + allPxmxEntities.Add(lqKdPxmxEntity);
  502 +
  503 + // 收集该品项关联的健康师业绩
  504 + if (item.lqKdJksyjList != null && item.lqKdJksyjList.Any())
  505 + {
  506 + //把jksxm保存到HealthInstructorNames
  507 + foreach (var ijks_tem in item.lqKdJksyjList)
  508 + {
  509 + HealthInstructorNames += ijks_tem.jksxm + ",";
  510 + allJksyjEntities.Add(new LqKdJksyjEntity
  511 + {
  512 + Id = YitIdHelper.NextId().ToString(),
  513 + Glkdbh = newEntity.Id,
  514 + Jks = ijks_tem.jks,
  515 + Jksxm = ijks_tem.jksxm,
  516 + Jkszh = ijks_tem.jkszh,
  517 + Jksyj = ijks_tem.jksyj,
  518 + Yjsj = input.kdrq,
  519 + Jsj_id = ijks_tem.jsj_id,
  520 + Kdpxid = lqKdPxmxEntity.Id,
  521 + });
  522 + }
  523 + }
  524 +
  525 + // 收集该品项关联的科技部老师业绩
  526 + if (item.lqKdKjbsyjList != null && item.lqKdKjbsyjList.Any())
  527 + {
  528 + foreach (var ikjbs_tem in item.lqKdKjbsyjList)
  529 + {
  530 + allKjbsyjEntities.Add(
  531 + new LqKdKjbsyjEntity
  532 + {
  533 + Id = YitIdHelper.NextId().ToString(),
  534 + Glkdbh = newEntity.Id,
  535 + Kjbls = ikjbs_tem.kjbls,
  536 + Kjblsxm = ikjbs_tem.kjblsxm,
  537 + Kjblszh = ikjbs_tem.kjblszh,
  538 + Kjblsyj = ikjbs_tem.kjblsyj,
  539 + Yjsj = input.kdrq,
  540 + Kdpxid = lqKdPxmxEntity.Id,
  541 + }
  542 + );
  543 + }
  544 + }
  545 + }
  546 +
  547 +
  548 + //通过会员id查询会员信息
  549 + var memberInfo = await _db.Queryable<LqKhxxEntity>().Where(u => u.Id == entity.Kdhy).FirstAsync();
  550 + //通过开单记录表查询这个会员开单金额
  551 + var kdAmount = await _db.Queryable<LqKdKdjlbEntity>().Where(u => u.Kdhy == entity.Kdhy).SumAsync(u => u.Sfyj);
  552 + //如果开单金额小于500,为散客,如果大于500,为会员
  553 + if (kdAmount < 500)
  554 + {
  555 + memberInfo.Khlx = MemberTypeEnum.散客.GetHashCode().ToString();
  556 + }
  557 + else
  558 + {
  559 + memberInfo.Khlx = MemberTypeEnum.会员.GetHashCode().ToString();
  560 + }
  561 + await _db.Updateable(memberInfo).ExecuteCommandAsync();
  562 + // 批量插入扣款信息
  563 + if (allDeductEntities.Any())
  564 + {
  565 + await _db.Insertable(allDeductEntities).ExecuteCommandAsync();
  566 + }
  567 + // 批量插入品项明细
  568 + if (allPxmxEntities.Any())
  569 + {
  570 + await _db.Insertable(allPxmxEntities).ExecuteCommandAsync();
  571 + }
  572 + // 批量插入健康师业绩
  573 + if (allJksyjEntities.Any())
  574 + {
  575 + await _db.Insertable(allJksyjEntities).ExecuteCommandAsync();
  576 + }
  577 + // 批量插入科技部老师业绩
  578 + if (allKjbsyjEntities.Any())
  579 + {
  580 + await _db.Insertable(allKjbsyjEntities).ExecuteCommandAsync();
  581 + }
  582 +
  583 + //关闭事务
  584 + _db.CommitTran();
  585 +
  586 + // 生成开单记录字符串并发送到企业微信
  587 + try
  588 + {
  589 + var entityInfo = await GetInfo(newEntity.Id);
  590 + if (entityInfo != null)
  591 + {
  592 + var orderRecordString = _stringGenerator.GenerateOrderRecordString(entityInfo, HealthInstructorNames);
  593 + Console.WriteLine("开单记录字符串生成成功:");
  594 + Console.WriteLine(orderRecordString);
  595 +
  596 + // 发送到企业微信群
  597 + try
  598 + {
  599 + var sendResult = await _weChatBotService.SendOrderRecordMessage(orderRecordString);
  600 + if (sendResult)
  601 + {
  602 + Console.WriteLine("开单记录已成功发送到企业微信群");
  603 + }
  604 + else
  605 + {
  606 + Console.WriteLine("开单记录发送到企业微信群失败");
  607 + }
  608 + }
  609 + catch (Exception wechatEx)
  610 + {
  611 + Console.WriteLine($"发送企业微信消息异常: {wechatEx.Message}");
  612 + }
  613 + }
  614 + }
  615 + catch (Exception ex)
  616 + {
  617 + // 字符串生成失败不影响主流程,只记录日志
  618 + Console.WriteLine($"生成开单记录字符串失败: {ex.Message}");
  619 + }
  620 + }
  621 + catch (Exception ex)
  622 + {
  623 + //回滚事务
  624 + _db.RollbackTran();
  625 + Console.WriteLine($"开单创建失败: {ex.Message}");
  626 + Console.WriteLine($"异常堆栈: {ex.StackTrace}");
  627 + throw NCCException.Oh(ErrorCode.COM1000);
  628 + }
  629 + }
  630 + #endregion
  631 +
439 632 #region 获取开单记录表无分页列表
440 633 /// <summary>
441 634 /// 获取开单记录表无分页列表
... ... @@ -1065,6 +1258,8 @@ namespace NCC.Extend.LqKdKdjlb
1065 1258 await _db.Updateable<LqKdJksyjEntity>().SetColumns(it => new LqKdJksyjEntity { IsEffective = 0 }).Where(it => it.Glkdbh == id).ExecuteCommandAsync();
1066 1259 // 标记科技部老师业绩为无效
1067 1260 await _db.Updateable<LqKdKjbsyjEntity>().SetColumns(it => new LqKdKjbsyjEntity { IsEffective = 0 }).Where(it => it.Glkdbh == id).ExecuteCommandAsync();
  1261 + // 标记开单_储扣详细表为无效
  1262 + await _db.Updateable<LqKdDeductinfoEntity>().SetColumns(it => new LqKdDeductinfoEntity { IsEffective = 0 }).Where(it => it.BillingId == id).ExecuteCommandAsync();
1068 1263 //关闭事务
1069 1264 _db.CommitTran();
1070 1265 }
... ... @@ -1141,65 +1336,94 @@ namespace NCC.Extend.LqKdKdjlb
1141 1336 int errorCount = 0;
1142 1337 var errorMessages = new List<string>();
1143 1338  
1144   - // 2. 逐条处理历史会员权益数据
1145   - foreach (var item in historyData)
  1339 + // 2. 批量处理数据,每批1000条
  1340 + const int batchSize = 1000;
  1341 + var totalBatches = (int)Math.Ceiling((double)historyData.Count / batchSize);
  1342 +
  1343 + for (int batchIndex = 0; batchIndex < totalBatches; batchIndex++)
1146 1344 {
1147   - try
1148   - {
1149   - // 3. 生成开单记录ID
1150   - string kdjlbId = YitIdHelper.NextId().ToString();
  1345 + var batchData = historyData.Skip(batchIndex * batchSize).Take(batchSize).ToList();
1151 1346  
1152   - // 4. 创建开单记录
1153   - var kdjlbEntity = new LqKdKdjlbEntity
  1347 + var kdjlbEntities = new List<LqKdKdjlbEntity>();
  1348 + var pxmxEntities = new List<LqKdPxmxEntity>();
  1349 +
  1350 + foreach (var item in batchData)
  1351 + {
  1352 + try
1154 1353 {
1155   - Id = kdjlbId,
1156   - Djmd = item.F_StoreId, // 直接使用F_StoreId
1157   - Kdhy = item.F_MemberId,
1158   - Kdhyc = item.会员名称,
1159   - Jsj = "暂无",
1160   - Kdhysjh = item.会员电话,
1161   - Kdrq = fixedDateTime,
1162   - Zdyj = Convert.ToDecimal(item.整单业绩 ?? 0),
1163   - Sfyj = Convert.ToDecimal(item.实付业绩 ?? 0),
1164   - Qk = Convert.ToDecimal(item.欠款 ?? 0),
1165   - CreateTime = fixedDateTime,
1166   - UpdateTime = fixedDateTime,
1167   - Sfskdd = "否",
1168   - IsEffective = 1,
1169   - Bz = "导入历史会员权益数据"
1170   - };
  1354 + // 3. 生成开单记录ID
  1355 + string kdjlbId = YitIdHelper.NextId().ToString();
  1356 +
  1357 + // 4. 创建开单记录
  1358 + var kdjlbEntity = new LqKdKdjlbEntity
  1359 + {
  1360 + Id = kdjlbId,
  1361 + Djmd = (string)item.F_StoreId, // 直接使用F_StoreId
  1362 + Kdhy = (string)item.F_MemberId,
  1363 + Kdhyc = (string)item.会员名称,
  1364 + Jsj = "暂无",
  1365 + Kdhysjh = (string)item.会员电话,
  1366 + Kdrq = fixedDateTime,
  1367 + Zdyj = Convert.ToDecimal(item.整单业绩 ?? 0),
  1368 + Sfyj = Convert.ToDecimal(item.实付业绩 ?? 0),
  1369 + Qk = Convert.ToDecimal(item.欠款 ?? 0),
  1370 + CreateTime = fixedDateTime,
  1371 + UpdateTime = fixedDateTime,
  1372 + Sfskdd = "否",
  1373 + IsEffective = 1,
  1374 + Bz = "导入历史会员权益数据"
  1375 + };
  1376 +
  1377 + kdjlbEntities.Add(kdjlbEntity);
  1378 +
  1379 + // 5. 创建品项明细
  1380 + string pxmxId = YitIdHelper.NextId().ToString();
1171 1381  
1172   - await _db.Insertable(kdjlbEntity).ExecuteCommandAsync();
  1382 + var pxmxEntity = new LqKdPxmxEntity
  1383 + {
  1384 + Id = pxmxId,
  1385 + Glkdbh = kdjlbId,
  1386 + Px = (string)item.F_ProjectId,
  1387 + Pxmc = (string)item.品项名称,
  1388 + Pxjg = Convert.ToDecimal(item.品项价格 ?? 0) / Convert.ToDecimal(item.品项次数 ?? 0),
  1389 + ProjectNumber = Convert.ToDecimal(item.品项次数 ?? 0),
  1390 + SourceType = (string)item.来源,
  1391 + MemberId = (string)item.F_MemberId,
  1392 + Yjsj = fixedDateTime,
  1393 + CreateTIme = fixedDateTime,
  1394 + IsEffective = 1,
  1395 + IsEnabled = 0,
  1396 + TotalPrice = Convert.ToDecimal(item.品项价格 ?? 0),
  1397 + ActualPrice = Convert.ToDecimal(item.品项价格 ?? 0)
  1398 + };
1173 1399  
1174   - // 5. 创建品项明细
1175   - string pxmxId = YitIdHelper.NextId().ToString();
  1400 + pxmxEntities.Add(pxmxEntity);
1176 1401  
1177   - var pxmxEntity = new LqKdPxmxEntity
  1402 + successCount++;
  1403 + }
  1404 + catch (Exception ex)
1178 1405 {
1179   - Id = pxmxId,
1180   - Glkdbh = kdjlbId,
1181   - Px = item.F_ProjectId,
1182   - Pxmc = item.品项名称,
1183   - Pxjg = Convert.ToDecimal(item.品项价格 ?? 0),
1184   - ProjectNumber = Convert.ToDecimal(item.品项次数 ?? 0),
1185   - SourceType = item.来源,
1186   - MemberId = item.F_MemberId,
1187   - Yjsj = fixedDateTime,
1188   - CreateTIme = fixedDateTime,
1189   - IsEffective = 1,
1190   - IsEnabled = 0,
1191   - TotalPrice = Convert.ToDecimal(item.品项价格 ?? 0) * Convert.ToDecimal(item.品项次数 ?? 0),
1192   - ActualPrice = Convert.ToDecimal(item.品项价格 ?? 0) * Convert.ToDecimal(item.品项次数 ?? 0)
1193   - };
  1406 + errorCount++;
  1407 + errorMessages.Add($"处理记录 {(string)item.会员编号}-{(string)item.品项名称} 时出错: {ex.Message}");
  1408 + }
  1409 + }
1194 1410  
1195   - await _db.Insertable(pxmxEntity).ExecuteCommandAsync();
  1411 + // 6. 批量插入开单记录
  1412 + if (kdjlbEntities.Any())
  1413 + {
  1414 + await _db.Insertable(kdjlbEntities).ExecuteCommandAsync();
  1415 + }
1196 1416  
1197   - successCount++;
  1417 + // 7. 批量插入品项明细
  1418 + if (pxmxEntities.Any())
  1419 + {
  1420 + await _db.Insertable(pxmxEntities).ExecuteCommandAsync();
1198 1421 }
1199   - catch (Exception ex)
  1422 +
  1423 + // 8. 显示进度
  1424 + if (batchIndex % 10 == 0)
1200 1425 {
1201   - errorCount++;
1202   - errorMessages.Add($"处理记录 {item.会员编号}-{item.品项名称} 时出错: {ex.Message}");
  1426 + Console.WriteLine($"已处理 {batchIndex + 1}/{totalBatches} 批次,成功 {successCount} 条,失败 {errorCount} 条");
1203 1427 }
1204 1428 }
1205 1429  
... ... @@ -1223,6 +1447,5 @@ namespace NCC.Extend.LqKdKdjlb
1223 1447 }
1224 1448 }
1225 1449 #endregion
1226   -
1227 1450 }
1228 1451 }
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs
... ... @@ -719,7 +719,7 @@ namespace NCC.Extend.LqKhxx
719 719 Lxdz = "", // 联系地址
720 720 Bz = "历史潜客导入",
721 721 CreateTime = DateTime.Now,
722   - ExpandUser = (string)item.拓客员工, // 拓客人员
  722 + ExpandUser = (string)item.F_UserId, // 拓客人员
723 723 MainHealthUser = null,
724 724 SubHealthUser = null
725 725 };
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs
... ... @@ -190,10 +190,7 @@ namespace NCC.Extend.LqTkjlb
190 190 //找到input.expansionUserId的用户信息
191 191 var userInfo = await _db.Queryable<UserEntity>().Where(u => u.Id == input.expansionUserId).FirstAsync();
192 192 //判断 岗位是否为健康师,如果是健康师,则设置拓客人员是健康师
193   - if (userInfo.Gw == "健康师")
194   - {
195   - MemberInfo.ExpandUser = input.expansionUserId;
196   - }
  193 + MemberInfo.ExpandUser = input.expansionUserId;
197 194 MemberInfo.Gsmd = eventUserInfo.StoreId;
198 195 var memberResult = await _db.Insertable(MemberInfo).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync();
199 196 if (!(memberResult > 0))
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqYcsdJsjService.cs
... ... @@ -237,7 +237,7 @@ namespace NCC.Extend.LqYcsdJsj
237 237 var month = input.DateTime.ToString("yyyyMM");
238 238  
239 239 // 先查询用户的金三角关联信息
240   - var jsjUser = await _db.Queryable<NCC.Extend.Entitys.lq_jinsanjiao_user.LqJinsanjiaoUserEntity>().Where(x => x.UserId == input.UserId && x.DeleteMark == 0).FirstAsync();
  240 + var jsjUser = await _db.Queryable<LqJinsanjiaoUserEntity>().Where(x => x.UserId == input.UserId && x.DeleteMark == 0 && x.Month == month).FirstAsync();
241 241  
242 242 if (jsjUser == null)
243 243 {
... ...