فهرست منبع

Merge branch 'test' into lib/test

libin 1 ماه پیش
والد
کامیت
52aa9b9d49
77فایلهای تغییر یافته به همراه1401 افزوده شده و 593 حذف شده
  1. 4 4
      src/Hotline.Api/Controllers/IdentityController.cs
  2. 1 0
      src/Hotline.Api/Controllers/KnowledgeController.cs
  3. 1 1
      src/Hotline.Api/Controllers/OrderApi/OrderCarbonCopyController.cs
  4. 1 1
      src/Hotline.Api/Controllers/OrderApi/OrderComplementController.cs
  5. 198 70
      src/Hotline.Api/Controllers/OrderController.cs
  6. 1 0
      src/Hotline.Api/Controllers/Snapshot/SnapshotController.cs
  7. 144 32
      src/Hotline.Api/Controllers/TestController.cs
  8. 2 1
      src/Hotline.Api/Controllers/WorkflowController.cs
  9. 2 1
      src/Hotline.Api/StartupExtensions.cs
  10. 9 9
      src/Hotline.Application/FlowEngine/IWorkflowApplication.cs
  11. 20 19
      src/Hotline.Application/FlowEngine/WorkflowApplication.cs
  12. 34 8
      src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs
  13. 3 2
      src/Hotline.Application/Identity/IIdentityAppService.cs
  14. 27 51
      src/Hotline.Application/Identity/IdentityAppService.cs
  15. 1 1
      src/Hotline.Application/Mappers/MapperConfigs.cs
  16. 15 1
      src/Hotline.Application/Orders/OrderApplication.cs
  17. 1 0
      src/Hotline.Application/Orders/OrderSecondaryHandlingApplication.cs
  18. 1 1
      src/Hotline.Application/Snapshot/DefaultSnapshotApplication.cs
  19. 1 0
      src/Hotline.Application/Snapshot/RedPackApplication.cs
  20. 24 29
      src/Hotline.Application/Snapshot/SnapshotApplicationBase.cs
  21. 101 0
      src/Hotline.Application/Snapshot/SnapshotThirdAccountSupplier.cs
  22. 1 1
      src/Hotline.Application/Snapshot/ZiGongSnapshotApplication.cs
  23. 1 1
      src/Hotline.Application/Subscribers/DatasharingSubscriber.cs
  24. 1 1
      src/Hotline.Repository.SqlSugar/Extensions/SqlSugarStartupExtensions.cs
  25. 0 23
      src/Hotline.Repository.SqlSugar/Snapshot/GuiderInfoRepository.cs
  26. 33 0
      src/Hotline.Repository.SqlSugar/Snapshot/SnapshotUserInfoRepository.cs
  27. 2 3
      src/Hotline.Repository.SqlSugar/Snapshot/ThirdAccountRepository.cs
  28. 5 0
      src/Hotline.Repository.SqlSugar/Snapshot/VolunteerRepository.cs
  29. 2 2
      src/Hotline.Share/Dtos/FlowEngine/Workflow/PreviousWorkflowDto.cs
  30. 16 5
      src/Hotline.Share/Dtos/Knowledge/KnowledgeDto.cs
  31. 47 2
      src/Hotline.Share/Dtos/Order/OrderDto.cs
  32. 19 0
      src/Hotline.Share/Dtos/Order/OrderScreenDto.cs
  33. 15 39
      src/Hotline.Share/Dtos/Snapshot/ThirdTokenDto.cs
  34. 25 0
      src/Hotline.Share/Enums/ThirdAccount/EAppType.cs
  35. 12 7
      src/Hotline.WeChat/WeChatService.cs
  36. 10 0
      src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs
  37. 35 12
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  38. 4 0
      src/Hotline/Hotline.csproj
  39. 12 6
      src/Hotline/KnowledgeBase/Knowledge.cs
  40. 41 17
      src/Hotline/KnowledgeBase/KnowledgeDomainService.cs
  41. 30 0
      src/Hotline/KnowledgeBase/KnowledgeRelationOrg.cs
  42. 0 2
      src/Hotline/KnowledgeBase/KnowledgeRelationType.cs
  43. 25 1
      src/Hotline/Orders/Order.cs
  44. 109 104
      src/Hotline/Orders/OrderSecondaryHandling.cs
  45. 3 3
      src/Hotline/Orders/OrderVisitDomainService.cs
  46. 6 0
      src/Hotline/Settings/SettingOrderVisitSmsReplyRule.cs
  47. 0 22
      src/Hotline/Snapshot/GuiderInfo.cs
  48. 0 13
      src/Hotline/Snapshot/Interfaces/IGuiderInfoRepository.cs
  49. 25 0
      src/Hotline/Snapshot/Interfaces/ISnapshotUserInfoRepository.cs
  50. 2 0
      src/Hotline/Snapshot/SnapshotSMSTemplate.cs
  51. 56 0
      src/Hotline/Snapshot/SnapshotUserInfo.cs
  52. 46 0
      src/Hotline/ThirdAccountDomainServices/Interfaces/IThirdAccountDomainService.cs
  53. 1 1
      src/Hotline/ThirdAccountDomainServices/Interfaces/IThirdAccountRepository.cs
  54. 3 3
      src/Hotline/ThirdAccountDomainServices/Interfaces/IThirdIdentiyService.cs
  55. 9 46
      src/Hotline/ThirdAccountDomainServices/ThirdAccount.cs
  56. 41 0
      src/Hotline/ThirdAccountDomainServices/ThirdAccountDomainFactory.cs
  57. 33 0
      src/Hotline/ThirdAccountDomainServices/ThirdIdentiyFactory.cs
  58. 52 1
      src/Hotline/Tools/DynamicClassHelper.cs
  59. 3 2
      test/Hotline.Tests/Application/BiSnapshotApplicationTest.cs
  60. 3 2
      test/Hotline.Tests/Application/DefaultCallApplicationTest.cs
  61. 3 1
      test/Hotline.Tests/Application/IndustryApplicationTest.cs
  62. 8 3
      test/Hotline.Tests/Application/InviteCodeApplicationTest.cs
  63. 3 2
      test/Hotline.Tests/Application/KnowApplicationTest.cs
  64. 3 1
      test/Hotline.Tests/Application/OrderSnapshotApplicationTest.cs
  65. 3 1
      test/Hotline.Tests/Application/RedPackApplicationTest.cs
  66. 17 12
      test/Hotline.Tests/Application/SnapshotApplicationTest.cs
  67. 3 2
      test/Hotline.Tests/Application/SystemSettingCacheManagerTest.cs
  68. 3 2
      test/Hotline.Tests/Controller/IndustryControllerTest.cs
  69. 3 2
      test/Hotline.Tests/Controller/KnowledgeControllerTest.cs
  70. 4 2
      test/Hotline.Tests/Controller/OrderControllerTest.cs
  71. 3 1
      test/Hotline.Tests/Controller/SnapshotControllerTest.cs
  72. 1 0
      test/Hotline.Tests/Controller/TestSessionContext.cs
  73. 3 2
      test/Hotline.Tests/Domain/OrderVisitDomainServiceTest.cs
  74. 1 1
      test/Hotline.Tests/Infrastructure/WeiXinTest.cs
  75. 3 3
      test/Hotline.Tests/Mock/ThirdTestService.cs
  76. 1 1
      test/Hotline.Tests/Startup.cs
  77. 20 7
      test/Hotline.Tests/TestBase.cs

+ 4 - 4
src/Hotline.Api/Controllers/IdentityController.cs

@@ -98,8 +98,8 @@ jxrWXHbT1FB6DqkdOnBbQqS1Azqz5HxLlSyEK3F60e3SgB5iZsDZ
     /// <returns>登录成功, 用户是新用户, 需要调用获取用户手机号码 third/phone 接口</returns>
     [AllowAnonymous]
     [HttpPost("third/token")]
-    public async Task<TokenOutDto> GetThirdTokenAsync([FromBody] ThirdTokenInDto dto)
-        => await _identityAppService.GetThredTokenAsync(dto);
+    public async Task<Dictionary<string, object>> GetThirdTokenAsync([FromBody] ThirdTokenInDto dto)
+        => await _identityAppService.GetThredTokenAsync(dto, HttpContext.RequestAborted);
 
     /// <summary>
     /// 根据OpenId刷新令牌
@@ -108,8 +108,8 @@ jxrWXHbT1FB6DqkdOnBbQqS1Azqz5HxLlSyEK3F60e3SgB5iZsDZ
     /// <returns></returns>
     [HttpGet("third/refresh")]
     [AllowAnonymous]
-    public async Task<TokenOutDto> RefreshTokenAsync(string openId)
-        => await _identityAppService.RefreshTokenAsync(openId);
+    public async Task<Dictionary<string, object>> RefreshTokenAsync(string openId)
+        => await _identityAppService.RefreshTokenAsync(openId, HttpContext.RequestAborted);
 
     [AllowAnonymous]
     [ApiExplorerSettings(IgnoreApi = true)]

+ 1 - 0
src/Hotline.Api/Controllers/KnowledgeController.cs

@@ -679,6 +679,7 @@ namespace Hotline.Api.Controllers
             var knowledge = await _knowledgeRepository.Queryable()
                 .Includes(x => x.SourceOrganize)
                 .Includes(x => x.KnowledgeTypes)
+                .Includes(x=>x.KnowledgeOrganizes)
                 .Includes(x => x.HotspotType)
                 .FirstAsync(p => p.Id == Id, HttpContext.RequestAborted);
             if (knowledge is null)

+ 1 - 1
src/Hotline.Api/Controllers/OrderControllers/OrderCarbonCopyController.cs → src/Hotline.Api/Controllers/OrderApi/OrderCarbonCopyController.cs

@@ -8,7 +8,7 @@ using Mapster;
 using MapsterMapper;
 using Microsoft.AspNetCore.Mvc;
 
-namespace Hotline.Api.Controllers.OrderControllers
+namespace Hotline.Api.Controllers.OrderApi
 {
     /// <summary>
     /// 工单抄送

+ 1 - 1
src/Hotline.Api/Controllers/OrderControllers/OrderComplementController.cs → src/Hotline.Api/Controllers/OrderApi/OrderComplementController.cs

@@ -2,7 +2,7 @@
 using Hotline.Share.Dtos.Order;
 using Microsoft.AspNetCore.Mvc;
 
-namespace Hotline.Api.Controllers.OrderControllers;
+namespace Hotline.Api.Controllers.OrderApi;
 
 public class OrderComplementController : BaseController
 {

+ 198 - 70
src/Hotline.Api/Controllers/OrderController.cs

@@ -1337,7 +1337,7 @@ public class OrderController : BaseController
             Histories = histories,
             IsCanUpdate = isCanUpdate
         };
-        if (_appOptions.Value.IsLuZhou 
+        if (_appOptions.Value.IsLuZhou
             && !_sessionContext.OrgIsCenter
             && rsp.OrderVisitModel.Order.IsSecret)
         {
@@ -2691,7 +2691,9 @@ public class OrderController : BaseController
             {
                 if (DateTime.Now > visitDetail.ScreenByEndTime && !_sessionContext.OrgIsCenter)
                 {
-                    throw UserFriendlyException.SameMessage("超过2个工作日不能申请甄别,不能申请");
+                    var mes = "超过截至甄别时间不能申请甄别!";
+                    mes = _appOptions.Value.IsLuZhou ? "回访完成的次月第一个工作日后不能再申请甄别!" : mes;
+                    throw UserFriendlyException.SameMessage(mes);
                 }
             }
         }
@@ -2970,11 +2972,31 @@ public class OrderController : BaseController
     }
 
     /// <summary>
-    /// 获取工单甄别所有文件
+    /// 更新甄别信息
     /// </summary>
-    /// <param name="id"></param>
+    /// <param name="dto"></param>
     /// <returns></returns>
-    [HttpGet("screen/all_file/{id}")]
+	[HttpPut("order_screen_alter")]
+	[LogFilter("更新甄别信息")]
+	public async Task Update([FromBody] OrderScreenAlterDto dto)
+	{
+        var screen = await _orderScreenRepository.GetAsync(dto.ScreenId);
+		//var FileJson = new List<Share.Dtos.File.FileJson>();
+  //      if (dto.Files.Any())
+  //          FileJson = await _fileRepository.AddFileAsync(dto.Files, dto.ScreenId, "", HttpContext.RequestAborted);
+  //      else
+  //          FileJson = screen.FileJson;
+        dto.Content = string.IsNullOrEmpty(dto.Content) ? screen.Content : dto.Content;
+		await _orderScreenRepository.Updateable().SetColumns(x => new OrderScreen { Content = dto.Content })
+			.Where(x => x.Id == dto.ScreenId).ExecuteCommandAsync();
+	}
+
+	/// <summary>
+	/// 获取工单甄别所有文件
+	/// </summary>
+	/// <param name="id"></param>
+	/// <returns></returns>
+	[HttpGet("screen/all_file/{id}")]
     public async Task<List<FileDto>> GetOrderScreenAllFile(string id)
     {
         var screen = await _orderScreenRepository.GetAsync(id);
@@ -3012,6 +3034,31 @@ public class OrderController : BaseController
         await _workflowDomainService.NextAsync(dto, cancellationToken: HttpContext.RequestAborted);
     }
 
+    /// <summary>
+    /// 甄别审批退回(返回前一节点)
+    /// </summary>
+    [HttpPost("screen/previous")]
+    [LogFilterAlpha("甄别审批退回")]
+    public async Task Previous([FromBody] PreviousWorkflowDto dto)
+    {
+        /*
+         *甄别退回到最开始节点到部门 todo 重构放在调用处判断  
+           if (workflow.FlowType == EFlowType.Review && workflow.ModuleCode == WorkflowModuleConsts.OrderScreen)
+           {
+           	newPrevStep.FlowAssignType = newPrevStep.StepType == EStepType.Start ? EFlowAssignType.Org : prevStep.FlowAssignType;
+           }
+         */
+        
+        await _workflowDomainService.PreviousAsync(dto,
+            newStepConfig: (workflow, currentStep, prevStepDefine, prevStep, newPrevStep) =>
+            {
+                newPrevStep.FlowAssignType = prevStepDefine.BusinessType is EBusinessType.Department
+                    ? EFlowAssignType.Org
+                    : prevStep.FlowAssignType;
+            },
+            cancellationToken: HttpContext.RequestAborted);
+    }
+
 
     #endregion
 
@@ -3361,44 +3408,83 @@ public class OrderController : BaseController
                         ApplyContent = dto.UrgeContent
                     };
                     model.InitId();
-                    //泸州任务 303 当前节点处于承办部门,不管是几级部门,催办对象都是当前接办部门所属的一级部门的所有部门经办人
-                    if (_appOptions.Value.IsLuZhou && !string.IsNullOrEmpty(order.OrgLevelOneCode) && order.OrgLevelOneCode != "001")
-                    {
-                        model.OrgId = order.OrgLevelOneCode;
-                        model.OrgName = order.OrgLevelOneName;
-                    }
-                    await _orderUrgeRepository.AddAsync(model, HttpContext.RequestAborted);
-                    if (dto.AcceptSms)
+
+                    //中心催办
+                    if (_sessionContext.OrgIsCenter)
                     {
-                        try
+                        //泸州任务 303 当前节点处于承办部门,不管是几级部门,催办对象都是当前接办部门所属的一级部门的所有部门经办人
+                        if (_appOptions.Value.IsLuZhou && !string.IsNullOrEmpty(order.OrgLevelOneCode) && order.OrgLevelOneCode != "001")
                         {
-                            var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
-                            //查询部门所有账号
-                            var userlist = await _userRepository.Queryable().Where(x =>
-                                x.OrgId == model.OrgId && !string.IsNullOrEmpty(x.PhoneNo) &&
-                                x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
-                            foreach (var user in userlist)
+                            model.OrgId = order.OrgLevelOneCode;
+                            model.OrgName = order.OrgLevelOneName;
+                        }
+                        if (dto.AcceptSms)
+                        {
+                            try
                             {
-                                //发送短信
-                                var messageDto = new Share.Dtos.Push.MessageDto
+                                var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
+                                //查询部门所有账号
+                                var userlist = await _userRepository.Queryable().Where(x =>
+                                    x.OrgId == model.OrgId && !string.IsNullOrEmpty(x.PhoneNo) &&
+                                    x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
+                                foreach (var user in userlist)
                                 {
-                                    PushBusiness = EPushBusiness.OrderUrge,
-                                    ExternalId = order.Id,
-                                    OrderId = order.Id,
-                                    PushPlatform = EPushPlatform.Sms,
-                                    Remark = order.Title,
-                                    Name = user.Name,
-                                    TemplateCode = "1002",
-                                    Params = new List<string>() { order.No },
-                                    TelNumber = user.PhoneNo,
-                                };
-                                await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
+                                    //发送短信
+                                    var messageDto = new Share.Dtos.Push.MessageDto
+                                    {
+                                        PushBusiness = EPushBusiness.OrderUrge,
+                                        ExternalId = order.Id,
+                                        OrderId = order.Id,
+                                        PushPlatform = EPushPlatform.Sms,
+                                        Remark = order.Title,
+                                        Name = user.Name,
+                                        TemplateCode = "1002",
+                                        Params = new List<string>() { order.No },
+                                        TelNumber = user.PhoneNo,
+                                    };
+                                    await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
+                                }
+                            }
+                            catch
+                            {
                             }
                         }
-                        catch
+                    }
+                    //部门催办
+                    else
+                    {
+                        if (dto.AcceptSms)
                         {
+                            try
+                            {
+                                //查询部门所有账号
+                                var userlist = work.FlowAssignType == EFlowAssignType.User || work.FlowAssignType == EFlowAssignType.Role
+                                    ? await _userRepository.Queryable().Where(x => x.Id == workflowStepHandler.UserId).ToListAsync() :
+                                    await _userRepository.Queryable().Where(x => x.OrgId == workflowStepHandler.OrgId).ToListAsync();
+                                foreach (var user in userlist)
+                                {
+                                    //发送短信
+                                    var messageDto = new Share.Dtos.Push.MessageDto
+                                    {
+                                        PushBusiness = EPushBusiness.OrderUrge,
+                                        ExternalId = order.Id,
+                                        OrderId = order.Id,
+                                        PushPlatform = EPushPlatform.Sms,
+                                        Remark = order.Title,
+                                        Name = user.Name,
+                                        TemplateCode = "1002",
+                                        Params = new List<string>() { order.No },
+                                        TelNumber = user.PhoneNo,
+                                    };
+                                    await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
+                                }
+                            }
+                            catch
+                            {
+                            }
                         }
                     }
+                    await _orderUrgeRepository.AddAsync(model, HttpContext.RequestAborted);
                 }
 
 
@@ -3421,7 +3507,8 @@ public class OrderController : BaseController
         var order = await _orderRepository.GetAsync(dto.OrderId, HttpContext.RequestAborted);
         if (order is null)
             throw UserFriendlyException.SameMessage("无效工单");
-
+        var work = await _workflowStepRepository.GetAsync(p => p.Id == order.ActualHandleStepId, HttpContext.RequestAborted);
+        var workflowStepHandler = work.GetWorkflowStepHandler();
         foreach (var item in dto.UrgeOrgDtos)
         {
             var model = _mapper.Map<OrderUrge>(dto);
@@ -3434,36 +3521,78 @@ public class OrderController : BaseController
             if (dto.Files.Any())
                 model.FileJson =
                     await _fileRepository.AddFileAsync(dto.Files, model.Id, "", HttpContext.RequestAborted);
+            //泸州任务 303 当前节点处于承办部门,不管是几级部门,催办对象都是当前接办部门所属的一级部门的所有部门经办人
+            if (_appOptions.Value.IsLuZhou && !string.IsNullOrEmpty(order.OrgLevelOneCode) && order.OrgLevelOneCode != "001")
+            {
+                model.OrgId = order.OrgLevelOneCode;
+                model.OrgName = order.OrgLevelOneName;
+            }
             await _orderUrgeRepository.AddAsync(model, HttpContext.RequestAborted);
-            if (dto.AcceptSms)
+            if (_sessionContext.OrgIsCenter)
             {
-                try
+                if (dto.AcceptSms)
                 {
-                    var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
-                    //查询部门所有账号
-                    var userlist = await _userRepository.Queryable().Where(x =>
-                        x.OrgId == model.OrgId && !string.IsNullOrEmpty(x.PhoneNo) &&
-                        x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
-                    foreach (var user in userlist)
+                    try
                     {
-                        //发送短信
-                        var messageDto = new Share.Dtos.Push.MessageDto
+                        var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
+                        //查询部门所有账号
+                        var userlist = await _userRepository.Queryable().Where(x =>
+                            x.OrgId == model.OrgId && !string.IsNullOrEmpty(x.PhoneNo) &&
+                            x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
+                        foreach (var user in userlist)
                         {
-                            PushBusiness = EPushBusiness.OrderUrge,
-                            ExternalId = order.Id,
-                            OrderId = order.Id,
-                            PushPlatform = EPushPlatform.Sms,
-                            Remark = order.Title,
-                            Name = user.Name,
-                            TemplateCode = "1002",
-                            Params = new List<string>() { order.No },
-                            TelNumber = user.PhoneNo,
-                        };
-                        await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
+                            //发送短信
+                            var messageDto = new Share.Dtos.Push.MessageDto
+                            {
+                                PushBusiness = EPushBusiness.OrderUrge,
+                                ExternalId = order.Id,
+                                OrderId = order.Id,
+                                PushPlatform = EPushPlatform.Sms,
+                                Remark = order.Title,
+                                Name = user.Name,
+                                TemplateCode = "1002",
+                                Params = new List<string>() { order.No },
+                                TelNumber = user.PhoneNo,
+                            };
+                            await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
+                        }
+                    }
+                    catch
+                    {
                     }
                 }
-                catch
+            }
+            else
+            {
+                if (dto.AcceptSms)
                 {
+                    try
+                    {
+                        //查询部门所有账号
+                        var userlist = work.FlowAssignType == EFlowAssignType.User || work.FlowAssignType == EFlowAssignType.Role
+                            ? await _userRepository.Queryable().Where(x => x.Id == workflowStepHandler.UserId).ToListAsync() :
+                            await _userRepository.Queryable().Where(x => x.OrgId == workflowStepHandler.OrgId).ToListAsync();
+                        foreach (var user in userlist)
+                        {
+                            //发送短信
+                            var messageDto = new Share.Dtos.Push.MessageDto
+                            {
+                                PushBusiness = EPushBusiness.OrderUrge,
+                                ExternalId = order.Id,
+                                OrderId = order.Id,
+                                PushPlatform = EPushPlatform.Sms,
+                                Remark = order.Title,
+                                Name = user.Name,
+                                TemplateCode = "1002",
+                                Params = new List<string>() { order.No },
+                                TelNumber = user.PhoneNo,
+                            };
+                            await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
+                        }
+                    }
+                    catch
+                    {
+                    }
                 }
             }
 
@@ -3629,7 +3758,7 @@ public class OrderController : BaseController
         if (_appOptions.Value.IsLuZhou && !_sessionContext.OrgIsCenter)
             orderDtos = orderDtos.Select(p => p.DataMask()).ToList();
 
-        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderDto>(dto.ColumnInfos);
 
         var dtos = orderDtos
             .Select(stu => _mapper.Map(stu, typeof(OrderDto), dynamicClass))
@@ -3674,7 +3803,7 @@ public class OrderController : BaseController
         var (total, items) = await query
             .Includes(d => d.OrderScreens)
             .Where(d => d.Contact == dto.PhoneNo)
-            .WhereIF(_sessionContext.OrgIsCenter==false,d=>d.IsSecret==false)
+            .WhereIF(_sessionContext.OrgIsCenter == false && _appOptions.Value.IsYiBin == true, d => d.IsSecret == false)
             .WhereIF(!string.IsNullOrEmpty(dto.OrderId), d => d.Id != dto.OrderId)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
             .Select(d => new OrderHistoryOutDto
@@ -6422,8 +6551,7 @@ public class OrderController : BaseController
 
                 if (_appOptions.Value.IsLuZhou)
                 {
-                    startTime = order.ExpiredTime.Value;
-                    beginTime = startTime;
+                    startTime = DateTime.Now;
                 }
 
                 var expiredTime = await _expireTime.CalcEndTime(beginTime, startTime, order.AcceptTypeCode);
@@ -7200,11 +7328,11 @@ public class OrderController : BaseController
         }
     }
 
-	/// <summary>
-	/// 批量重提   根据传入的工单编号特提所有工单
-	/// </summary>
-	/// <returns></returns>
-	[HttpPost("order_batch_special")]
+    /// <summary>
+    /// 批量重提   根据传入的工单编号特提所有工单
+    /// </summary>
+    /// <returns></returns>
+    [HttpPost("order_batch_special")]
     [AllowAnonymous]
     public async Task BatchSpecial([FromBody] OrderBatchSpecialDto model)
     {
@@ -7212,15 +7340,15 @@ public class OrderController : BaseController
             .Includes(o => o.Workflow)
             .Includes(o => o.OrderVisits)
             .Where(o => (o.CounterSignType == null || o.CounterSignType == ECounterSignType.Department))
-            .In(o=> o.No, model.No).ToListAsync();
+            .In(o => o.No, model.No).ToListAsync();
         if (!orders.Any())
             throw UserFriendlyException.SameMessage("未查询到工单信息!");
         foreach (var order in orders)
         {
             var nextStep = await _workflowTraceRepository.Queryable()
-				.LeftJoin<SystemOrganize>((step, o) => step.HandlerOrgId == o.Id)
-				.Where((step,o) =>  step.WorkflowId == order.WorkflowId && step.TraceStyle == ETraceStyle.Flow && step.StepType == EStepType.Normal
-					&&!string.IsNullOrEmpty(step.HandlerOrgId) && o.Level == 1 && step.BusinessType == EBusinessType.Department).OrderByDescending(step => step.CreationTime)
+                .LeftJoin<SystemOrganize>((step, o) => step.HandlerOrgId == o.Id)
+                .Where((step, o) => step.WorkflowId == order.WorkflowId && step.TraceStyle == ETraceStyle.Flow && step.StepType == EStepType.Normal
+                    && !string.IsNullOrEmpty(step.HandlerOrgId) && o.Level == 1 && step.BusinessType == EBusinessType.Department).OrderByDescending(step => step.CreationTime)
                 .FirstAsync(HttpContext.RequestAborted);
             if (nextStep is null)
                 continue;

+ 1 - 0
src/Hotline.Api/Controllers/Snapshot/SnapshotController.cs

@@ -19,6 +19,7 @@ using Hotline.Share.Enums.Snapshot;
 using Hotline.Share.Tools;
 using Hotline.Snapshot;
 using Hotline.Snapshot.Interfaces;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Tools;
 using Mapster;
 using Microsoft.AspNetCore.Authorization;

+ 144 - 32
src/Hotline.Api/Controllers/TestController.cs

@@ -40,6 +40,8 @@ using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.JudicialManagement;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Mq;
+using Hotline.ThirdAccountDomainServices.Interfaces;
+using Hotline.Tools;
 using Hotline.Users;
 using Mapster;
 using MapsterMapper;
@@ -49,7 +51,9 @@ using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Options;
 using MiniExcelLibs;
 using NETCore.Encrypt;
+using Senparc.Weixin.MP.AdvancedAPIs.MerChant;
 using SqlSugar;
+using System.Threading;
 using XC.RSAUtil;
 using XF.Domain.Authentications;
 using XF.Domain.Cache;
@@ -69,11 +73,9 @@ namespace Hotline.Api.Controllers;
 public class TestController : BaseController
 {
     private readonly ILogger<TestController> _logger;
-    //private readonly IAuthorizeGenerator _authorizeGenerator;
     private readonly IOptionsSnapshot<CallCenterConfiguration> _options;
     private readonly ISessionContext _sessionContext;
     private readonly IRepository<User> _userRepository;
-
     private readonly ITypedCache<User> _cache;
     private readonly IRealtimeService _realtimeService;
     private readonly IBlacklistDomainService _blacklistDomainService;
@@ -81,25 +83,18 @@ public class TestController : BaseController
     private readonly ISugarUnitOfWork<HotlineDbContext> _uow;
     private readonly IRepository<Identity.Roles.Role> _roleRepository;
     private readonly IMediator _mediator;
-
     private readonly IDistributedLock _distributedLock;
     private readonly IRepository<OrderUrge> _orderUrgeRepository;
     private readonly IRepositoryTextSearch<OrderTs> _repositoryts;
-
     private readonly ITimeLimitDomainService _timeLimitDomainService;
     private readonly IWfModuleDomainService _wfModuleDomainService;
     private readonly IDaySettingRepository _daySettingRepository;
-    //private readonly ITrClient _trClient;
     private readonly ICapPublisher _capPublisher;
     private readonly IQueue _queue;
     private readonly IExportApplication _exportApplication;
     private readonly IRepository<WorkflowTrace> _workflowTraceRepository;
-
     private readonly IRepository<WorkflowStep> _workflowStepRepository;
-
     private readonly IWorkflowRepository _workflowRepository;
-    //private readonly IRepository<WorkflowStepHandler> _workflowStepHandleRepository;
-
     private readonly IRepository<SystemOrganize> _systemOrganizeRepository;
     private readonly IOrderRepository _orderRepository;
     private readonly IRepository<TrCallRecord> _trCallRecordRepository;
@@ -112,7 +107,6 @@ public class TestController : BaseController
     private readonly IRepository<JudicialManagementOrders> _judicialManagementOrdersRepository;
     private readonly IRepository<EnforcementOrdersHandler> _enforcementOrdersHandlerRepository;
     private readonly IWorkflowApplication _workflowApplication;
-
     private readonly IRepository<ContingencyManagementHotspot> _contingencyManagementHotspotRepository;
     private readonly IRepository<Hotspot> _hotspotRepository;
     private readonly IOrderApplication _orderApplication;
@@ -120,10 +114,7 @@ public class TestController : BaseController
     private readonly IOrderDomainService _orderDomainService;
     private readonly ICallApplication _callApplication;
     private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
-
     private readonly ISystemSettingCacheManager _systemSettingCacheManager;
-    //private readonly ITypedCache<List<User>> _cache;
-    //private readonly ICacheManager<User> _cache;
     private readonly ICalcExpireTime _expireTime;
     private readonly ICallNativeRepository _callNativeRepository;
     private readonly IRepository<OldSendProData> _oldSendProDataRepository;
@@ -132,6 +123,7 @@ public class TestController : BaseController
     private readonly IThirdIdentiyService _thirdIdentiyService;
     private readonly IServiceProvider _serviceProvider;
     private readonly IRepository<OrderDelay> _orderDelayRepository;
+    private readonly IRepository<OrderSecondaryHandling> _orderSecondaryHandlingRepository;
 
 
     public TestController(
@@ -156,14 +148,12 @@ public class TestController : BaseController
         ITimeLimitDomainService timeLimitDomainService,
         IWfModuleDomainService wfModuleDomainService,
         IDaySettingRepository daySettingRepository,
-        //ITrClient trClient,
         ICapPublisher capPublisher,
         IQueue queue,
         IExportApplication exportApplication,
         IRepository<WorkflowTrace> workflowTraceRepository,
         IRepository<WorkflowStep> workflowStepRepository,
         IWorkflowRepository workflowRepository,
-        //IRepository<WorkflowStepHandler> workflowStepHandleRepository,
         IRepository<SystemOrganize> systemOrganizeRepository,
         IOrderRepository orderRepository,
         IRepository<TrCallRecord> trCallRecordRepository,
@@ -173,14 +163,14 @@ public class TestController : BaseController
         IMapper mapper,
         IOrderApplication orderApplication,
         IRepository<Tel> telRepository,
-   IOrderReportApplication orderReportApplication,
-IRepository<EnforcementOrders> enforcementOrdersRepository,
-IRepository<JudicialManagementOrders> judicialManagementOrdersRepository,
-IRepository<EnforcementOrdersHandler> enforcementOrdersHandlerRepository,
-IRepository<ContingencyManagementHotspot> contingencyManagementHotspotRepository,
-IRepository<Hotspot> hotspotRepository,
-IOrderDomainService orderDomainService,
-ICallApplication callApplication,
+        IOrderReportApplication orderReportApplication,
+        IRepository<EnforcementOrders> enforcementOrdersRepository,
+        IRepository<JudicialManagementOrders> judicialManagementOrdersRepository,
+        IRepository<EnforcementOrdersHandler> enforcementOrdersHandlerRepository,
+        IRepository<ContingencyManagementHotspot> contingencyManagementHotspotRepository,
+        IRepository<Hotspot> hotspotRepository,
+        IOrderDomainService orderDomainService,
+        ICallApplication callApplication,
         IOptionsSnapshot<AppConfiguration> appOptions,
         ISystemSettingCacheManager systemSettingCacheManager,
         ICalcExpireTime expireTime,
@@ -190,11 +180,11 @@ ICallApplication callApplication,
         IThirdIdentiyService thirdIdentiyService,
         IOrderScreenRepository orderScreenRepository,
         IRepository<OrderVisit> orderVisitRepository,
-        IServiceProvider serviceProvider
+        IServiceProvider serviceProvider,
+        IRepository<OrderSecondaryHandling> orderSecondaryHandlingRepository
         )
     {
         _logger = logger;
-        //_authorizeGenerator = authorizeGenerator;
         _options = options;
         _sessionContext = sessionContext;
         _userRepository = userRepository;
@@ -211,14 +201,12 @@ ICallApplication callApplication,
         _timeLimitDomainService = timeLimitDomainService;
         _wfModuleDomainService = wfModuleDomainService;
         _daySettingRepository = daySettingRepository;
-        //_trClient = trClient;
         _capPublisher = capPublisher;
         _queue = queue;
         _exportApplication = exportApplication;
         _workflowTraceRepository = workflowTraceRepository;
         _workflowStepRepository = workflowStepRepository;
         _workflowRepository = workflowRepository;
-        //_workflowStepHandleRepository = workflowStepHandleRepository;
         _systemOrganizeRepository = systemOrganizeRepository;
         _orderRepository = orderRepository;
         _trCallRecordRepository = trCallRecordRepository;
@@ -246,6 +234,7 @@ ICallApplication callApplication,
         _orderVisitRepository = orderVisitRepository;
         _serviceProvider = serviceProvider;
         _orderDelayRepository = orderDelayRepository;
+        _orderSecondaryHandlingRepository = orderSecondaryHandlingRepository;
     }
 
     /// <summary>
@@ -258,7 +247,7 @@ ICallApplication callApplication,
     {
         var order = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.ReceiveProvinceNo == "");
 
-        var order1 = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.ReceiveProvinceNo =="20202020202020");
+        var order1 = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.ReceiveProvinceNo == "20202020202020");
         var order2 = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.ReceiveProvinceNo == "ZMHD995100002024111101317");
 
         var inDto = new ThirdTokenDto
@@ -266,7 +255,7 @@ ICallApplication callApplication,
             AppId = _systemSettingCacheManager.WxOpenAppId,
             Secret = _systemSettingCacheManager.WxOpenAppSecret
         };
-        return await _thirdIdentiyService.GetPhoneNumberAsync(inDto);
+        return await _thirdIdentiyService.GetPhoneNumberAsync(inDto, CancellationToken.None);
     }
 
     /// <summary>
@@ -549,7 +538,7 @@ ICallApplication callApplication,
         //var query = _userRepository.Queryable().Where(x => false);
         //await _capPublisher.PublishDelay(EventNames.OrderRelateCall, "123", cancellationToken: HttpContext.RequestAborted);
         var times = await _expireTime.CalcWorkTimeEx(
-                       DateTime.Parse("2025-02-21 16:00:11.154098"),DateTime.Parse("2025-02-28 11:27:11.441577"),false);
+                       DateTime.Parse("2025-02-21 16:00:11.154098"), DateTime.Parse("2025-02-28 11:27:11.441577"), false);
         return OpenResponse.Ok(times);
     }
 
@@ -1249,7 +1238,38 @@ ICallApplication callApplication,
             creationTimeHandleDurationWorkday = creationTimeHandleDurationWorkday <= 0 ? 10 : creationTimeHandleDurationWorkday;
             centerToOrgHandleDurationWorkday = centerToOrgHandleDurationWorkday <= 0 ? 10 : centerToOrgHandleDurationWorkday;
 
-            order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday);
+            double? secondaryHandlingDurationWorkday = null;
+            DateTime? secondaryHandlingAuditTime = null;
+
+            //计算二次办理时长
+            if (_appOptions.Value.IsZiGong)
+            {
+
+                //查询是否有二次办理申请通过的
+                var orderSecondaryData = await _orderSecondaryHandlingRepository.GetAsync(p => p.OrderId == order.Id &&
+                  p.IsHandel == false && p.State == ESecondaryHandlingState.End, HttpContext.RequestAborted);
+                if (orderSecondaryData != null)
+                {
+                    orderSecondaryData.IsHandel = true;
+                    await _orderSecondaryHandlingRepository.UpdateAsync(orderSecondaryData, HttpContext.RequestAborted);
+                    if (orderSecondaryData.AuditTime.HasValue)
+                    {
+                        secondaryHandlingAuditTime = orderSecondaryData.AuditTime;
+                        secondaryHandlingDurationWorkday = orderSecondaryData.AuditTime.HasValue
+                            ?
+                            await _expireTime.CalcWorkTimeEx(
+                                orderSecondaryData.AuditTime.Value, now,
+                            false)
+                            : null;
+                    }
+                }
+                //处理办理时长
+            }
+
+            order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday,
+                secondaryHandlingDurationWorkday, secondaryHandlingAuditTime);
+
+            // order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday, null, null);
 
         }
 
@@ -1335,8 +1355,36 @@ ICallApplication callApplication,
                 : 0;
             creationTimeHandleDurationWorkday = creationTimeHandleDurationWorkday <= 0 ? 10 : creationTimeHandleDurationWorkday;
             centerToOrgHandleDurationWorkday = centerToOrgHandleDurationWorkday <= 0 ? 10 : centerToOrgHandleDurationWorkday;
+            double? secondaryHandlingDurationWorkday = null;
+            DateTime? secondaryHandlingAuditTime = null;
 
-            order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday);
+            //计算二次办理时长
+            if (_appOptions.Value.IsZiGong)
+            {
+
+                //查询是否有二次办理申请通过的
+                var orderSecondaryData = await _orderSecondaryHandlingRepository.GetAsync(p => p.OrderId == order.Id &&
+                  p.IsHandel == false && p.State == ESecondaryHandlingState.End, HttpContext.RequestAborted);
+                if (orderSecondaryData != null)
+                {
+                    orderSecondaryData.IsHandel = true;
+                    await _orderSecondaryHandlingRepository.UpdateAsync(orderSecondaryData, HttpContext.RequestAborted);
+                    if (orderSecondaryData.AuditTime.HasValue)
+                    {
+                        secondaryHandlingAuditTime = orderSecondaryData.AuditTime;
+                        secondaryHandlingDurationWorkday = orderSecondaryData.AuditTime.HasValue
+                            ?
+                            await _expireTime.CalcWorkTimeEx(
+                                orderSecondaryData.AuditTime.Value, now,
+                            false)
+                            : null;
+                    }
+                }
+                //处理办理时长
+            }
+
+            order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday,
+                secondaryHandlingDurationWorkday, secondaryHandlingAuditTime);
             order.FileUserId = notification.HandlerId;
             order.FileUserName = notification.HandlerName;
             order.FileUserOrgId = notification.HandlerOrgId;
@@ -1429,4 +1477,68 @@ ICallApplication callApplication,
     //    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFiled, orderFlowDto, cancellationToken: cancellationToken);
     //}
 
+    [AllowAnonymous]
+    [HttpGet("TestExport")]
+    public async Task<FileStreamResult> TestExport()
+    {
+        var columns = new List<ColumnInfo>
+        {
+            /*
+             *9
+               :
+               {prop: "title", name: "工单标题"}
+               10
+               :
+               {prop: "expiredTime", name: "期满时间"}
+
+               {prop: "reTransactNum", name: "重办次数"}
+             */
+            new ColumnInfo { Prop = "title", Name = "工单标题" },
+            new ColumnInfo { Prop = "expiredTime", Name = "期满时间" },
+            new ColumnInfo { Prop = "reTransactNum", Name = "重办次数" },
+        };
+        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<MyClass>(columns);
+
+        //var order = await _orderRepository.GetAsync("08dd65e7-7a7c-43ce-8212-242435a18216", HttpContext.RequestAborted);
+        //var dto = _mapper.Map<OrderDto>(order);
+
+        var dtos = new List<MyClass> {
+            new MyClass
+        {
+            Title = "测试标题",
+            ExpiredTime = DateTime.Now,
+            ReTransactNum = 12
+        },
+            new MyClass
+            {
+                Title = "测试标题1",
+                ExpiredTime = DateTime.Now.AddDays(1),
+                ReTransactNum = 13
+            },
+            new MyClass
+            {
+                Title = "测试标题2",
+                ExpiredTime = DateTime.Now.AddDays(2),
+                ReTransactNum = 14
+            }
+        };
+
+        //dynamic temp = _mapper.Map(dtos, typeof(List<MyClass>), dynamicClass);
+
+        dynamic temp = dtos
+            .Select(stu => _mapper.Map(stu, typeof(MyClass), dynamicClass))
+            .Cast<object>()
+            .ToList();
+
+        var stream = ExcelHelper.CreateStream(temp);
+
+        return ExcelStreamResult(stream, "工单数据");
+    }
+}
+
+class MyClass
+{
+    public string Title { get; set; }
+    public DateTime ExpiredTime { get; set; }
+    public int ReTransactNum { get; set; }
 }

+ 2 - 1
src/Hotline.Api/Controllers/WorkflowController.cs

@@ -354,10 +354,11 @@ public class WorkflowController : BaseController
     /// 退回(返回前一节点)
     /// </summary>
     [HttpPost("previous")]
+    [Obsolete("即将弃用")]
     [LogFilterAlpha("审核退回")]
     public async Task Previous([FromBody] PreviousWorkflowDto dto)
     {
-        await _workflowApplication.PreviousAsync(dto, cancellationToken: HttpContext.RequestAborted);
+        await _workflowDomainService.PreviousAsync(dto, cancellationToken: HttpContext.RequestAborted);
     }
 
     /// <summary>

+ 2 - 1
src/Hotline.Api/StartupExtensions.cs

@@ -38,6 +38,7 @@ using Hotline.Orders.DatabaseEventHandler;
 using Hotline.Ai.XingTang;
 using Hotline.Pdf;
 using Hotline.XingTang;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 
 
 namespace Hotline.Api;
@@ -214,7 +215,7 @@ internal static class StartupExtensions
         services.AddScoped<IExpireTimeSupplier, WorkDaySupplier>();
         services.AddScoped<IExpireTimeSupplier, HourSupplier>();
 
-        services.AddScoped<Users.IThirdIdentiyService, WeChatService>();
+        services.AddScoped<IThirdIdentiyService, WeChatService>();
 
         services.AddWeChatService();
 

+ 9 - 9
src/Hotline.Application/FlowEngine/IWorkflowApplication.cs

@@ -43,15 +43,15 @@ namespace Hotline.Application.FlowEngine
         ///// </summary>
         //Task<Workflow> NextAsync(NextWorkflowDto dto, DateTime? expiredTime = null, CancellationToken cancellationToken = default);
 
-        /// <summary>
-        /// 退回(返回前一节点)
-        /// </summary>
-        Task<(Workflow workflow, WorkflowStep currentStep, StepDefine prevDefine,
-                WorkflowStep prevStep, WorkflowStep newStep, EFlowDirection flowDirection)>
-            PreviousAsync(PreviousWorkflowDto dto, 
-                EHandleMode handleMode = EHandleMode.Previous,
-                Action<Workflow, WorkflowStep, StepDefine, WorkflowStep, WorkflowStep>? newStepConfig = null,
-                CancellationToken cancellationToken = default);
+        ///// <summary>
+        ///// 退回(返回前一节点)
+        ///// </summary>
+        //Task<(Workflow workflow, WorkflowStep currentStep, StepDefine prevDefine,
+        //        WorkflowStep prevStep, WorkflowStep newStep, EFlowDirection flowDirection)>
+        //    PreviousAsync(PreviousWorkflowDto dto, 
+        //        EHandleMode handleMode = EHandleMode.Previous,
+        //        Action<Workflow, WorkflowStep, StepDefine, WorkflowStep, WorkflowStep>? newStepConfig = null,
+        //        CancellationToken cancellationToken = default);
 
         /// <summary>
         /// 工单退回(返回前一节点)

+ 20 - 19
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -344,26 +344,27 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     //    return workflow;
     //}
 
-    /// <summary>
-    /// 退回(返回前一节点)
-    /// </summary>
-    public async Task<(Workflow workflow, WorkflowStep currentStep, StepDefine prevDefine,
-            WorkflowStep prevStep, WorkflowStep newStep, EFlowDirection flowDirection)>
-        PreviousAsync(PreviousWorkflowDto dto,
-            EHandleMode handleMode = EHandleMode.Previous,
-            Action<Workflow, WorkflowStep, StepDefine, WorkflowStep, WorkflowStep>? newStepConfig = null,
-            CancellationToken cancellationToken = default)
-    {
-        var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
-            withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
 
-        return await _workflowDomainService.PreviousAsync(workflow, dto, new OperatorInfo(
-            _sessionContext.RequiredUserId, _sessionContext.UserName,
-            _sessionContext.RequiredOrgId, _sessionContext.OrgName,
-            _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
-            _sessionContext.OrgIsCenter, _sessionContext.Roles,
-            _sessionContext.OrgLevel), handleMode, newStepConfig, cancellationToken);
-    }
+    ///// <summary>
+    ///// 退回(返回前一节点)
+    ///// </summary>
+    //public async Task<(Workflow workflow, WorkflowStep currentStep, StepDefine prevDefine,
+    //        WorkflowStep prevStep, WorkflowStep newStep, EFlowDirection flowDirection)>
+    //    PreviousAsync(PreviousWorkflowDto dto,
+    //        EHandleMode handleMode = EHandleMode.Previous,
+    //        Action<Workflow, WorkflowStep, StepDefine, WorkflowStep, WorkflowStep>? newStepConfig = null,
+    //        CancellationToken cancellationToken = default)
+    //{
+    //    var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
+    //        withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
+
+    //    return await _workflowDomainService.PreviousAsync(workflow, dto, new OperatorInfo(
+    //        _sessionContext.RequiredUserId, _sessionContext.UserName,
+    //        _sessionContext.RequiredOrgId, _sessionContext.OrgName,
+    //        _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
+    //        _sessionContext.OrgIsCenter, _sessionContext.Roles,
+    //        _sessionContext.OrgLevel), handleMode, newStepConfig, cancellationToken);
+    //}
 
     /// <summary>
     /// 工单退回(返回前一节点)

+ 34 - 8
src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs

@@ -1,6 +1,5 @@
 using DotNetCore.CAP;
 using Hotline.Application.CallCenter;
-using Hotline.Application.JudicialManagement;
 using Hotline.Application.Orders;
 using Hotline.Caching.Interfaces;
 using Hotline.CallCenter.Tels;
@@ -11,10 +10,8 @@ using Hotline.FlowEngine.WorkflowModules;
 using Hotline.JudicialManagement.Notifies;
 using Hotline.KnowledgeBase;
 using Hotline.Orders;
-using Hotline.SeedData;
 using Hotline.Settings;
 using Hotline.Settings.TimeLimitDomain;
-using Hotline.Settings.TimeLimits;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Dtos.TrCallCenter;
@@ -42,7 +39,6 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
     private readonly ICapPublisher _capPublisher;
     private readonly IMapper _mapper;
     private readonly IRepository<OrderDelay> _orderDelayRepository;
-    // private readonly ITimeLimitDomainService _timeLimitDomainService;
     private readonly ILogger<WorkflowEndHandler> _logger;
     private readonly IKnowledgeRepository _knowledgeRepository;
     private readonly ICallApplication _callApplication;
@@ -51,6 +47,7 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
     private readonly Publisher _publisher;
     private readonly ICalcExpireTime _expireTime;
     private readonly IRepository<OrderTerminate> _orderTerminateRepository;
+    private readonly IRepository<OrderSecondaryHandling> _orderSecondaryHandlingRepository;
 
     public WorkflowEndHandler(
         IMapper mapper,
@@ -62,14 +59,14 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
         IKnowledgeRepository knowledgeRepository,
         IRepository<OrderDelay> orderDelayRepository,
         ICapPublisher capPublisher,
-        // ITimeLimitDomainService timeLimitDomainService,
         ICallApplication callApplication,
         IOptionsSnapshot<AppConfiguration> appOptions,
         ISystemSettingCacheManager systemSettingCacheManager,
         Publisher publisher,
         ILogger<WorkflowEndHandler> logger,
         ICalcExpireTime expireTime,
-        IRepository<OrderTerminate> orderTerminateRepository)
+        IRepository<OrderTerminate> orderTerminateRepository,
+        IRepository<OrderSecondaryHandling> orderSecondaryHandlingRepository)
     {
         _mapper = mapper;
         _knowledgeDomainService = knowledgeDomainService;
@@ -80,7 +77,6 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
         _knowledgeRepository = knowledgeRepository;
         _orderDelayRepository = orderDelayRepository;
         _capPublisher = capPublisher;
-        //_timeLimitDomainService = timeLimitDomainService;
         _callApplication = callApplication;
         _appOptions = appOptions;
         _systemSettingCacheManager = systemSettingCacheManager;
@@ -88,6 +84,7 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
         _logger = logger;
         _expireTime = expireTime;
         _orderTerminateRepository = orderTerminateRepository;
+        _orderSecondaryHandlingRepository = orderSecondaryHandlingRepository;
     }
 
     /// <summary>Handles a notification</summary>
@@ -164,7 +161,36 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                     creationTimeHandleDurationWorkday = creationTimeHandleDurationWorkday <= 0 ? 10 : creationTimeHandleDurationWorkday;
                     centerToOrgHandleDurationWorkday = centerToOrgHandleDurationWorkday <= 0 ? 10 : centerToOrgHandleDurationWorkday;
 
-                    order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday);
+                    double? secondaryHandlingDurationWorkday = null;
+                    DateTime? secondaryHandlingAuditTime = null;
+
+                    //计算二次办理时长
+                    if (_appOptions.Value.IsZiGong)
+                    {
+
+                        //查询是否有二次办理申请通过的
+                        var orderSecondaryData = await _orderSecondaryHandlingRepository.GetAsync(p => p.OrderId == order.Id &&
+                          p.IsHandel == false && p.State == ESecondaryHandlingState.End, cancellationToken);
+                        if (orderSecondaryData != null)
+                        {
+                            //处理办理时长
+                            orderSecondaryData.IsHandel = true;
+                            await _orderSecondaryHandlingRepository.UpdateAsync(orderSecondaryData, cancellationToken);
+                            if (orderSecondaryData.AuditTime.HasValue)
+                            {
+                                secondaryHandlingAuditTime = orderSecondaryData.AuditTime;
+                                secondaryHandlingDurationWorkday = orderSecondaryData.AuditTime.HasValue
+                                    ?
+                                    await _expireTime.CalcWorkTimeEx(
+                                        orderSecondaryData.AuditTime.Value, now,
+                                    false)
+                                    : null;
+                            }
+                        }
+                    }
+
+                    order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday,
+                        secondaryHandlingDurationWorkday, secondaryHandlingAuditTime);
                     order.FileUserId = notification.Trace.HandlerId;
                     order.FileUserName = notification.Trace.HandlerName;
                     order.FileUserOrgId = notification.Trace.HandlerOrgId;

+ 3 - 2
src/Hotline.Application/Identity/IIdentityAppService.cs

@@ -8,6 +8,7 @@ using Fw.Utility.UnifyResponse;
 using Hotline.Share.Dtos.Identity;
 using Hotline.Users;
 using Hotline.Share.Dtos.Snapshot;
+using DocumentFormat.OpenXml.Drawing.Diagrams;
 
 namespace Hotline.Application.Identity
 {
@@ -19,14 +20,14 @@ namespace Hotline.Application.Identity
         /// <param name="dto"></param>
         /// <returns></returns>
         /// <exception cref="UserFriendlyException"></exception>
-        Task<TokenOutDto> GetThredTokenAsync(ThirdTokenInDto dto);
+        Task<Dictionary<string, object>> GetThredTokenAsync(ThirdTokenInDto dto, CancellationToken token);
 
         /// <summary>
         /// 根据OpenId刷新令牌
         /// </summary>
         /// <param name="openId"></param>
         /// <returns></returns>
-        Task<TokenOutDto> RefreshTokenAsync(string openId);
+        Task<Dictionary<string, object>> RefreshTokenAsync(string openId, CancellationToken token);
 
         Task<string> LoginAsync(LoginDto dto, CancellationToken cancellationToken);
 

+ 27 - 51
src/Hotline.Application/Identity/IdentityAppService.cs

@@ -17,8 +17,9 @@ using Hotline.Share.Enums.Identity;
 using Hotline.Share.Enums.Snapshot;
 using Hotline.Share.Enums.User;
 using Hotline.Share.Tools;
-using Hotline.Snapshot;
 using Hotline.Snapshot.Interfaces;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
 using IdentityModel;
 using Mapster;
@@ -37,8 +38,6 @@ namespace Hotline.Application.Identity;
 public class IdentityAppService : IIdentityAppService, IScopeDependency
 {
     private readonly IAccountRepository _accountRepository;
-    private readonly IRepository<Citizen> _citizenRepository;
-    private readonly ISessionContext _sessionContext;
     private readonly IAccountDomainService _accountDomainService;
     private readonly IRepository<User> _userRepository;
     private readonly IJwtSecurity _jwtSecurity;
@@ -48,12 +47,10 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
     private readonly IRepository<Scheduling> _schedulingRepository;
     private readonly IOrderDomainService _orderDomainService;
     private readonly ISystemSettingCacheManager _systemSettingCacheManager;
-    private readonly IThirdIdentiyService _thirdIdentiyService;
     private readonly IThirdAccountRepository _thirdAccountRepository;
-    private readonly IGuiderInfoRepository _guiderInfoRepository;
-    private readonly IVolunteerRepository _volunteerRepository;
     private readonly ISystemLogRepository _systemLog;
-
+    private readonly ThirdIdentiyFactory _thirdIdentiyFactory;
+    private readonly ThirdAccountDomainFactory _thirdAccountDomainFactory;
 
     public IdentityAppService(
         IAccountRepository accountRepository,
@@ -66,13 +63,10 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
         IRepository<Scheduling> schedulingRepository,
         IOrderDomainService orderDomainService,
         ISystemSettingCacheManager systemSettingCacheManager,
-        IThirdIdentiyService thirdIdentiyService,
         IThirdAccountRepository thirdAccountRepository,
-        ISessionContext sessionContext,
-        IRepository<Citizen> citizenRepository,
-        IGuiderInfoRepository guiderInfoRepository,
-        IVolunteerRepository volunteerRepository,
-        ISystemLogRepository systemLog)
+        ISystemLogRepository systemLog,
+        ThirdIdentiyFactory thirdIdentiyFactory,
+        ThirdAccountDomainFactory thirdAccountDomainFactory)
     {
         _accountRepository = accountRepository;
         _accountDomainService = accountDomainService;
@@ -84,13 +78,10 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
         _schedulingRepository = schedulingRepository;
         _orderDomainService = orderDomainService;
         _systemSettingCacheManager = systemSettingCacheManager;
-        _thirdIdentiyService = thirdIdentiyService;
         _thirdAccountRepository = thirdAccountRepository;
-        _sessionContext = sessionContext;
-        _citizenRepository = citizenRepository;
-        _guiderInfoRepository = guiderInfoRepository;
-        _volunteerRepository = volunteerRepository;
         _systemLog = systemLog;
+        _thirdIdentiyFactory = thirdIdentiyFactory;
+        _thirdAccountDomainFactory = thirdAccountDomainFactory;
     }
 
     public async Task<string> OldToNewLoginAsync(HotlineLoginOldToNewDto dto, CancellationToken cancellationToken)
@@ -316,50 +307,35 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
     /// <param name="dto"></param>
     /// <returns></returns>
     /// <exception cref="UserFriendlyException"></exception>
-    public async Task<TokenOutDto> GetThredTokenAsync(ThirdTokenInDto dto)
+    public async Task<Dictionary<string, object>> GetThredTokenAsync(ThirdTokenInDto dto, CancellationToken token)
     {
         var thirdDto = dto.Adapt<ThirdTokenDto>();
-        if (dto.ThirdType == EThirdType.WeChat)
-        {
-            thirdDto.AppId = _systemSettingCacheManager.WxOpenAppId;
-            thirdDto.Secret = _systemSettingCacheManager.WxOpenAppSecret;
-        }
-        var thirdToken = await _thirdIdentiyService.GetTokenAsync(thirdDto);
-        var phone = await _thirdIdentiyService.GetPhoneNumberAsync(thirdDto);
+        thirdDto = await _thirdAccountDomainFactory.GetThirdParameterAsync(thirdDto, token);
+        var thirdToken = await _thirdIdentiyFactory.GetTokenAsync(thirdDto, token);
+        var phone = await _thirdIdentiyFactory.GetPhoneNumberAsync(thirdDto, token);
         var thirdAccount = await _thirdAccountRepository.GetByOpenIdAsync(thirdToken.OpenId);
 
         // 新用户注册
         if (thirdAccount is null)
         {
             thirdAccount = thirdToken.Adapt<ThirdAccount>();
-            thirdAccount.CitizenType = EReadPackUserType.Citizen;
             thirdAccount.PhoneNumber = phone.PhoneNumber;
-            var guider =  await _guiderInfoRepository.GetByPhoneNumberAsync(phone.PhoneNumber);
-            if (guider != null)
-            {
-                thirdAccount.CitizenType = EReadPackUserType.Guider;
-                thirdAccount.UserId = guider.Id;
-            }
-            else
-            {
-                var citizen = await _citizenRepository.Queryable().Where(m => m.PhoneNumber == phone.PhoneNumber).FirstAsync();
-                thirdAccount.UserId = citizen?.Id;
-            }
             thirdAccount.Id = await _thirdAccountRepository.AddAsync(thirdAccount);
+            await _thirdAccountDomainFactory.RegisterAsync(thirdAccount, token);
         }
 
-        return await GetJwtToken(thirdAccount);
+        return await GetJwtToken(thirdAccount, token);
     }
 
-    public async Task<TokenOutDto> RefreshTokenAsync(string openId)
+    public async Task<Dictionary<string, object>> RefreshTokenAsync(string openId, CancellationToken token)
     {
         var thirdAccount = await _thirdAccountRepository.GetByOpenIdAsync(openId)
             ?? throw UserFriendlyException.SameMessage("未找到用户信息");
 
-        return await GetJwtToken(thirdAccount);
+        return await GetJwtToken(thirdAccount, token);
     }
 
-    private async Task<TokenOutDto> GetJwtToken(ThirdAccount thirdAccount)
+    private async Task<Dictionary<string, object>> GetJwtToken(ThirdAccount thirdAccount, CancellationToken cancel)
     {
         var jwtOptions = _identityOptionsAccessor.Value.Jwt;
         var claims = new List<Claim>
@@ -369,20 +345,20 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
             new(JwtClaimTypes.Scope, jwtOptions.Scope),
             new(AppClaimTypes.OpenId, thirdAccount.OpenId),
         };
+        claims = await _thirdAccountDomainFactory.GetClaimAsync(thirdAccount, claims, cancel);
         var audience = new AudienceTicket(thirdAccount.Id);
         var expiredSeconds = jwtOptions.Expired <= 0 ? 3600 : jwtOptions.Expired;
         await _cacheAudience.SetAsync(audience.Id, audience, TimeSpan.FromSeconds(expiredSeconds));
         var token = _jwtSecurity.EncodeJwtToken(claims, audience.Ticket);
-        var isVolunteer = await _volunteerRepository.IsVolunteerAsync(thirdAccount.PhoneNumber);
-        return new TokenOutDto()
+        
+        var dicOutData = new Dictionary<string, object>()
         {
-            UserType = thirdAccount.CitizenType,
-            Token = token,
-            IsVolunteer = isVolunteer,
-            OpenId = thirdAccount.OpenId,
-            PhoneNumber = thirdAccount.PhoneNumber,
-            InvitationCode = thirdAccount.InvitationCode,
-            UserName = thirdAccount.UserName
+            { "Token", token },
+            { "OpenId", thirdAccount.OpenId },
+            { "PhoneNumber", thirdAccount.PhoneNumber },
+            { "UserName", thirdAccount.UserName }
         };
+        dicOutData = await _thirdAccountDomainFactory.GetLoginOutDataAsync(thirdAccount, dicOutData, cancel);
+        return dicOutData;
     }
 }

+ 1 - 1
src/Hotline.Application/Mappers/MapperConfigs.cs

@@ -17,10 +17,10 @@ using Hotline.Share.Dtos.Settings;
 using Hotline.Share.Dtos.TrCallCenter;
 using Hotline.Share.Dtos.Snapshot;
 using Hotline.Share.Enums.Order;
-using Hotline.Snapshot;
 using Mapster;
 using XF.Domain.Entities;
 using Hotline.Share.Tools;
+using Hotline.ThirdAccountDomainServices;
 
 namespace Hotline.Application.Mappers
 {

+ 15 - 1
src/Hotline.Application/Orders/OrderApplication.cs

@@ -350,7 +350,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         creationTimeHandleDurationWorkday = creationTimeHandleDurationWorkday <= 0 ? 10 : creationTimeHandleDurationWorkday;
         centerToOrgHandleDurationWorkday = centerToOrgHandleDurationWorkday <= 0 ? 10 : centerToOrgHandleDurationWorkday;
 
-        order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday);
+        order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday, null, null);
         await _orderRepository.UpdateAsync(order, cancellationToken);
     }
 
@@ -1264,6 +1264,19 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             await _orderRepository.UpdateAsync(order, cancellationToken);
         }
 
+        //更新会签状态
+        if (_appOptions.Value.IsZiGong)
+        {
+            if (dto.Workflow.FlowDirection == EFlowDirection.CenterToOrg)
+            {
+                order.CounterSignType = dto.Workflow.NextHandlers.Count > 1 ? ECounterSignType.Center : null;
+            }
+            else if (dto.Workflow.FlowDirection == EFlowDirection.OrgToOrg)
+            {
+                order.CounterSignType = dto.Workflow.NextHandlers.Count > 1 ? ECounterSignType.Department : null;
+            }
+        }
+
 
         if (dto.Data.LeaderSMSKey != null)
         {
@@ -3450,6 +3463,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             {
                 var workflowStep = await _workflowStepRepository.Queryable().Where(x => x.Id == order.Workflow.TopCountersignStepId)
                     .FirstAsync(cancellationToken);
+
                 if (workflowStep != null)
                 {
                     var dtoEnd = new EndCountersignDto() { CountersignId = workflowStep.StartCountersignId };

+ 1 - 0
src/Hotline.Application/Orders/OrderSecondaryHandlingApplication.cs

@@ -168,6 +168,7 @@ namespace Hotline.Application.Orders
             model.AuditId = _sessionContext.UserId;
             model.AuditUser = _sessionContext.UserName;
             model.AuditTime = DateTime.Now;
+            model.IsHandel = false;
             var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == model.OrderId && x.VisitState == EVisitState.Visited, cancellationToken);
             if (model.State == ESecondaryHandlingState.End)
             {

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
src/Hotline.Application/Snapshot/DefaultSnapshotApplication.cs


+ 1 - 0
src/Hotline.Application/Snapshot/RedPackApplication.cs

@@ -12,6 +12,7 @@ using Hotline.Share.Enums.Snapshot;
 using Hotline.Share.Tools;
 using Hotline.Snapshot;
 using Hotline.Snapshot.Interfaces;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Mapster;
 using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.Logging;

+ 24 - 29
src/Hotline.Application/Snapshot/SnapshotApplicationBase.cs

@@ -4,7 +4,6 @@ using Hotline.Share.Dtos.Article;
 using Hotline.Share.Dtos.Snapshot;
 using Hotline.Share.Tools;
 using Hotline.Snapshot;
-using Hotline.Users;
 using SqlSugar;
 using XF.Domain.Authentications;
 using XF.Domain.Dependency;
@@ -35,6 +34,7 @@ using Hotline.Snapshot.Notifications;
 using Hotline.EventBus;
 using Hotline.Quality.Notifications;
 using XF.Utility.EnumExtensions;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 
 namespace Hotline.Application.Snapshot;
 
@@ -69,7 +69,6 @@ public abstract class SnapshotApplicationBase
     private readonly IGuiderSystemService _guiderSystemService;
     private readonly ICapPublisher _capPublisher;
     private readonly Publisher _publisher;
-    private readonly IGuiderInfoRepository _guiderInfoRepository;
     private readonly IFileDomainService _fileDomainService;
     private readonly ICommunityInfoRepository _communityInfoRepository;
     private readonly IRedPackAuditRepository _redPackAuditRepository;
@@ -78,8 +77,9 @@ public abstract class SnapshotApplicationBase
     private readonly IOrderVisitDetailRepository _orderVisitDetailRepository;
     private readonly IInviteCodeRecordRepository _inviteCodeRecordRepository;
     private readonly IInviteCodeRepository _inviteCodeRepository;
+    private readonly ISnapshotUserInfoRepository _snapshotUserInfoRepository;
 
-    public SnapshotApplicationBase(IThirdIdentiyService thirdLoginService, IIndustryRepository industryRepository, ISnapshotBulletinRepository bulletinRepository, ISessionContext sessionContext, IRepository<RedPackRecord> redPackRecordRepository, IRepository<Order> orderRepository, IThirdAccountRepository thirdAccountRepository, IOrderSnapshotRepository orderSnapshotRepository, ISystemSettingCacheManager systemSettingCacheManager, ISystemAreaDomainService systemAreaDomainService, IFileRepository fileRepository, ISystemDicDataCacheManager systemDicDataCacheManager, ISnapshotOrderPublishRepository snapshotOrderPublishRepository, IRepository<WorkflowTrace> workflowTraceRepository, IPractitionerRepository practitionerRepository, IRepository<SystemArea> systemAreaRepository, IVolunteerRepository volunteerRepository, IVolunteerReportRepository volunteerReportRepository, ISystemLogRepository systemLog, IGuiderSystemService guiderSystemService, ICapPublisher capPublisher, Publisher publisher, IGuiderInfoRepository guiderInfoRepository, IFileDomainService fileDomainService, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IOrderVisitRepository orderVisitRepository, IOrderVisitDetailRepository orderVisitDetailRepository, IRedPackGuiderAuditRepository redPackGuiderAuditRepository, IInviteCodeRecordRepository inviteCodeRecordRepository, IInviteCodeRepository inviteCodeRepository)
+    public SnapshotApplicationBase(IThirdIdentiyService thirdLoginService, IIndustryRepository industryRepository, ISnapshotBulletinRepository bulletinRepository, ISessionContext sessionContext, IRepository<RedPackRecord> redPackRecordRepository, IRepository<Order> orderRepository, IThirdAccountRepository thirdAccountRepository, IOrderSnapshotRepository orderSnapshotRepository, ISystemSettingCacheManager systemSettingCacheManager, ISystemAreaDomainService systemAreaDomainService, IFileRepository fileRepository, ISystemDicDataCacheManager systemDicDataCacheManager, ISnapshotOrderPublishRepository snapshotOrderPublishRepository, IRepository<WorkflowTrace> workflowTraceRepository, IPractitionerRepository practitionerRepository, IRepository<SystemArea> systemAreaRepository, IVolunteerRepository volunteerRepository, IVolunteerReportRepository volunteerReportRepository, ISystemLogRepository systemLog, IGuiderSystemService guiderSystemService, ICapPublisher capPublisher, Publisher publisher, IFileDomainService fileDomainService, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IOrderVisitRepository orderVisitRepository, IOrderVisitDetailRepository orderVisitDetailRepository, IRedPackGuiderAuditRepository redPackGuiderAuditRepository, IInviteCodeRecordRepository inviteCodeRecordRepository, IInviteCodeRepository inviteCodeRepository, ISnapshotUserInfoRepository snapshotUserInfoRepository)
     {
         _thirdLoginService = thirdLoginService;
         _industryRepository = industryRepository;
@@ -103,7 +103,6 @@ public abstract class SnapshotApplicationBase
         _guiderSystemService = guiderSystemService;
         _capPublisher = capPublisher;
         _publisher = publisher;
-        _guiderInfoRepository = guiderInfoRepository;
         _fileDomainService = fileDomainService;
         _communityInfoRepository = communityInfoRepository;
         _redPackAuditRepository = redPackAuditRepository;
@@ -112,6 +111,7 @@ public abstract class SnapshotApplicationBase
         _redPackGuiderAuditRepository = redPackGuiderAuditRepository;
         _inviteCodeRecordRepository = inviteCodeRecordRepository;
         _inviteCodeRepository = inviteCodeRepository;
+        _snapshotUserInfoRepository = snapshotUserInfoRepository;
     }
 
     #region 小程序
@@ -295,20 +295,17 @@ public abstract class SnapshotApplicationBase
     /// <returns></returns>
     public async Task<SnapshotUserInfoOutDto> GetSnapshotUserInfoAsync()
     {
-        var openId = _sessionContext.OpenId;
-        var thirdAccount = await _thirdAccountRepository.GetByOpenIdAsync(openId);
-        if (thirdAccount.PhoneNumber.IsNullOrEmpty() && _sessionContext.Phone.NotNullOrEmpty())
-            thirdAccount.PhoneNumber = _sessionContext.Phone;
+        var userInfo = await _snapshotUserInfoRepository.GetAsync(_sessionContext.UserId);
 
         var dayTime = DateTime.Now;
         var readPack = await _redPackRecordRepository.Queryable()
-            .Where(m => m.WXOpenId == openId && m.PickupStatus == ERedPackPickupStatus.Received)
+            .Where(m => m.WXOpenId == _sessionContext.OpenId && m.PickupStatus == ERedPackPickupStatus.Received)
             .Where(m => m.CreationTime.Date == dayTime.Date)
             .Select(m => SqlFunc.AggregateSum(m.Amount))
             .FirstAsync();
 
         var outDto = await _orderRepository.Queryable()
-            .Where(m => m.Contact == thirdAccount.PhoneNumber)
+            .Where(m => m.Contact == userInfo.PhoneNumber)
             .Select(m => new SnapshotUserInfoOutDto
             {
                 NoReplyCount = SqlFunc.AggregateSum(SqlFunc.IIF(m.Status < EOrderStatus.Filed, 1, 0)),
@@ -317,8 +314,8 @@ public abstract class SnapshotApplicationBase
             }).FirstAsync();
 
         outDto.DayAmount = readPack;
-        outDto.TotalAmount = thirdAccount.TotalAmount;
-        outDto.PhoneNumber = thirdAccount.PhoneNumber;
+        outDto.TotalAmount = userInfo.TotalAmount;
+        outDto.PhoneNumber = userInfo.PhoneNumber;
         return outDto;
     }
 
@@ -468,7 +465,7 @@ public abstract class SnapshotApplicationBase
     /// <returns></returns>
     public async Task<string> GetRedPackReceivedTotalAsync(CancellationToken cancellationToken)
     {
-        var member = await _thirdAccountRepository.GetAsync(m => m.OpenId == _sessionContext.OpenId || m.PhoneNumber == _sessionContext.Phone, cancellationToken)
+        var member = await _snapshotUserInfoRepository.GetAsync(m => m.Id == _sessionContext.UserId, cancellationToken)
             ?? throw UserFriendlyException.SameMessage("用户不存在");
         return member.TotalAmount.ToYuanFinance();
     }
@@ -529,9 +526,9 @@ public abstract class SnapshotApplicationBase
         { 
             throw new UserFriendlyException(200, "邀请码格式错误");
         }
-        var third = await _thirdAccountRepository.GetByOpenIdAsync(_sessionContext.OpenId)
+        var userInfo = await _snapshotUserInfoRepository.GetAsync(_sessionContext.UserId)
             ?? throw UserFriendlyException.SameMessage("用户不存在");
-        if (third.InvitationCode.NotNullOrEmpty())
+        if (userInfo.InvitationCode.NotNullOrEmpty())
         {
             throw new UserFriendlyException(200, "邀请码已存在");
         }
@@ -539,20 +536,21 @@ public abstract class SnapshotApplicationBase
         {
             throw new UserFriendlyException(200, "邀请码已经被使用");
         }
-        third.InvitationCode = dto.InvitationCode;
+        userInfo.InvitationCode = dto.InvitationCode;
         var invite = await _inviteCodeRepository.Queryable()
             .Where(m => invitationCode >= m.BeginCode && invitationCode <= m.EndCode)
             .FirstAsync() ?? throw new UserFriendlyException(200, "邀请码无效");
+        var thirdInfo = await _thirdAccountRepository.GetAsync(userInfo.ThirdAccountId);
         var entity = new InviteCodeRecord
         {
             OrgId = invite.Id,
             OrgName = invite.OrgName,
             InviteCode = dto.InvitationCode,
-            WXOpenId = third.OpenId,
-            PhoneNumber = third.PhoneNumber,
-            Name = third.UserName,
+            WXOpenId = thirdInfo.OpenId,
+            PhoneNumber = userInfo.PhoneNumber,
+            Name = userInfo.Name,
         };
-        await _thirdAccountRepository.UpdateAsync(third);
+        await _snapshotUserInfoRepository.UpdateAsync(userInfo);
         await _inviteCodeRecordRepository.AddAsync(entity);
     }
 
@@ -667,21 +665,18 @@ public abstract class SnapshotApplicationBase
             .Where(m => m.Id == orderId)
             .Select(m => new { m.MemberName, m.MemberMobile })
             .FirstAsync(cancellationToken);
-        var guider = await _guiderInfoRepository.GetByPhoneNumberAsync(guiderInfo.MemberMobile);
+        var guider = await _snapshotUserInfoRepository.GetByPhoneNumberAsync(guiderInfo.MemberMobile);
         if (guider != null) return;
 
-        var entity = new GuiderInfo
+        var entity = new SnapshotUserInfo
         {
             Name = guiderInfo.MemberName,
-            PhoneNumber = guiderInfo.MemberMobile
+            PhoneNumber = guiderInfo.MemberMobile,
+            CitizenType = EReadPackUserType.Guider
         };
-        entity.Id = await _guiderInfoRepository.AddAsync(entity, cancellationToken);
         var third = await _thirdAccountRepository.GetByPhoneNumberAsync(guiderInfo.MemberMobile);
-
-        if (third == null) return;
-        third.UserId = entity.Id;
-        third.CitizenType = EReadPackUserType.Guider;
-        await _thirdAccountRepository.UpdateAsync(third, cancellationToken);
+        entity.ThirdAccountId = third?.Id;
+        entity.Id = await _snapshotUserInfoRepository.AddAsync(entity, cancellationToken);
     }
 
     /// <summary>

+ 101 - 0
src/Hotline.Application/Snapshot/SnapshotThirdAccountSupplier.cs

@@ -0,0 +1,101 @@
+using Hotline.Caching.Interfaces;
+using Hotline.Orders;
+using Hotline.Repository.SqlSugar.Snapshot;
+using Hotline.Share.Dtos.Snapshot;
+using Hotline.Share.Enums.Snapshot;
+using Hotline.Share.Enums.User;
+using Hotline.Snapshot;
+using Hotline.Snapshot.Interfaces;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
+using IdentityModel;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+
+namespace Hotline.Application.Snapshot;
+public class SnapshotThirdAccountSupplier : IThirdAccountDomainService, IScopeDependency
+{
+    private readonly IThirdAccountRepository _thirdAccountRepository;
+    private readonly IVolunteerRepository _volunteerRepository;
+    private readonly ISnapshotUserInfoRepository _snapshotUserInfoRepository;
+    private readonly ISystemSettingCacheManager _systemSettingCacheManager;
+
+    public SnapshotThirdAccountSupplier(IThirdAccountRepository thirdAccountRepository, IVolunteerRepository volunteerRepository, ISnapshotUserInfoRepository snapshotUserInfoRepository, ISystemSettingCacheManager systemSettingCacheManager)
+    {
+        _thirdAccountRepository = thirdAccountRepository;
+        _volunteerRepository = volunteerRepository;
+        _snapshotUserInfoRepository = snapshotUserInfoRepository;
+        _systemSettingCacheManager = systemSettingCacheManager;
+    }
+
+    public async Task<List<Claim>> GetClaimAsync(ThirdAccount account, List<Claim> claims, CancellationToken token)
+    {
+        var userInfo = await _snapshotUserInfoRepository.GetByThirdIdAsync(account.Id);
+        if(userInfo != null)
+        {
+            var subject = claims.Find(m => m.Type == JwtClaimTypes.Subject);
+            if (subject != null)
+                claims.Remove(subject);
+            claims.Add(new(JwtClaimTypes.Subject, userInfo.Id));
+        }
+        return claims;
+    }
+
+    public async Task<Dictionary<string, object>> GetLoginOutDataAsync(ThirdAccount thirdAccount, Dictionary<string, object> dicOutData, CancellationToken cancel)
+    {
+        var isVolunteer = await _volunteerRepository.IsVolunteerAsync(thirdAccount.PhoneNumber);
+        var user = await _snapshotUserInfoRepository.Queryable().Where(m => m.ThirdAccountId == thirdAccount.Id).FirstAsync();
+        if (user == null)
+        {
+            user = new SnapshotUserInfo
+            {
+                CitizenType = EReadPackUserType.Citizen,
+                ThirdAccountId = thirdAccount.Id,
+                Name = thirdAccount.UserName,
+                PhoneNumber = thirdAccount.PhoneNumber,
+            };
+            await _snapshotUserInfoRepository.AddAsync(user);
+        }
+        dicOutData.Add("UserType", user.CitizenType);
+        dicOutData.Add("IsVolunteer", isVolunteer);
+        dicOutData.Add("InvitationCode", user.InvitationCode);
+        return dicOutData;
+    }
+
+    public async Task<ThirdTokenDto> GetThirdParameterAsync(ThirdTokenDto thirdDto, CancellationToken token)
+    {
+        if (thirdDto.ThirdType == EThirdType.WeChat)
+        {
+            thirdDto.AppId = _systemSettingCacheManager.WxOpenAppId;
+            thirdDto.Secret = _systemSettingCacheManager.WxOpenAppSecret;
+        }
+        return await Task.FromResult(thirdDto);
+    }
+
+    public async Task RegisterAsync(ThirdAccount thirdAccount, CancellationToken token)
+    {
+        var userInfo = await _snapshotUserInfoRepository.GetByPhoneNumberAsync(thirdAccount.PhoneNumber);
+        if (userInfo != null)
+        {
+            userInfo.CitizenType = EReadPackUserType.Guider;
+            userInfo.ThirdAccountId = thirdAccount.Id;
+            await _snapshotUserInfoRepository.UpdateAsync(userInfo);
+        }
+        else
+        {
+            userInfo = new SnapshotUserInfo
+            {
+                ThirdAccountId = thirdAccount.Id,
+                PhoneNumber = thirdAccount.PhoneNumber,
+                CitizenType = EReadPackUserType.Citizen,
+            };
+            await _snapshotUserInfoRepository.AddAsync(userInfo);
+        }
+    }
+}
+

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
src/Hotline.Application/Snapshot/ZiGongSnapshotApplication.cs


+ 1 - 1
src/Hotline.Application/Subscribers/DatasharingSubscriber.cs

@@ -527,7 +527,7 @@ namespace Hotline.Application.Subscribers
                 PreviousWorkflowDto previous = new PreviousWorkflowDto();
                 previous.Opinion = dto.ProvinceScreenResult.AuditOpinion;
                 previous.WorkflowId = orderScreen.WorkflowId;
-                await _workflowApplication.PreviousAsync(previous, cancellationToken: cancellationToken);
+                await _workflowDomainService.PreviousAsync(previous, cancellationToken: cancellationToken);
             }
 
             if (int.Parse(dto.ProvinceScreenResult.AuditResult) > 0)

+ 1 - 1
src/Hotline.Repository.SqlSugar/Extensions/SqlSugarStartupExtensions.cs

@@ -147,7 +147,7 @@ namespace Hotline.Repository.SqlSugar.Extensions
 
                 var types = typeof(User).Assembly.GetTypes()
                     .Where(d => d.GetInterfaces().Any(x => x == typeof(ITable) && !d.IsAbstract))
-                    .Where(d => d.Name != "Order" && d.Name != "OrderCopy" && d.Name != "Workflow" && d.Name != "WorkflowStep" && d.Name != "WorkflowTrace")
+                    //.Where(d => d.Name != "Order" && d.Name != "OrderCopy" && d.Name != "Workflow" && d.Name != "WorkflowStep" && d.Name != "WorkflowTrace")
                     .Distinct()
                     .ToArray();
 

+ 0 - 23
src/Hotline.Repository.SqlSugar/Snapshot/GuiderInfoRepository.cs

@@ -1,23 +0,0 @@
-using Hotline.Repository.SqlSugar.DataPermissions;
-using Hotline.Snapshot;
-using Hotline.Snapshot.Interfaces;
-using SqlSugar;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using XF.Domain.Dependency;
-
-namespace Hotline.Repository.SqlSugar.Snapshot;
-public class GuiderInfoRepository : BaseRepository<GuiderInfo>, IGuiderInfoRepository, IScopeDependency
-{
-    public GuiderInfoRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder, IServiceProvider serviceProvider) : base(uow, dataPermissionFilterBuilder, serviceProvider)
-    {
-    }
-
-    public async Task<GuiderInfo> GetByPhoneNumberAsync(string phoneNumber)
-    {
-        return await Queryable().Where(m => m.PhoneNumber == phoneNumber).FirstAsync();
-    }
-}

+ 33 - 0
src/Hotline.Repository.SqlSugar/Snapshot/SnapshotUserInfoRepository.cs

@@ -0,0 +1,33 @@
+using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Share.Tools;
+using Hotline.Snapshot;
+using Hotline.Snapshot.Interfaces;
+using Hotline.Snapshot;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+using SqlSugar;
+using Hotline.Repository.SqlSugar.DataPermissions;
+
+namespace Hotline.Repository.SqlSugar.Snapshot;
+
+public class SnapshotUserInfoRepository : BaseRepository<SnapshotUserInfo>, ISnapshotUserInfoRepository, IScopeDependency
+{
+    public SnapshotUserInfoRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder, IServiceProvider serviceProvider) : base(uow, dataPermissionFilterBuilder, serviceProvider)
+    {
+    }
+
+    public async Task<SnapshotUserInfo?> GetByPhoneNumberAsync(string? phoneNumber)
+    {
+        if (phoneNumber.IsNullOrEmpty()) return null;
+        return await Queryable().Where(m => m.PhoneNumber == phoneNumber).FirstAsync();
+    }
+
+    public async Task<SnapshotUserInfo> GetByThirdIdAsync(string id)
+    {
+        return await Queryable().Where(m => m.ThirdAccountId == id).FirstAsync();
+    }
+}

+ 2 - 3
src/Hotline.Repository.SqlSugar/Snapshot/ThirdAccountRepository.cs

@@ -1,9 +1,8 @@
 using Hotline.Repository.SqlSugar.DataPermissions;
-using Hotline.Snapshot;
-using Hotline.Snapshot.Interfaces;
 using SqlSugar;
 using XF.Domain.Dependency;
-using XF.Domain.Repository;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 
 namespace Hotline.Repository.SqlSugar.Snapshot;
 public class ThirdAccountRepository : BaseRepository<ThirdAccount>,  IThirdAccountRepository , IScopeDependency

+ 5 - 0
src/Hotline.Repository.SqlSugar/Snapshot/VolunteerRepository.cs

@@ -24,6 +24,11 @@ public class VolunteerRepository : BaseRepository<Volunteer>, IVolunteerReposito
         return await Queryable().Where(m => m.PhoneNumber == phone.Trim()).FirstAsync();
     }
 
+    /// <summary>
+    /// 是否是志愿者
+    /// </summary>
+    /// <param name="phoneNumber"></param>
+    /// <returns></returns>
     public async Task<bool> IsVolunteerAsync(string? phoneNumber)
     {
         if (phoneNumber.IsNullOrEmpty()) return false;

+ 2 - 2
src/Hotline.Share/Dtos/FlowEngine/Workflow/PreviousWorkflowDto.cs

@@ -15,8 +15,8 @@ public class PreviousWorkflowDto : EndWorkflowIdDto
     /// <summary>
     /// 指定办理对象
     /// </summary>
-    public FlowStepHandler? Handler { get; set; }
-    // public StepAssignInfo? Handler { get; set; }
+    //public FlowStepHandler? Handler { get; set; }
+    public StepAssignInfo? Handler { get; set; }
 
     // /// <summary>
     // /// 逆向流程,节点指派方式

+ 16 - 5
src/Hotline.Share/Dtos/Knowledge/KnowledgeDto.cs

@@ -57,10 +57,15 @@ namespace Hotline.Share.Dtos.Knowledge
         /// </summary>
         public List<KnowledgeRelationTypeDto> KnowledgeType { get; set; }
 
-        /// <summary>
-        /// 到期时间
-        /// </summary>
-        public DateTime? ExpiredTime { get; set; }
+		/// <summary>
+		/// 知识归属
+		/// </summary>
+		public List<string> KnowledgeOrg { get; set; }
+
+		/// <summary>
+		/// 到期时间
+		/// </summary>
+		public DateTime? ExpiredTime { get; set; }
 
         /// <summary>
         /// 是否公开
@@ -141,6 +146,11 @@ namespace Hotline.Share.Dtos.Knowledge
 		public string KnowledgeTypeSpliceName { get; set; }
 	}
 
+	public record KnowledgeRelationOrgDto
+	{
+		public string OrgId { get; set; }
+	}
+
 	/// <summary>
 	/// 基础
 	/// </summary>
@@ -258,7 +268,8 @@ namespace Hotline.Share.Dtos.Knowledge
         public List<FileJson>? FileJson { get; set; }
 
         public List<KnowledgeTypeDto> KnowledgeTypes { get; set; }
-    }
+		public List<OrgDto> KnowledgeOrganizes { get; set; }
+	}
 
     public class KnowledgeBaseDto {
 		public DateTime? LastModificationTime { get; set; }

+ 47 - 2
src/Hotline.Share/Dtos/Order/OrderDto.cs

@@ -608,9 +608,34 @@ namespace Hotline.Share.Dtos.Order
         public string? DelayText => DelayingCount > 0 ? "是" : "否";
 
         /// <summary>
-        /// 特提次数
+        /// 一级热点
         /// </summary>
-        public int SpecialNum { get; set; }
+        public string OneHotspotName => !string.IsNullOrEmpty(HotspotSpliceName) && !string.IsNullOrEmpty(HotspotId) && HotspotId.Length >= 2 ? HotspotSpliceName.Split("-")[0] : string.Empty;
+
+        /// <summary>
+        /// 二级热点
+        /// </summary>
+		public string TwoHotspotName => !string.IsNullOrEmpty(HotspotSpliceName) && !string.IsNullOrEmpty(HotspotId) && HotspotId.Length >= 4 ? HotspotSpliceName.Split("-")[1] : string.Empty;
+
+        /// <summary>
+        /// 三级热点
+        /// </summary>
+		public string ThreeHotspotName => !string.IsNullOrEmpty(HotspotSpliceName) && !string.IsNullOrEmpty(HotspotId) && HotspotId.Length >= 6 ? HotspotSpliceName.Split("-")[2] : string.Empty;
+
+		/// <summary>
+		/// 四级热点
+		/// </summary>
+		public string FourHotspotName => !string.IsNullOrEmpty(HotspotSpliceName) && !string.IsNullOrEmpty(HotspotId) && HotspotId.Length >= 8 ? HotspotSpliceName.Split("-")[3] : string.Empty;
+
+		/// <summary>
+		/// 五级热点
+		/// </summary>
+		public string FiveHotspotName => !string.IsNullOrEmpty(HotspotSpliceName) && !string.IsNullOrEmpty(HotspotId) && HotspotId.Length >= 10 ? HotspotSpliceName.Split("-")[4] : string.Empty;
+
+		/// <summary>
+		/// 特提次数
+		/// </summary>
+		public int SpecialNum { get; set; }
 
         private string CalculateExpiredText()
         {
@@ -1026,6 +1051,26 @@ namespace Hotline.Share.Dtos.Order
         #endregion
 
         public bool? IsReTransact { get; set; }
+
+        /// <summary>
+        /// 重办时长,最新二次办理审批通过后的归档时间-最新二次办理审批通过时间(秒)
+        /// </summary>
+        public double? SecondaryHandlingDuration { get; set; }
+
+        public double? SecondaryHandlingDurationWorkday { get; set; }
+        public string? SecondaryHandlingDurationWorkdayDayText => SecondaryHandlingDurationDay();
+
+        public string SecondaryHandlingDurationDay()
+        {
+            var overDays = "";
+            if (SecondaryHandlingDurationWorkday.HasValue && SecondaryHandlingDurationWorkday.Value > 0)
+            {
+                var totalDays = Math.Round(((double)SecondaryHandlingDurationWorkday / 3600 / 8), 2);
+                overDays = totalDays > 0 ? totalDays + "" : "0.01";
+            }
+
+            return overDays;
+        }
     }
 
 

+ 19 - 0
src/Hotline.Share/Dtos/Order/OrderScreenDto.cs

@@ -370,6 +370,25 @@ namespace Hotline.Share.Dtos.Order
         public DateTime ScreenByEndTime { get; set; }
     }
 
+    public class OrderScreenAlterDto { 
+    
+        /// <summary>
+        /// 甄别Id
+        /// </summary>
+        public string ScreenId { get; set; }
+
+
+		/// <summary>
+		/// 甄别申请原因
+		/// </summary>
+		public string? Content { get; set; }
+
+        /// <summary>
+        /// 附件
+        /// </summary>
+		//public List<FileDto> Files { get; set; }
+	}
+
     public enum EOrderScreenType
     {
         /// <summary>

+ 15 - 39
src/Hotline.Share/Dtos/Snapshot/ThirdTokenDto.cs

@@ -1,47 +1,11 @@
-using Hotline.Share.Enums.Snapshot;
+using Hotline.Share.Enums.KnowledgeBase;
+using Hotline.Share.Enums.Snapshot;
+using Hotline.Share.Enums.ThirdAccount;
 using Hotline.Share.Enums.User;
 using System.ComponentModel.DataAnnotations;
 
 namespace Hotline.Share.Dtos.Snapshot;
 
-public class TokenOutDto
-{
-    /// <summary>
-    /// 用户类型
-    /// </summary>
-    public EReadPackUserType UserType { get; set; }
-
-    /// <summary>
-    /// 登录token
-    /// </summary>
-    public string Token { get; set; }
-
-    /// <summary>
-    /// 电话号码
-    /// </summary>
-    public string PhoneNumber { get; set; }
-
-    /// <summary>
-    /// 用户名字
-    /// </summary>
-    public string UserName { get; set; }
-
-    /// <summary>
-    /// OpenId
-    /// </summary>
-    public string OpenId { get; set; }
-
-    /// <summary>
-    /// 是否自愿者
-    /// </summary>
-    public bool IsVolunteer { get; set; }
-
-    /// <summary>
-    /// 邀请码
-    /// </summary>
-    public string InvitationCode { get; set; }
-}
-
 public class ThirdTokenInDto
 {
     /// <summary>
@@ -59,6 +23,14 @@ public class ThirdTokenInDto
     /// 0: 微信
     /// </summary>
     public EThirdType ThirdType { get; set; } = EThirdType.WeChat;
+
+    /// <summary>
+    /// 登录app(不传默认随手拍)
+    /// 1: 随手拍
+    /// 2: 部门办件app
+    /// 3: 市民办件app
+    /// </summary>
+    public EAppType AppType { get; set; } = EAppType.Snapshot;
 }
 
 public class ThirdPhoneInDto : ThirdTokenInDto { }
@@ -90,6 +62,10 @@ public class ThirdTokenOutDto
 {
     public string SessionKey { get; set; }
     public string OpenId { get; set; }
+    /// <summary>
+    /// UnIconId
+    /// </summary>
+    public string? UnIonId { get; set; }
 }
 
 public class GuiderSystemOutDto

+ 25 - 0
src/Hotline.Share/Enums/ThirdAccount/EAppType.cs

@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Enums.ThirdAccount;
+public enum EAppType
+{
+    /// <summary>
+    /// 随手拍
+    /// </summary>
+    Snapshot = 1,
+
+    /// <summary>
+    /// 部门办件app
+    /// </summary>
+    Department = 2,
+
+    /// <summary>
+    /// 市民办件app
+    /// </summary>
+    Citizen = 3
+}
+

+ 12 - 7
src/Hotline.WeChat/WeChatService.cs

@@ -1,5 +1,6 @@
-using Hotline.Share.Dtos.Snapshot;
-using Hotline.Users;
+using Hotline.Settings;
+using Hotline.Share.Dtos.Snapshot;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Microsoft.Extensions.Logging;
 using Senparc.CO2NET.Extensions;
 using Senparc.Weixin;
@@ -13,19 +14,22 @@ namespace Hotline.WeChat;
 public class WeChatService : IThirdIdentiyService
 {
     private readonly ILogger<WeChatService> _logger;
+    private readonly ISystemLogRepository _systemLog;
 
-    public WeChatService(ILogger<WeChatService> logger)
+    public WeChatService(ILogger<WeChatService> logger, ISystemLogRepository systemLog)
     {
         _logger = logger;
+        _systemLog = systemLog;
     }
 
-    public async Task<ThirdTokenOutDto> GetTokenAsync(ThirdTokenDto dto)
+    public async Task<ThirdTokenOutDto> GetTokenAsync(ThirdTokenDto dto, CancellationToken token)
     {
         try
         {
             var result = await SnsApi.JsCode2JsonAsync(dto.AppId, dto.Secret, dto.LoginCode);
+            _systemLog.Add("微信获取Token", dto, status: 1, executeResult: result.ToJson());
             if (result.errcode != ReturnCode.请求成功) throw UserFriendlyException.SameMessage("获取微信用户信息失败");
-            return new ThirdTokenOutDto() { SessionKey = result.session_key, OpenId = result.openid };
+            return new ThirdTokenOutDto() { SessionKey = result.session_key, OpenId = result.openid , UnIonId = result.unionid};
 
         }
         catch (Exception e)
@@ -40,11 +44,12 @@ public class WeChatService : IThirdIdentiyService
     /// </summary>
     /// <param name="dto"></param>
     /// <returns></returns>
-    public async Task<ThirdPhoneOutDto> GetPhoneNumberAsync(ThirdTokenDto dto)
+    public async Task<ThirdPhoneOutDto> GetPhoneNumberAsync(ThirdTokenDto dto, CancellationToken token)
     {
         await AccessTokenContainer.RegisterAsync(dto.AppId, dto.Secret);
         _logger.LogInformation($"GetPhoneNumberAsync: {dto.ToJson()}");
         var result = await BusinessApi.GetUserPhoneNumberAsync(dto.AppId, dto.TelCode);
+        _systemLog.Add("微信获取手机号码", dto, status: 1, executeResult: result.ToJson());
         if (result.errcode != ReturnCode.请求成功)
             _logger.LogError($"GetPhoneNumberAsync: {result.ToJson()}");
         return new ThirdPhoneOutDto()
@@ -52,7 +57,7 @@ public class WeChatService : IThirdIdentiyService
             ErrorCode = (int)result.errcode,
             IsError = result.errcode != ReturnCode.请求成功,
             ErrorMessage = result.errmsg + " " + result.errcode,
-            PhoneNumber = result.phone_info?.phoneNumber
+            PhoneNumber = result.phone_info?.phoneNumber,
         };
     }
 }

+ 10 - 0
src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs

@@ -99,6 +99,16 @@ namespace Hotline.FlowEngine.Workflows
                 Action<Workflow, WorkflowStep, StepDefine, WorkflowStep, WorkflowStep>? newStepConfig = null,
                 CancellationToken cancellationToken = default);
 
+        /// <summary>
+        /// 退回
+        /// </summary>
+        Task<(Workflow workflow, WorkflowStep currentStep, StepDefine prevDefine,
+                WorkflowStep prevStep, WorkflowStep newStep, EFlowDirection flowDirection)>
+            PreviousAsync(PreviousWorkflowDto dto,
+                EHandleMode handleMode = EHandleMode.Previous,
+                Action<Workflow, WorkflowStep, StepDefine, WorkflowStep, WorkflowStep>? newStepConfig = null,
+                CancellationToken cancellationToken = default);
+
         /// <summary>
         /// 撤回(返回到之前任意节点)
         /// </summary>

+ 35 - 12
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -903,6 +903,7 @@ namespace Hotline.FlowEngine.Workflows
 
         /// <summary>
         /// 退回(new)
+        /// workflow, currentStep, prevStepDefine, prevStep, newPrevStep
         /// </summary>
         public async Task<(Workflow workflow, WorkflowStep currentStep, StepDefine prevDefine,
                 WorkflowStep prevStep, WorkflowStep newStep, EFlowDirection flowDirection)>
@@ -990,17 +991,14 @@ namespace Hotline.FlowEngine.Workflows
             var newPrevStep = DuplicateStep(workflow, prevStepDefine, prevStep, EWorkflowTraceType.Previous, dto.ExpiredTime);
             newPrevStep.Assign(prevStep, EFlowAssignType.User);
 
-			//甄别退回到最开始节点到部门 todo 重构放在调用处判断  
-			if (workflow.FlowType == EFlowType.Review && workflow.ModuleCode == WorkflowModuleConsts.OrderScreen)
-			{
-				newPrevStep.FlowAssignType = newPrevStep.StepType == EStepType.Start ? EFlowAssignType.Org : prevStep.FlowAssignType;
-			}
-			//退给派单组节点,需按照平均分配原则派给一个派单员 禅道299 TODO
-			if (dto.Handler != null) //todo 改为按策略判断
-            {
-                var handle = dto.Handler;
-                newPrevStep.Assign(handle.UserId, handle.Username, handle.OrgId, handle.OrgName, handle.RoleId, handle.RoleName);
-            }
+			////甄别退回到最开始节点到部门 todo 重构放在调用处判断  
+			//if (workflow.FlowType == EFlowType.Review && workflow.ModuleCode == WorkflowModuleConsts.OrderScreen)
+			//{
+			//	newPrevStep.FlowAssignType = newPrevStep.StepType == EStepType.Start ? EFlowAssignType.Org : prevStep.FlowAssignType;
+			//}
+
+			if (dto.Handler != null)
+                newPrevStep.Assign(dto.Handler);
 
             //await Task.Run(() => newStepConfig?.Invoke(workflow, currentStep, prevStepDefine, prevStep, newPrevStep), cancellationToken);
             newStepConfig?.Invoke(workflow, currentStep, prevStepDefine, prevStep, newPrevStep);
@@ -1050,6 +1048,27 @@ namespace Hotline.FlowEngine.Workflows
             return (workflow, currentStep, prevStepDefine, prevStep, newPrevStep, flowDirection);
         }
 
+        /// <summary>
+        /// 退回
+        /// </summary>
+        public async Task<(Workflow workflow, WorkflowStep currentStep, StepDefine prevDefine, 
+                WorkflowStep prevStep, WorkflowStep newStep, EFlowDirection flowDirection)> 
+            PreviousAsync(PreviousWorkflowDto dto, 
+                EHandleMode handleMode = EHandleMode.Previous, 
+                Action<Workflow, WorkflowStep, StepDefine, WorkflowStep, WorkflowStep>? newStepConfig = null,
+            CancellationToken cancellationToken = default)
+        {
+            var workflow = await GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
+                withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
+
+            return await PreviousAsync(workflow, dto, new OperatorInfo(
+                _sessionContext.RequiredUserId, _sessionContext.UserName,
+                _sessionContext.RequiredOrgId, _sessionContext.OrgName,
+                _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
+                _sessionContext.OrgIsCenter, _sessionContext.Roles,
+                _sessionContext.OrgLevel), handleMode, newStepConfig, cancellationToken);
+        }
+
         private async Task UpdateTracesStateAsync(List<WorkflowTrace> traces, EWorkflowTraceState traceState,
             CancellationToken cancellationToken)
         {
@@ -3348,7 +3367,11 @@ namespace Hotline.FlowEngine.Workflows
             //    _sessionContext.RequiredOrgId, _sessionContext.OrgName,
             //    _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName);
 
-            HandleStep(step, EHandleMode.Normal, "流程归档", string.Empty);
+            var opinion = workflow.FlowType == EFlowType.Handle
+                ? $"流程归档。承办意见:{dto.Opinion}"
+                : "流程归档";
+
+            HandleStep(step, EHandleMode.Normal, opinion, string.Empty);
 
             await _workflowStepRepository.AddAsync(step, cancellationToken);
             workflow.Steps.Add(step);

+ 4 - 0
src/Hotline/Hotline.csproj

@@ -24,4 +24,8 @@
     <ProjectReference Include="..\XF.Domain.Repository\XF.Domain.Repository.csproj" />
   </ItemGroup>
 
+  <ItemGroup>
+    <Folder Include="ThirdAccountDomainServices\Register\" />
+  </ItemGroup>
+
 </Project>

+ 12 - 6
src/Hotline/KnowledgeBase/Knowledge.cs

@@ -131,16 +131,22 @@ public class Knowledge : WorkflowEntity//   WorkflowEntity  FullStateEntity
     [Navigate(NavigateType.OneToMany, nameof(KnowledgeRelationType.KnowledgeId))]
     public List<KnowledgeRelationType> KnowledgeType { get; set; }
 
-    /// <summary>
-    /// 知识库分类
-    /// </summary>
-    [Navigate(typeof(KnowledgeRelationType), nameof(KnowledgeRelationType.KnowledgeId), nameof(KnowledgeRelationType.KnowledgeTypeId))]
+	/// <summary>
+	/// 知识库分类
+	/// </summary>
+	[Navigate(typeof(KnowledgeRelationType), nameof(KnowledgeRelationType.KnowledgeId), nameof(KnowledgeRelationType.KnowledgeTypeId))]
     public List<KnowledgeType> KnowledgeTypes { get; set; }
 
     /// <summary>
-    /// 部门
+    /// 知识库归属
     /// </summary>
-    [Navigate(NavigateType.OneToOne, nameof(CreatorOrgId))]//一对一 
+    [Navigate(typeof(KnowledgeRelationOrg), nameof(KnowledgeRelationOrg.KnowledgeId), nameof(KnowledgeRelationOrg.OrgId))]
+	public List<SystemOrganize> KnowledgeOrganizes { get; set; }
+
+	/// <summary>
+	/// 部门
+	/// </summary>
+	[Navigate(NavigateType.OneToOne, nameof(CreatorOrgId))]//一对一 
     public SystemOrganize SystemOrganize { get; set; }
 
     /// <summary>

+ 41 - 17
src/Hotline/KnowledgeBase/KnowledgeDomainService.cs

@@ -423,9 +423,14 @@ namespace Hotline.KnowledgeBase
                 var knTypes = _mapper.Map<List<KnowledgeType>>(dto.KnowledgeType);
                 kn.KnowledgeTypes = knTypes;
             }
+            if (dto.KnowledgeOrg.Any())
+            {
+                kn.KnowledgeOrganizes = dto.KnowledgeOrg.Select(x => new SystemOrganize { Id = x }).ToList();
+			}
 
             await _knowledgeRepository.AddNav(kn)
                 .Include(d => d.KnowledgeTypes)
+                .Include(d => d.KnowledgeOrganizes)
                 .ExecuteCommandAsync();
 
             return kn;
@@ -485,23 +490,42 @@ namespace Hotline.KnowledgeBase
                 knowledge.CreatorOrgLevel = _sessionContext.OrgLevel;
             }
 
-            if (dto.KnowledgeType.Any())
-            {
-                knowledge.KnowledgeTypes = dto.KnowledgeType.Select(d => new KnowledgeType
-                {
-                    Id = d.KnowledgeTypeId,
-                }).ToList();
-                await _knowledgeRepository.UpdateNav(knowledge)
-                    .Include(d => d.KnowledgeTypes, new UpdateNavOptions
-                    {
-                        ManyToManyIsUpdateA = true
-                    })
-                    .ExecuteCommandAsync();
-            }
-            else
-            {
-                await _knowledgeRepository.UpdateAsync(knowledge, cancellation);
-            }
+           
+            var ktbool = dto.KnowledgeType.Any();
+			var kobool = dto.KnowledgeOrg.Any();
+			if (ktbool)
+			{
+				knowledge.KnowledgeTypes = dto.KnowledgeType.Select(x => new KnowledgeType { Id = x.KnowledgeTypeId }).ToList();
+			}
+			if (kobool)
+			{
+				knowledge.KnowledgeOrganizes = dto.KnowledgeOrg.Select(x => new SystemOrganize { Id = x }).ToList();
+			}
+
+			await _knowledgeRepository.UpdateNav(knowledge)
+				.Include(d => d.KnowledgeTypes, new UpdateNavOptions { ManyToManyIsUpdateA =true, ManyToManyIsUpdateB = ktbool })
+				.Include(d => d.KnowledgeOrganizes, new UpdateNavOptions { ManyToManyIsUpdateA = true, ManyToManyIsUpdateB = kobool })
+				.ExecuteCommandAsync();
+            //if (dto.KnowledgeType.Any())
+            //         {
+            //             knowledge.KnowledgeTypes = dto.KnowledgeType.Select(d => new KnowledgeType
+            //             {
+            //                 Id = d.KnowledgeTypeId,
+            //             }).ToList();
+            //             await _knowledgeRepository.UpdateNav(knowledge)
+            //                 .Include(d => d.KnowledgeTypes, new UpdateNavOptions
+            //                 {
+            //                     ManyToManyIsUpdateA = true
+            //                 })
+            //                 .ExecuteCommandAsync();
+            //         }
+            //         else
+            //         {
+            //             await _knowledgeRepository.UpdateAsync(knowledge, cancellation);
+            //         }
+
+
+
 
             return knowledge;
         }

+ 30 - 0
src/Hotline/KnowledgeBase/KnowledgeRelationOrg.cs

@@ -0,0 +1,30 @@
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Entities;
+
+namespace Hotline.KnowledgeBase
+{
+	/// <summary>
+	/// 知识归属部门
+	/// </summary>
+	[Description("知识归属部门")]
+	public class KnowledgeRelationOrg : ITable, IEntity
+	{
+		/// <summary>
+		/// 知识库ID
+		/// </summary>
+		[SugarColumn(IsPrimaryKey = true)]
+		public string KnowledgeId { get; set; }
+
+		/// <summary>
+		/// 部门ID
+		/// </summary>
+		[SugarColumn(IsPrimaryKey = true)]
+		public string OrgId { get; set; }
+	}
+}

+ 0 - 2
src/Hotline/KnowledgeBase/KnowledgeRelationType.cs

@@ -14,8 +14,6 @@ namespace Hotline.KnowledgeBase
 	/// 知识库关联类型
 	/// </summary>
 	[Description("知识库关联类型")]
-	//[SugarIndex("index_knowledgeRelationType_knowledgeId", nameof(KnowledgeRelationType.KnowledgeId), OrderByType.Desc)]
-	//[SugarIndex("index_knowledgeRelationType_typeId", nameof(KnowledgeRelationType.KnowledgeTypeId), OrderByType.Desc)]
 	[SugarIndex("index_knowledgeRelationType_spliceName", nameof(KnowledgeRelationType.KnowledgeTypeSpliceName), OrderByType.Desc)]
 	public class KnowledgeRelationType : ITable, IEntity
     {

+ 25 - 1
src/Hotline/Orders/Order.cs

@@ -464,6 +464,15 @@ namespace Hotline.Orders
         [SugarColumn(ColumnDescription = "归档工作时长")]
         public double? FileDurationWorkday { get; set; }
 
+        /// <summary>
+        /// 重办时长,最新二次办理审批通过后的归档时间-最新二次办理审批通过时间(秒)
+        /// </summary>
+        [SugarColumn(ColumnDescription = "重办时长,最新二次办理审批通过后的归档时间-最新二次办理审批通过时间(秒)")]
+        public double? SecondaryHandlingDuration { get; set; }
+
+        [SugarColumn(ColumnDescription = "重办时长工作日时长")]
+        public double? SecondaryHandlingDurationWorkday { get; set; }
+
         /// <summary>
         /// 全流程时长(秒)
         /// </summary>
@@ -1261,7 +1270,8 @@ namespace Hotline.Orders
         /// 归档
         /// </summary>
         public void File(DateTime filedTime, double handleDurationWorkday, double fileDurationWorkday, double allDurationWorkday
-            , double creationTimeHandleDurationWorkday, double centerToOrgHandleDurationWorkday)
+            , double creationTimeHandleDurationWorkday, double centerToOrgHandleDurationWorkday, double? secondaryHandlingDurationWorkday,
+            DateTime? secondaryHandlingAuditTime)
         {
             if (Status is EOrderStatus.Filed) return;
             Status = EOrderStatus.Filed;
@@ -1271,6 +1281,7 @@ namespace Hotline.Orders
             AllDurationWorkday = allDurationWorkday;
             CreationTimeHandleDurationWorkday = creationTimeHandleDurationWorkday;
             CenterToOrgHandleDurationWorkday = centerToOrgHandleDurationWorkday;
+            SecondaryHandlingDurationWorkday = secondaryHandlingDurationWorkday;
 
             //计算实际办结时长
             SetHandleDuration();
@@ -1278,6 +1289,7 @@ namespace Hotline.Orders
             SetAllDuration();
             SetCreationTimeHandleDurationWorkday();
             SetCenterToOrgHandleDurationWorkday();
+            SetSecondaryHandlingDuration(secondaryHandlingAuditTime);
         }
 
         /// <summary>
@@ -1396,6 +1408,18 @@ namespace Hotline.Orders
             FileDuration = Math.Round((FiledTime - CenterToOrgTime).Value.TotalSeconds);
         }
 
+        /// <summary>
+        /// 自贡 任务 390【标】综合查询增加“重办时长”数据列
+        /// </summary>
+        /// <param name="SecondaryHandlingAuditTime"></param>
+        public void SetSecondaryHandlingDuration(DateTime? SecondaryHandlingAuditTime)
+        {
+            if (!FiledTime.HasValue || !SecondaryHandlingAuditTime.HasValue)
+                SecondaryHandlingDuration = null;
+            else
+                SecondaryHandlingDuration = Math.Round((FiledTime - SecondaryHandlingAuditTime).Value.TotalSeconds);
+        }
+
         /// <summary>
         /// 办结时长(秒) 归档时间-受理时间(工单创建时间)
         /// </summary>

+ 109 - 104
src/Hotline/Orders/OrderSecondaryHandling.cs

@@ -11,108 +11,113 @@ using XF.Domain.Repository;
 
 namespace Hotline.Orders
 {
-	[Description("二次办理")]
-	public class OrderSecondaryHandling : FullStateEntity
-	{
-		/// <summary>
-		/// 工单ID
-		/// </summary>
-		[SugarColumn(ColumnDescription = "工单ID")]
-		public string OrderId { get; set; }
-
-
-		/// <summary>
-		/// 回访id
-		/// </summary>
-		[SugarColumn(ColumnDescription = "回访id")]
-		public string VisitId { get; set; }
-
-		/// <summary>
-		/// 回访明细id
-		/// </summary>
-		[SugarColumn(ColumnDescription = "回访明细id")]
-		public string VisitDetailId { get; set; }
-
-		/// <summary>
-		/// 状态
-		/// </summary>
-		[SugarColumn(ColumnDescription = "状态")]
-		public ESecondaryHandlingState? State { get; set; }
-
-		/// <summary>
-		/// 重提办理
-		/// </summary>
-		public int? SendBackNum { get; set; }
-
-		/// <summary>
-		/// 申请理由
-		/// </summary>
-		[SugarColumn(ColumnDescription = "申请理由", ColumnDataType = "text")]
-		public string? Content { get; set; }
-
-		/// <summary>
-		/// 退回意见
-		/// </summary>
-		[SugarColumn(ColumnDescription = "退回意见", ColumnDataType = "text")]
-		public string? SendBackContent { get; set; }
-
-		/// <summary>
-		/// 审批意见
-		/// </summary>
-		[SugarColumn(ColumnDescription = "审批意见", ColumnDataType = "text")]
-		public string? AuditContent { get; set; }
-
-		/// <summary>
-		/// 工单
-		/// </summary>
-		[Navigate(NavigateType.OneToOne, nameof(OrderId))]
-		public Order Order { get; set; }
-
-
-		/// <summary>
-		/// 回访
-		/// </summary>
-		[Navigate(NavigateType.OneToOne, nameof(VisitDetailId))]
-		public OrderVisitDetail VisitDetail { get; set; }
-
-		/// <summary>
-		/// 回访
-		/// </summary>
-		[Navigate(NavigateType.OneToOne, nameof(VisitId))]
-		public OrderVisit Visit { get; set; }
-
-		/// <summary>
-		/// 审批人ID
-		/// </summary>
-		[SugarColumn(ColumnDescription = "审批人ID")]
-		public string? AuditId { get; set; }
-
-		[SugarColumn(ColumnDescription = "审批人")]
-		public string? AuditUser { get; set; }
-
-		/// <summary>
-		/// 审批时间
-		/// </summary>
-		public DateTime? AuditTime { get; set; }
-
-		/// <summary>
-		/// 申请部门ID
-		/// </summary>
-		[SugarColumn(ColumnDescription = "申请部门ID")]
-		public string ApplyOrgId { get; set; }
-
-		/// <summary>
-		/// 申请部门名称
-		/// </summary>
-		[SugarColumn(ColumnDescription = "申请部门名称")]
-		public string ApplyOrgName { get; set; }
-
-		[SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
-		public List<FileJson>? FileJson { get; set; }
-
-		/// <summary>
-		/// 回访状态
-		/// </summary>
-		public EVisitState VisitState { get; set; }
-	}
+    [Description("二次办理")]
+    public class OrderSecondaryHandling : FullStateEntity
+    {
+        /// <summary>
+        /// 工单ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "工单ID")]
+        public string OrderId { get; set; }
+
+
+        /// <summary>
+        /// 回访id
+        /// </summary>
+        [SugarColumn(ColumnDescription = "回访id")]
+        public string VisitId { get; set; }
+
+        /// <summary>
+        /// 回访明细id
+        /// </summary>
+        [SugarColumn(ColumnDescription = "回访明细id")]
+        public string VisitDetailId { get; set; }
+
+        /// <summary>
+        /// 状态
+        /// </summary>
+        [SugarColumn(ColumnDescription = "状态")]
+        public ESecondaryHandlingState? State { get; set; }
+
+        /// <summary>
+        /// 重提办理
+        /// </summary>
+        public int? SendBackNum { get; set; }
+
+        /// <summary>
+        /// 申请理由
+        /// </summary>
+        [SugarColumn(ColumnDescription = "申请理由", ColumnDataType = "text")]
+        public string? Content { get; set; }
+
+        /// <summary>
+        /// 退回意见
+        /// </summary>
+        [SugarColumn(ColumnDescription = "退回意见", ColumnDataType = "text")]
+        public string? SendBackContent { get; set; }
+
+        /// <summary>
+        /// 审批意见
+        /// </summary>
+        [SugarColumn(ColumnDescription = "审批意见", ColumnDataType = "text")]
+        public string? AuditContent { get; set; }
+
+        /// <summary>
+        /// 工单
+        /// </summary>
+        [Navigate(NavigateType.OneToOne, nameof(OrderId))]
+        public Order Order { get; set; }
+
+
+        /// <summary>
+        /// 回访
+        /// </summary>
+        [Navigate(NavigateType.OneToOne, nameof(VisitDetailId))]
+        public OrderVisitDetail VisitDetail { get; set; }
+
+        /// <summary>
+        /// 回访
+        /// </summary>
+        [Navigate(NavigateType.OneToOne, nameof(VisitId))]
+        public OrderVisit Visit { get; set; }
+
+        /// <summary>
+        /// 审批人ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "审批人ID")]
+        public string? AuditId { get; set; }
+
+        [SugarColumn(ColumnDescription = "审批人")]
+        public string? AuditUser { get; set; }
+
+        /// <summary>
+        /// 审批时间
+        /// </summary>
+        public DateTime? AuditTime { get; set; }
+
+        /// <summary>
+        /// 申请部门ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "申请部门ID")]
+        public string ApplyOrgId { get; set; }
+
+        /// <summary>
+        /// 申请部门名称
+        /// </summary>
+        [SugarColumn(ColumnDescription = "申请部门名称")]
+        public string ApplyOrgName { get; set; }
+
+        [SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
+        public List<FileJson>? FileJson { get; set; }
+
+        /// <summary>
+        /// 回访状态
+        /// </summary>
+        public EVisitState VisitState { get; set; }
+
+        /// <summary>
+        /// 是否办理完成
+        /// </summary>
+        public bool? IsHandel { get; set; }
+    }
 }

+ 3 - 3
src/Hotline/Orders/OrderVisitDomainService.cs

@@ -189,12 +189,12 @@ public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependenc
             .FirstAsync()
             .Then(async detailSeat =>
             {
-                if (smsReplyRule.SeatEvaluate != null || smsReplyRule.VoiceEvaluate != null)
+                if (smsReplyRule.SeatEvaluate != null || smsReplyRule.SmSVoiceEvaluate != null)
                 {
                     if (smsReplyRule.SeatEvaluate != null)
                         detailSeat.SeatEvaluate ??= smsReplyRule.SeatEvaluate;
-                    if (smsReplyRule.VoiceEvaluate != null)
-                        detailSeat.VoiceEvaluate ??= smsReplyRule.VoiceEvaluate;
+                    if (smsReplyRule.SmSVoiceEvaluate != null)
+                        detailSeat.VoiceEvaluate ??= smsReplyRule.SmSVoiceEvaluate;
                     await _orderVisitDetailRepository.UpdateAsync(detailSeat);
                 }
             });

+ 6 - 0
src/Hotline/Settings/SettingOrderVisitSmsReplyRule.cs

@@ -62,6 +62,12 @@ public class SettingOrderVisitSmsReplyRule : FullStateEntity
     [SugarColumn(ColumnDescription = "语音评价(不需要更新就填NULL)")]
     public EVoiceEvaluate? VoiceEvaluate { get; set; }
 
+    /// <summary>
+    /// 短信语音评价(话务评价)
+    /// </summary>
+    [SugarColumn(ColumnDescription = "短信语音评价(不需要更新就填NULL)")]
+    public EVoiceEvaluate? SmSVoiceEvaluate { get; set; }
+
     /// <summary>
     /// 部门办件态度
     /// </summary>

+ 0 - 22
src/Hotline/Snapshot/GuiderInfo.cs

@@ -1,22 +0,0 @@
-using System.ComponentModel;
-using XF.Domain.Repository;
-
-namespace Hotline.Snapshot;
-
-/// <summary>
-/// 网格员信息
-/// 当网格系统回推信息时, 填入网格员信息
-/// </summary>
-[Description("网格员信息")]
-public class GuiderInfo : CreationSoftDeleteEntity
-{
-    /// <summary>
-    /// 姓名
-    /// </summary>
-    public string Name { get; set; }
-
-    /// <summary>
-    /// 手机号码
-    /// </summary>
-    public string PhoneNumber { get; set; }
-}

+ 0 - 13
src/Hotline/Snapshot/Interfaces/IGuiderInfoRepository.cs

@@ -1,13 +0,0 @@
-using Hotline.Share.Dtos.Snapshot;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using XF.Domain.Repository;
-
-namespace Hotline.Snapshot.Interfaces;
-public interface IGuiderInfoRepository : IRepository<GuiderInfo>
-{
-    Task<GuiderInfo> GetByPhoneNumberAsync(string phoneNumber);
-}

+ 25 - 0
src/Hotline/Snapshot/Interfaces/ISnapshotUserInfoRepository.cs

@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Snapshot.Interfaces;
+public interface ISnapshotUserInfoRepository : IRepository<SnapshotUserInfo>
+{
+    /// <summary>
+    /// 根据电话号码获取用户信息
+    /// </summary>
+    /// <param name="phoneNumber"></param>
+    /// <returns></returns>
+    Task<SnapshotUserInfo?> GetByPhoneNumberAsync(string? phoneNumber);
+
+    /// <summary>
+    /// 根据第三方账号Id获取用户信息
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    Task<SnapshotUserInfo> GetByThirdIdAsync(string id);
+}
+

+ 2 - 0
src/Hotline/Snapshot/SnapshotSMSTemplate.cs

@@ -2,12 +2,14 @@
 using SqlSugar;
 using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using XF.Domain.Repository;
 
 namespace Hotline.Snapshot;
+[Description("行业短信模板")]
 public class SnapshotSMSTemplate : FullStateEntity
 {
     /// <summary>

+ 56 - 0
src/Hotline/Snapshot/SnapshotUserInfo.cs

@@ -0,0 +1,56 @@
+using Hotline.Share.Enums.Snapshot;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Snapshot;
+
+/// <summary>
+/// 网格员和普通随手拍人员信息
+/// </summary>
+[Description("随手拍用户信息")]
+public class SnapshotUserInfo : CreationSoftDeleteEntity
+{
+    /// <summary>
+    /// 用户自己填的邀请码
+    /// </summary>
+    [SugarColumn(ColumnDescription = "用户自己填的邀请码")]
+    public string? InvitationCode { get; set; }
+
+    /// <summary>
+    /// 历史已经领取金额总和(单位:元)
+    /// </summary>
+    [SugarColumn(ColumnDescription = "历史已经领取金额总和(单位:元)")]
+    public double TotalAmount { get; set; }
+
+    /// <summary>
+    /// 第三方账号Id
+    /// <inheritdoc cref="Hotline.ThirdAccountDomainServices.ThirdAccount"/>
+    /// </summary>
+    [SugarColumn(ColumnDescription = "第三方账号Id")]
+    public string? ThirdAccountId { get; set; }
+
+    /// <summary>
+    /// 用户类型
+    /// 注册时根据手机号码判断是否是 网格员
+    /// </summary>
+    [SugarColumn(ColumnDescription = "用户类型")]
+    public EReadPackUserType CitizenType { get; set; }
+
+    /// <summary>
+    /// 姓名
+    /// </summary>
+    [SugarColumn(ColumnDescription = "姓名")]
+    public string? Name { get; set; }
+
+    /// <summary>
+    /// 电话号码
+    /// </summary>
+    [SugarColumn(ColumnDescription = "电话号码")]
+    public string? PhoneNumber { get; set; }
+}

+ 46 - 0
src/Hotline/ThirdAccountDomainServices/Interfaces/IThirdAccountDomainService.cs

@@ -0,0 +1,46 @@
+using Hotline.Share.Dtos.Snapshot;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.ThirdAccountDomainServices.Interfaces;
+public interface IThirdAccountDomainService
+{
+    /// <summary>
+    /// 如何用户不存在,注册新的用户
+    /// </summary>
+    /// <param name="account"></param>
+    /// <param name="token"></param>
+    /// <returns></returns>
+    Task RegisterAsync(ThirdAccount account, CancellationToken token);
+
+    /// <summary>
+    /// 登录成功后添加到SessionContext中的参数
+    /// </summary>
+    /// <param name="account"></param>
+    /// <param name="claims"></param>
+    /// <param name="token"></param>
+    /// <returns></returns>
+    Task<List<Claim>> GetClaimAsync(ThirdAccount account, List<Claim> claims, CancellationToken token);
+
+    /// <summary>
+    /// 登录成功后返回给前端的参数
+    /// </summary>
+    /// <param name="thirdAccount"></param>
+    /// <param name="dicOutData"></param>
+    /// <param name="cancel"></param>
+    /// <returns></returns>
+    Task<Dictionary<string, object>> GetLoginOutDataAsync(ThirdAccount thirdAccount, Dictionary<string, object> dicOutData, CancellationToken cancel);
+
+    /// <summary>
+    /// 调用第三方接口需要的入参
+    /// </summary>
+    /// <param name="thirdDto"></param>
+    /// <param name="token"></param>
+    /// <returns></returns>
+    Task<ThirdTokenDto> GetThirdParameterAsync(ThirdTokenDto thirdDto, CancellationToken token);
+}
+

+ 1 - 1
src/Hotline/Snapshot/Interfaces/IThirdAccountRepository.cs → src/Hotline/ThirdAccountDomainServices/Interfaces/IThirdAccountRepository.cs

@@ -1,6 +1,6 @@
 using XF.Domain.Repository;
 
-namespace Hotline.Snapshot.Interfaces;
+namespace Hotline.ThirdAccountDomainServices.Interfaces;
 public interface IThirdAccountRepository : IRepository<ThirdAccount>
 {
     Task<ThirdAccount> GetByOpenIdAsync(string openId);

+ 3 - 3
src/Hotline/Users/IThirdIdentiyService.cs → src/Hotline/ThirdAccountDomainServices/Interfaces/IThirdIdentiyService.cs

@@ -1,13 +1,13 @@
 using Hotline.Share.Dtos.Snapshot;
 
-namespace Hotline.Users;
+namespace Hotline.ThirdAccountDomainServices.Interfaces;
 
 /// <summary>
 /// 第三方认证服务
 /// </summary>
 public interface IThirdIdentiyService
 {
-    Task<ThirdTokenOutDto> GetTokenAsync(ThirdTokenDto dto);
+    Task<ThirdTokenOutDto> GetTokenAsync(ThirdTokenDto dto, CancellationToken token);
 
-    Task<ThirdPhoneOutDto> GetPhoneNumberAsync(ThirdTokenDto dto);
+    Task<ThirdPhoneOutDto> GetPhoneNumberAsync(ThirdTokenDto dto, CancellationToken token);
 }

+ 9 - 46
src/Hotline/Snapshot/ThirdAccount.cs → src/Hotline/ThirdAccountDomainServices/ThirdAccount.cs

@@ -4,8 +4,10 @@ using System.ComponentModel;
 using XF.Domain.Repository;
 using Hotline.Orders;
 using Hotline.Share.Enums.User;
+using Hotline.Snapshot;
+using Hotline.Share.Enums.ThirdAccount;
 
-namespace Hotline.Snapshot;
+namespace Hotline.ThirdAccountDomainServices;
 
 /// <summary>
 /// 随手拍用户微信小程序登录信息
@@ -13,21 +15,6 @@ namespace Hotline.Snapshot;
 [Description("小程序账号信息")]
 public class ThirdAccount : CreationSoftDeleteEntity
 {
-    /// <summary>
-    /// 关联用户信息
-    /// 如果是市民: 关联 <inheritdoc cref="Citizen"/>
-    /// 如果是网格员: 关联 <inheritdoc cref="GuiderInfo"/>
-    /// </summary>
-    [SugarColumn(ColumnDescription = "关联用户信息")]
-    public string? UserId { get; set; }
-
-    /// <summary>
-    /// 用户类型
-    /// 注册时根据手机号码判断是否是 网格员
-    /// </summary>
-    [SugarColumn(ColumnDescription = "用户类型")]
-    public EReadPackUserType CitizenType { get; set; }
-
     /// <summary>
     /// 电话
     /// </summary>
@@ -53,51 +40,27 @@ public class ThirdAccount : CreationSoftDeleteEntity
     /// </summary>
     public EThirdType AccountType { get; set; }
 
-    /// <summary>
-    /// 历史已经领取金额总和(单位:元)
-    /// </summary>
-    [SugarColumn(ColumnDescription = "历史已经领取金额总和(单位:元)")]
-    public double TotalAmount { get; set; }
-
     /// <summary>
     /// 用户头像Url
     /// </summary>
     [SugarColumn(ColumnDescription = "用户头像Url")]
     public string? HeadImgUrl { get; set; }
 
-    /// <summary>
-    /// 用户自己填的邀请码
-    /// </summary>
-    [SugarColumn(ColumnDescription = "用户自己填的邀请码")]
-    public string? InvitationCode { get; set; }
-
     /// <summary>
     /// 用户昵称
     /// </summary>
     [SugarColumn(ColumnDescription = "用户昵称")]
     public string? UserName { get; set; }
 
-    ///// <summary>
-    ///// 应用类型
-    ///// </summary>
-    //[SugarColumn(ColumnDescription = "应用类型", DefaultValue = "1")]
-    //public EAppType AppType { get; set; }
-}
-
-public enum EAppType
-{
-    /// <summary>
-    /// 随手拍
-    /// </summary>
-    Snapshot = 1,
-
     /// <summary>
-    /// 部门办件app
+    /// 用户在开放平台的唯一标识符。本字段在满足一定条件的情况下才返回。具体参看:https://mp.weixin.qq.com/debug/wxadoc/dev/api/uinionID.html
     /// </summary>
-    Department = 2,
+    [SugarColumn(ColumnDescription = "用户在开放平台的唯一标识符")]
+    public string? UnIonId { get; set; }
 
     /// <summary>
-    /// 市民办件app
+    /// 应用类型
     /// </summary>
-    Citizen = 3
+    [SugarColumn(ColumnDescription = "应用类型", DefaultValue = "1")]
+    public EAppType AppType { get; set; }
 }

+ 41 - 0
src/Hotline/ThirdAccountDomainServices/ThirdAccountDomainFactory.cs

@@ -0,0 +1,41 @@
+using Hotline.Share.Dtos.Snapshot;
+using Hotline.Share.Enums.KnowledgeBase;
+using Hotline.Share.Enums.ThirdAccount;
+using Hotline.Share.Enums.User;
+using Hotline.ThirdAccountDomainServices.Interfaces;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+
+namespace Hotline.ThirdAccountDomainServices;
+public class ThirdAccountDomainFactory : IThirdAccountDomainService, ISelfDependency, IScopeDependency
+{
+    private readonly IEnumerable<IThirdAccountDomainService> _serviceItems;
+
+    public ThirdAccountDomainFactory(IEnumerable<IThirdAccountDomainService> serviceItems)
+    {
+        _serviceItems = serviceItems;
+    }
+
+    public IThirdAccountDomainService GetSupplier(EAppType enumType)
+        => _serviceItems
+        .FirstOrDefault(supplier => supplier.GetType().Name.ToLower().StartsWith(enumType.ToString().ToLower()))
+        ?? _serviceItems.First();
+
+    public async Task<List<Claim>> GetClaimAsync(ThirdAccount account, List<Claim> claims, CancellationToken token)
+        => await GetSupplier(account.AppType).GetClaimAsync(account, claims, token);
+
+    public async Task<Dictionary<string, object>> GetLoginOutDataAsync(ThirdAccount thirdAccount, Dictionary<string, object> dicOutData, CancellationToken cancel)
+        => await GetSupplier(thirdAccount.AppType).GetLoginOutDataAsync(thirdAccount, dicOutData, cancel);
+
+    public async Task<ThirdTokenDto> GetThirdParameterAsync(ThirdTokenDto thirdDto, CancellationToken token)
+        => await GetSupplier(thirdDto.AppType).GetThirdParameterAsync(thirdDto, token);
+
+    public async Task RegisterAsync(ThirdAccount account, CancellationToken token)
+        => await GetSupplier(account.AppType).RegisterAsync(account, token);
+}
+

+ 33 - 0
src/Hotline/ThirdAccountDomainServices/ThirdIdentiyFactory.cs

@@ -0,0 +1,33 @@
+using Hotline.Settings.TimeLimitDomain.ExpireTimeSupplier;
+using Hotline.Share.Dtos.Snapshot;
+using Hotline.Share.Enums.Settings;
+using Hotline.Share.Enums.User;
+using Hotline.ThirdAccountDomainServices.Interfaces;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+
+namespace Hotline.ThirdAccountDomainServices;
+public class ThirdIdentiyFactory : IThirdIdentiyService, ISelfDependency, IScopeDependency
+{
+    private readonly IEnumerable<IThirdIdentiyService> _thirdIdentityServices;
+
+    public ThirdIdentiyFactory(IEnumerable<IThirdIdentiyService> thirdIdentityServices)
+    {
+        _thirdIdentityServices = thirdIdentityServices;
+    }
+
+    public IThirdIdentiyService GetSupplier(EThirdType thirdType)
+        => _thirdIdentityServices
+        .FirstOrDefault(supplier => supplier.GetType().Name.ToLower().StartsWith(thirdType.ToString().ToLower()))
+        ?? _thirdIdentityServices.First();
+
+    public async Task<ThirdTokenOutDto> GetTokenAsync(ThirdTokenDto dto, CancellationToken token)
+        => await GetSupplier(dto.ThirdType).GetTokenAsync(dto, token);
+
+    public async Task<ThirdPhoneOutDto> GetPhoneNumberAsync(ThirdTokenDto dto, CancellationToken token)
+        => await GetSupplier(dto.ThirdType).GetPhoneNumberAsync(dto, token);
+}

+ 52 - 1
src/Hotline/Tools/DynamicClassHelper.cs

@@ -17,7 +17,7 @@ public class DynamicClassHelper
         ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
         TypeBuilder typeBuilder = moduleBuilder.DefineType(className, TypeAttributes.Public);
 
-        foreach (var property in propInfos)
+        foreach (var property in propInfos.OrderBy(d=>d.Sort).ToList())
         {
             var propertyName = property.Prop.Trim().ToPascalCase();
             var propertyType = typeof(string);
@@ -51,4 +51,55 @@ public class DynamicClassHelper
         Type generatedType = typeBuilder.CreateType();
         return generatedType;
     }
+
+    public static Type CreateDynamicClass<TSource>(List<ColumnInfo> propInfos)
+    {
+        string className = "DynamicClass";
+        AssemblyName assemblyName = new AssemblyName("DynamicAssembly");
+        AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
+        TypeBuilder typeBuilder = moduleBuilder.DefineType(className, TypeAttributes.Public);
+        var sourceProps = typeof(TSource).GetProperties();
+
+        foreach (var property in propInfos.OrderBy(d => d.Sort).ToList())
+        {
+            var propertyName = property.Prop.Trim().ToPascalCase();
+            var propertyType = sourceProps.FirstOrDefault(d => d.Name == propertyName)?.PropertyType ?? typeof(string);
+
+            FieldBuilder fieldBuilder = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
+            PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
+
+            MethodAttributes getSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
+
+            MethodBuilder getMethodBuilder = typeBuilder.DefineMethod("get_" + propertyName, getSetAttributes, propertyType, Type.EmptyTypes);
+            ILGenerator getIL = getMethodBuilder.GetILGenerator();
+            getIL.Emit(OpCodes.Ldarg_0);
+            getIL.Emit(OpCodes.Ldfld, fieldBuilder);
+            getIL.Emit(OpCodes.Ret);
+
+            MethodBuilder setMethodBuilder = typeBuilder.DefineMethod("set_" + propertyName, getSetAttributes, null, new Type[] { propertyType });
+            ILGenerator setIL = setMethodBuilder.GetILGenerator();
+            setIL.Emit(OpCodes.Ldarg_0);
+            setIL.Emit(OpCodes.Ldarg_1);
+            setIL.Emit(OpCodes.Stfld, fieldBuilder);
+            setIL.Emit(OpCodes.Ret);
+
+            propertyBuilder.SetGetMethod(getMethodBuilder);
+            propertyBuilder.SetSetMethod(setMethodBuilder);
+
+            var columnNameCtorInfo = typeof(ExcelColumnNameAttribute).GetConstructor(new Type[] { typeof(string), typeof(string[]) });
+            var attributeBuilder = new CustomAttributeBuilder(columnNameCtorInfo, new object[] { property.Name, null });
+            propertyBuilder.SetCustomAttribute(attributeBuilder);
+
+            if (propertyType == typeof(DateTime))
+            {
+                var columnExcelFormatCtorInfo = typeof(ExcelFormatAttribute).GetConstructor(new Type[] { typeof(string) });
+                var excelFormatAttributeBuilder = new CustomAttributeBuilder(columnExcelFormatCtorInfo, new object[] { "yyyy-MM-dd HH:mm:ss" });
+                propertyBuilder.SetCustomAttribute(excelFormatAttributeBuilder);
+            }
+        }
+
+        Type generatedType = typeBuilder.CreateType();
+        return generatedType;
+    }
 }

+ 3 - 2
test/Hotline.Tests/Application/BiSnapshotApplicationTest.cs

@@ -5,7 +5,8 @@ using Hotline.Identity.Roles;
 using Hotline.Settings;
 using Hotline.Share.Dtos.Snapshot;
 using Hotline.Share.Tools;
-using Hotline.Snapshot.Interfaces;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
 using Mapster;
 using Microsoft.AspNetCore.Http;
@@ -24,7 +25,7 @@ namespace Hotline.Tests.Application;
 public class BiSnapshotApplicationTest : TestBase
 {
     private readonly IBiSnapshotApplication _biSnapshotApplication;
-    public BiSnapshotApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, ITypedCache<SystemSetting> cacheSettingData, IBiSnapshotApplication biSnapshotApplication) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData)
+    public BiSnapshotApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, ITypedCache<SystemSetting> cacheSettingData, IBiSnapshotApplication biSnapshotApplication, ThirdAccountDomainFactory thirdAccountDomainFactory) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData, thirdAccountDomainFactory)
     {
         _biSnapshotApplication = biSnapshotApplication;
     }

+ 3 - 2
test/Hotline.Tests/Application/DefaultCallApplicationTest.cs

@@ -11,7 +11,8 @@ using Hotline.Settings;
 using Hotline.Share.Dtos.CallCenter;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.CallCenter;
-using Hotline.Snapshot.Interfaces;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
 using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.DependencyInjection;
@@ -30,7 +31,7 @@ public class DefaultCallApplicationTest : TestBase
     private readonly IOrderRepository _orderRepository;
     private readonly ICallTelClient _callTelClient;
 
-    public DefaultCallApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, XingTangCallApplication defaultCallApplication, IOrderVisitRepository orderVisitRepository, IRepository<CallNative> callNativeRepository, IOrderRepository orderRepository, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ITypedCache<SystemSetting> cacheSettingData, ICallTelClient callTelClient) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData)
+    public DefaultCallApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, XingTangCallApplication defaultCallApplication, IOrderVisitRepository orderVisitRepository, IRepository<CallNative> callNativeRepository, IOrderRepository orderRepository, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ITypedCache<SystemSetting> cacheSettingData, ICallTelClient callTelClient, ThirdAccountDomainFactory thirdAccountDomainFactory) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData, thirdAccountDomainFactory)
     {
         _fixture = new Fixture();
         _defaultCallApplication = defaultCallApplication;

+ 3 - 1
test/Hotline.Tests/Application/IndustryApplicationTest.cs

@@ -15,6 +15,8 @@ using Shouldly;
 using XF.Domain.Repository;
 using Hotline.Settings;
 using XF.Domain.Cache;
+using Hotline.ThirdAccountDomainServices.Interfaces;
+using Hotline.ThirdAccountDomainServices;
 
 namespace Hotline.Tests.Application;
 public class IndustryApplicationTest : TestBase
@@ -23,7 +25,7 @@ public class IndustryApplicationTest : TestBase
     private readonly IIndustryRepository _industryRepository;
     private readonly ISystemOrganizeRepository _systemOrganizeRepository;
 
-    public IndustryApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, IIndustryApplication industryApplication, IIndustryRepository industryRepository, ISystemOrganizeRepository systemOrganizeRepository, ITypedCache<SystemSetting> cacheSettingData) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData)
+    public IndustryApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, IIndustryApplication industryApplication, IIndustryRepository industryRepository, ISystemOrganizeRepository systemOrganizeRepository, ITypedCache<SystemSetting> cacheSettingData, ThirdAccountDomainFactory thirdAccountDomainFactory) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData, thirdAccountDomainFactory)
     {
         _industryApplication = industryApplication;
         _industryRepository = industryRepository;

+ 8 - 3
test/Hotline.Tests/Application/InviteCodeApplicationTest.cs

@@ -6,6 +6,8 @@ using Hotline.Repository.SqlSugar.Snapshot;
 using Hotline.Settings;
 using Hotline.Share.Dtos.Snapshot;
 using Hotline.Snapshot.Interfaces;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
 using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.DependencyInjection;
@@ -27,14 +29,16 @@ public class InviteCodeApplicationTest : TestBase
     private readonly IInviteCodeRepository _inviteCodeRepository;
     private readonly ISessionContext _sessionContext;
     private readonly IInviteCodeRecordRepository _inviteCodeRecordRepository;
+    private readonly ISnapshotUserInfoRepository _snapshotUserInfoRepository;
 
-    public InviteCodeApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, IInviteCodeApplication inviteCodeApplication, ISnapshotApplication snapshotApplication, IInviteCodeRepository inviteCodeRepository, ISessionContext sessionContext, IInviteCodeRecordRepository inviteCodeRecordRepository, ITypedCache<SystemSetting> cacheSettingData) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData)
+    public InviteCodeApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, IInviteCodeApplication inviteCodeApplication, ISnapshotApplication snapshotApplication, IInviteCodeRepository inviteCodeRepository, ISessionContext sessionContext, IInviteCodeRecordRepository inviteCodeRecordRepository, ITypedCache<SystemSetting> cacheSettingData, ISnapshotUserInfoRepository snapshotUserInfoRepository, ThirdAccountDomainFactory thirdAccountDomainFactory) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData, thirdAccountDomainFactory)
     {
         _inviteCodeApplication = inviteCodeApplication;
         _snapshotApplication = snapshotApplication;
         this._inviteCodeRepository = inviteCodeRepository;
         _sessionContext = sessionContext;
         _inviteCodeRecordRepository = inviteCodeRecordRepository;
+        _snapshotUserInfoRepository = snapshotUserInfoRepository;
     }
 
     [Fact]
@@ -54,9 +58,10 @@ public class InviteCodeApplicationTest : TestBase
         await _inviteCodeRepository.RemoveAsync(id);
 
         SetWeiXin();
-        await _thirdAccountRepository.Updateable()
+
+        await _snapshotUserInfoRepository.Updateable()
             .SetColumns(m => m.InvitationCode, null)
-            .Where(m => m.OpenId == _sessionContext.OpenId)
+            .Where(m => m.ThirdAccountId == _sessionContext.UserId)
             .ExecuteCommandAsync();
         await _inviteCodeRecordRepository.Removeable().Where(m => m.InviteCode == "110").ExecuteCommandAsync();
         await _snapshotApplication.SaveInvitationCodeAsync(new SaveInvitationCodeInDto { InvitationCode = "110"});

+ 3 - 2
test/Hotline.Tests/Application/KnowApplicationTest.cs

@@ -7,7 +7,8 @@ using Hotline.KnowledgeBase.Notifies;
 using Hotline.Settings;
 using Hotline.Share.Dtos.Knowledge;
 using Hotline.Share.Tools;
-using Hotline.Snapshot.Interfaces;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
 using Mapster;
 using MediatR;
@@ -33,7 +34,7 @@ public class KnowApplicationTest : TestBase
     private readonly IRepository<KnowledgeWord> _knowledgeWordRepository;
     private readonly IRepository<KnowledgeHotWord> _knowledgeHotWordRepository;
 
-    public KnowApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IKnowApplication knowApplication, IMediator mediator, IRepository<KnowledgeBase.Knowledge> knowledgeRepository, IKnowledgeDomainService knowledgeDomainService, IRepository<KnowledgeWord> knowledgeWordRepository, IRepository<KnowledgeHotWord> knowledgeHotWordRepository, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ITypedCache<SystemSetting> cacheSettingData) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData)
+    public KnowApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IKnowApplication knowApplication, IMediator mediator, IRepository<KnowledgeBase.Knowledge> knowledgeRepository, IKnowledgeDomainService knowledgeDomainService, IRepository<KnowledgeWord> knowledgeWordRepository, IRepository<KnowledgeHotWord> knowledgeHotWordRepository, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ITypedCache<SystemSetting> cacheSettingData, ThirdAccountDomainFactory thirdAccountDomainFactory) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData, thirdAccountDomainFactory)
     {
         _knowApplication = knowApplication;
         _mediator = mediator;

+ 3 - 1
test/Hotline.Tests/Application/OrderSnapshotApplicationTest.cs

@@ -14,6 +14,8 @@ using Hotline.Share.Requests;
 using Hotline.Share.Tools;
 using Hotline.Snapshot.Interfaces;
 using Hotline.Tests.Mock;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
 using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.DependencyInjection;
@@ -43,7 +45,7 @@ public class OrderSnapshotApplicationTest : TestBase
     private readonly IRedPackApplication _redPackApplication;
     private readonly IOrderRepository _orderRepository;
 
-    public OrderSnapshotApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, OrderServiceMock orderServiceMock, ISystemDicDataCacheManager systemDicDataCacheManager, IOrderSnapshotRepository orderSnapshotRepository, IOrderSnapshotApplication orderSnapshotApplication, ISnapshotApplication snapshotApplication, IIndustryLogRepository industryLogRepository, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IRedPackRecordRepository redPackRecordRepository, ISnapshotLabelLogRepository snapshotLabelLogRepository, ITypedCache<SystemSetting> cacheSettingData, IRedPackApplication redPackApplication, IOrderRepository orderRepository) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData)
+    public OrderSnapshotApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, OrderServiceMock orderServiceMock, ISystemDicDataCacheManager systemDicDataCacheManager, IOrderSnapshotRepository orderSnapshotRepository, IOrderSnapshotApplication orderSnapshotApplication, ISnapshotApplication snapshotApplication, IIndustryLogRepository industryLogRepository, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IRedPackRecordRepository redPackRecordRepository, ISnapshotLabelLogRepository snapshotLabelLogRepository, ITypedCache<SystemSetting> cacheSettingData, IRedPackApplication redPackApplication, IOrderRepository orderRepository, ThirdAccountDomainFactory thirdAccountDomainFactory) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData, thirdAccountDomainFactory)
     {
         _orderServiceMock = orderServiceMock;
         _systemDicDataCacheManager = systemDicDataCacheManager;

+ 3 - 1
test/Hotline.Tests/Application/RedPackApplicationTest.cs

@@ -10,6 +10,8 @@ using Hotline.Share.Dtos.Snapshot;
 using Hotline.Share.Enums.Snapshot;
 using Hotline.Snapshot.Interfaces;
 using Hotline.Tests.Mock;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
 using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.DependencyInjection;
@@ -33,7 +35,7 @@ public class RedPackApplicationTest : TestBase
     private readonly IIndustryRepository _industryRepository;
     private readonly ISpecialRedPackAuditRepository _specialRedPackAuditRepository;
 
-    public RedPackApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, IRedPackApplication redPackApplication, IRedPackRecordRepository redPackRecordRepository, ITypedCache<SystemSetting> cacheSettingData, OrderServiceMock orderServiceMock, ISystemDicDataCacheManager systemDicDataCacheManager, IIndustryRepository industryRepository, ISpecialRedPackAuditRepository specialRedPackAuditRepository) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData)
+    public RedPackApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, IRedPackApplication redPackApplication, IRedPackRecordRepository redPackRecordRepository, ITypedCache<SystemSetting> cacheSettingData, OrderServiceMock orderServiceMock, ISystemDicDataCacheManager systemDicDataCacheManager, IIndustryRepository industryRepository, ISpecialRedPackAuditRepository specialRedPackAuditRepository, ThirdAccountDomainFactory thirdAccountDomainFactory) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData, thirdAccountDomainFactory)
     {
         _redPackApplication = redPackApplication;
         _redPackRecordRepository = redPackRecordRepository;

+ 17 - 12
test/Hotline.Tests/Application/SnapshotApplicationTest.cs

@@ -18,6 +18,8 @@ using Hotline.Share.Tools;
 using Hotline.Snapshot;
 using Hotline.Snapshot.Interfaces;
 using Hotline.Tests.Mock;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
 using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.DependencyInjection;
@@ -46,8 +48,9 @@ public class SnapshotApplicationTest : TestBase
     private readonly IIndustryLogRepository _industryLogRepository;
     private readonly IRedPackApplication _redPackApplication;
     private readonly IOrderSnapshotApplication _orderSnapshotApplication;
+    private readonly ISnapshotUserInfoRepository _snapshotUserInfoRepository;
 
-    public SnapshotApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, ISnapshotApplication snapshotApplication, IIdentityAppService identityAppService, IRepository<RedPackRecord> redPackRecordRepository, IIndustryApplication industryApplication, IIndustryRepository industryRepository, IFileRepository fileRepository, OrderServiceMock orderServiceMock, IOrderRepository orderRepository, IOrderSnapshotRepository orderSnapshotRepository, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ISessionContext sessionContext, IGuiderSystemService guiderSystemService, ISystemSettingCacheManager systemSettingCacheManager, ICommunityInfoRepository communityInfoRepository, IIndustryLogRepository industryLogRepository, IRedPackApplication redPackApplication, IOrderSnapshotApplication orderSnapshotApplication, ITypedCache<SystemSetting> cacheSettingData) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData)
+    public SnapshotApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, ISnapshotApplication snapshotApplication, IIdentityAppService identityAppService, IRepository<RedPackRecord> redPackRecordRepository, IIndustryApplication industryApplication, IIndustryRepository industryRepository, IFileRepository fileRepository, OrderServiceMock orderServiceMock, IOrderRepository orderRepository, IOrderSnapshotRepository orderSnapshotRepository, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ISessionContext sessionContext, IGuiderSystemService guiderSystemService, ISystemSettingCacheManager systemSettingCacheManager, ICommunityInfoRepository communityInfoRepository, IIndustryLogRepository industryLogRepository, IRedPackApplication redPackApplication, IOrderSnapshotApplication orderSnapshotApplication, ITypedCache<SystemSetting> cacheSettingData, ThirdAccountDomainFactory thirdAccountDomainFactory, ISnapshotUserInfoRepository snapshotUserInfoRepository) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData, thirdAccountDomainFactory)
     {
         _snapshotApplication = snapshotApplication;
         _identityAppService = identityAppService;
@@ -66,6 +69,7 @@ public class SnapshotApplicationTest : TestBase
         _industryLogRepository = industryLogRepository;
         _redPackApplication = redPackApplication;
         _orderSnapshotApplication = orderSnapshotApplication;
+        _snapshotUserInfoRepository = snapshotUserInfoRepository;
     }
 
     /// <summary>
@@ -230,7 +234,7 @@ public class SnapshotApplicationTest : TestBase
     [Fact]
     public async Task GetSnapshotUserInfo_Test()
     {
-        await _identityAppService.GetThredTokenAsync(new ThirdTokenInDto());
+        await _identityAppService.GetThredTokenAsync(new ThirdTokenInDto(), CancellationToken.None);
         var result = await _snapshotApplication.GetSnapshotUserInfoAsync();
         result.ShouldNotBeNull();
         result.PhoneNumber.ShouldNotBeNullOrEmpty();
@@ -244,11 +248,11 @@ public class SnapshotApplicationTest : TestBase
     [Fact]
     public async Task RefreshTokenAsync()
     {
-        var token = await _identityAppService.GetThredTokenAsync(new ThirdTokenInDto());
-        var newToken = await _identityAppService.RefreshTokenAsync(token.OpenId);
+        var token = await _identityAppService.GetThredTokenAsync(new ThirdTokenInDto(), CancellationToken.None);
+        var newToken = await _identityAppService.RefreshTokenAsync(token["OpenId"].ToString(), CancellationToken.None);
         newToken.ShouldNotBeNull();
-        newToken.OpenId.ShouldBe(token.OpenId);
-        newToken.PhoneNumber.ShouldNotBeNullOrEmpty();
+        newToken["OpenId"].ShouldBe(token["OpenId"].ToString());
+        newToken["PhoneNumber"].ToString().ShouldNotBeNullOrEmpty();
     }
 
     /// <summary>
@@ -258,8 +262,8 @@ public class SnapshotApplicationTest : TestBase
     [Fact]
     public async Task GetThirdToken_Test()
     {
-        var result = await _identityAppService.GetThredTokenAsync(new ThirdTokenInDto { LoginCode = "0c3Adhll2zDMBe413rnl2KvEym2AdhlH" });
-        result.PhoneNumber.ShouldNotBeNullOrEmpty();
+        var result = await _identityAppService.GetThredTokenAsync(new ThirdTokenInDto { LoginCode = "0c3Adhll2zDMBe413rnl2KvEym2AdhlH" }, CancellationToken.None);
+        result["PhoneNumber"].ToString().ShouldNotBeNullOrEmpty();
     }
 
     [Fact]
@@ -361,13 +365,14 @@ public class SnapshotApplicationTest : TestBase
         var code = new Random().Next(100, 200).ToString();
         try
         {
-            await _thirdAccountRepository.Updateable()
+            await _snapshotUserInfoRepository.Updateable()
                 .SetColumns(m => m.InvitationCode, null)
-                .Where(m => m.OpenId == _sessionContext.OpenId)
+                .Where(m => m.Id == _sessionContext.UserId)
                 .ExecuteCommandAsync();
             await _snapshotApplication.SaveInvitationCodeAsync(new SaveInvitationCodeInDto { InvitationCode = code });
-            var third = await _thirdAccountRepository.GetByOpenIdAsync(_sessionContext.OpenId);
-            third.InvitationCode.ShouldBe(code);
+            var userInfo = await _snapshotUserInfoRepository.GetAsync(_sessionContext.UserId);
+            userInfo.ShouldNotBeNull();
+            userInfo!.InvitationCode.ShouldBe(code);
         }
         catch (Exception e)
         {

+ 3 - 2
test/Hotline.Tests/Application/SystemSettingCacheManagerTest.cs

@@ -3,7 +3,8 @@ using Hotline.Caching.Interfaces;
 using Hotline.Identity.Accounts;
 using Hotline.Identity.Roles;
 using Hotline.Settings;
-using Hotline.Snapshot.Interfaces;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
 using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.DependencyInjection;
@@ -23,7 +24,7 @@ public class SystemSettingCacheManagerTest : TestBase
     private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
     private readonly IRepository<SystemSetting> _systemSettingRepository;
 
-    public SystemSettingCacheManagerTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, ISystemSettingCacheManager systemSettingCacheManager, ISystemDicDataCacheManager systemDicDataCacheManager, IRepository<SystemSetting> systemSettingRepository, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ITypedCache<SystemSetting> cacheSettingData) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData)
+    public SystemSettingCacheManagerTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, ISystemSettingCacheManager systemSettingCacheManager, ISystemDicDataCacheManager systemDicDataCacheManager, IRepository<SystemSetting> systemSettingRepository, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ITypedCache<SystemSetting> cacheSettingData, ThirdAccountDomainFactory thirdAccountDomainFactory) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData, thirdAccountDomainFactory)
     {
         _systemSettingCacheManager = systemSettingCacheManager;
         _systemDicDataCacheManager = systemDicDataCacheManager;

+ 3 - 2
test/Hotline.Tests/Controller/IndustryControllerTest.cs

@@ -3,7 +3,8 @@ using Hotline.Api.Controllers.Snapshot;
 using Hotline.Identity.Accounts;
 using Hotline.Identity.Roles;
 using Hotline.Settings;
-using Hotline.Snapshot.Interfaces;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
@@ -21,7 +22,7 @@ namespace Hotline.Tests.Controller;
 public class IndustryControllerTest : TestBase
 {
     private readonly IndustryController _industryController;
-    public IndustryControllerTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, IndustryController industryController, ITypedCache<SystemSetting> cacheSettingData) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData)
+    public IndustryControllerTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, IndustryController industryController, ITypedCache<SystemSetting> cacheSettingData, ThirdAccountDomainFactory thirdAccountDomainFactory) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData, thirdAccountDomainFactory)
     {
         _industryController = industryController;
         _industryController.ControllerContext = new ControllerContext

+ 3 - 2
test/Hotline.Tests/Controller/KnowledgeControllerTest.cs

@@ -6,8 +6,9 @@ using Hotline.Settings;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.Knowledge;
 using Hotline.Share.Enums.KnowledgeBase;
-using Hotline.Snapshot.Interfaces;
 using Hotline.Tests.Mock;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
@@ -28,7 +29,7 @@ public class KnowledgeControllerTest : TestBase
     private readonly KnowledgeController _knowledgeController;
     private readonly IRepository<KnowledgeBase.Knowledge> _knowledgeRepository;
 
-    public KnowledgeControllerTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, KnowledgeServiceMock knowledgeServiceMock, KnowledgeController knowledgeController, IRepository<KnowledgeBase.Knowledge> knowledgeRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ITypedCache<SystemSetting> cacheSettingData) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData)
+    public KnowledgeControllerTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, KnowledgeServiceMock knowledgeServiceMock, KnowledgeController knowledgeController, IRepository<KnowledgeBase.Knowledge> knowledgeRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ITypedCache<SystemSetting> cacheSettingData, ThirdAccountDomainFactory thirdAccountDomainFactory) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData, thirdAccountDomainFactory)
     {
         _knowledgeServiceMock = knowledgeServiceMock;
         _knowledgeController = knowledgeController;

+ 4 - 2
test/Hotline.Tests/Controller/OrderControllerTest.cs

@@ -42,6 +42,8 @@ using XF.Domain.Authentications;
 using XF.Domain.Cache;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
+using Hotline.ThirdAccountDomainServices.Interfaces;
+using Hotline.ThirdAccountDomainServices;
 
 namespace Hotline.Tests.Controller;
 
@@ -81,9 +83,9 @@ public class OrderControllerTest : TestBase
         ISystemLogRepository systemLogRepository, IOrderVisitDomainService orderVisitDomainService,
         IRepository<OrderVisitDetail> orderVisitDetailRepository, ISystemDicDataCacheManager systemDicDataCacheManager,
         IWorkflowDomainService workflowDomainService,
-        ITypedCache<SystemSetting> cacheSettingData)
+        ITypedCache<SystemSetting> cacheSettingData, ThirdAccountDomainFactory thirdAccountDomainFactory)
         : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount,
-            cacheSettingData)
+            cacheSettingData, thirdAccountDomainFactory)
     {
         _hotspotRepository = hotspotRepository;
         _orderController = orderController;

+ 3 - 1
test/Hotline.Tests/Controller/SnapshotControllerTest.cs

@@ -10,6 +10,8 @@ using Hotline.Share.Dtos.Snapshot;
 using Hotline.Share.Enums.Snapshot;
 using Hotline.Share.Tools;
 using Hotline.Snapshot.Interfaces;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
@@ -33,7 +35,7 @@ public class SnapshotControllerTest : TestBase
     private readonly IEasyCachingProvider _easyCaching;
     private readonly IRedisCachingProvider _redisCaching;
 
-    public SnapshotControllerTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, SnapshotController snapshotController, IOrderRepository orderRepository, IOrderSnapshotRepository orderSnapshotRepository, IIndustryRepository industryRepository, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, IEasyCachingProvider easyCaching, IRedisCachingProvider redisCaching, ITypedCache<SystemSetting> cacheSettingData) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData)
+    public SnapshotControllerTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, SnapshotController snapshotController, IOrderRepository orderRepository, IOrderSnapshotRepository orderSnapshotRepository, IIndustryRepository industryRepository, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, IEasyCachingProvider easyCaching, IRedisCachingProvider redisCaching, ITypedCache<SystemSetting> cacheSettingData, ThirdAccountDomainFactory thirdAccountDomainFactory) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData, thirdAccountDomainFactory)
     {
         _snapshotController = snapshotController;
         _snapshotController.ControllerContext = new ControllerContext

+ 1 - 0
test/Hotline.Tests/Controller/TestSessionContext.cs

@@ -16,6 +16,7 @@ public class TestSessionContext : ISessionContext, IScopeDependency
     {
         _contextAccessor = httpContextAccessor;
         _changeSessionProvider = serviceProvider.GetService<ISessionContextProvider>();
+        //_contextAccessor.HttpContext ??= new DefaultHttpContext();
         //if (httpContextAccessor.HttpContext == null) _contextAccessor.HttpContext = new DefaultHttpContext();
     }
 

+ 3 - 2
test/Hotline.Tests/Domain/OrderVisitDomainServiceTest.cs

@@ -13,8 +13,9 @@ using Hotline.Share.Dtos.Push;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Push;
 using Hotline.Share.Tools;
-using Hotline.Snapshot.Interfaces;
 using Hotline.Tests.Mock;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
 using Mapster;
 using Microsoft.AspNetCore.Http;
@@ -38,7 +39,7 @@ public class OrderVisitDomainServiceTest : TestBase
     private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
     private readonly ISystemLogRepository _logRepository;
 
-    public OrderVisitDomainServiceTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IOrderVisitDomainService orderVisitDomainService, IOrderVisitRepository orderVisitRepository, IRepository<OrderVisitDetail> orderVisitDetailRepository, Publisher publisher, IOrderRepository orderRepository, OrderServiceMock orderServiceMock, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ISettingOrderVisitSmsReplyRuleRepository settingOrderVisitSmsReplyRuleRepository, ISystemDicDataCacheManager systemDicDataCacheManager, IOptionsSnapshot<AppConfiguration> appOptions, ISystemLogRepository logRepository, ITypedCache<SystemSetting> cacheSettingData) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData)
+    public OrderVisitDomainServiceTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IOrderVisitDomainService orderVisitDomainService, IOrderVisitRepository orderVisitRepository, IRepository<OrderVisitDetail> orderVisitDetailRepository, Publisher publisher, IOrderRepository orderRepository, OrderServiceMock orderServiceMock, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ISettingOrderVisitSmsReplyRuleRepository settingOrderVisitSmsReplyRuleRepository, ISystemDicDataCacheManager systemDicDataCacheManager, IOptionsSnapshot<AppConfiguration> appOptions, ISystemLogRepository logRepository, ITypedCache<SystemSetting> cacheSettingData, ThirdAccountDomainFactory thirdAccountDomainFactory) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData, thirdAccountDomainFactory)
     {
         _orderVisitDomainService = orderVisitDomainService;
         _orderVisitRepository = orderVisitRepository;

+ 1 - 1
test/Hotline.Tests/Infrastructure/WeiXinTest.cs

@@ -14,6 +14,6 @@ public class WeiXinTest
     // [Fact]
     public async Task GetPhoneNumber_Test()
     {
-        var result = await _weChatService.GetPhoneNumberAsync(new ThirdTokenDto { AppId = "12333", Secret = "4444444" });
+        var result = await _weChatService.GetPhoneNumberAsync(new ThirdTokenDto { AppId = "12333", Secret = "4444444" }, CancellationToken.None);
     }
 }

+ 3 - 3
test/Hotline.Tests/Mock/ThirdTestService.cs

@@ -1,11 +1,11 @@
 using Hotline.Share.Dtos.Snapshot;
-using Hotline.Users;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using XF.Domain.Dependency;
 
 namespace Hotline.Tests.Mock;
 public class ThirdTestService : IThirdIdentiyService, IScopeDependency
 {
-    public async Task<ThirdPhoneOutDto> GetPhoneNumberAsync(ThirdTokenDto dto)
+    public async Task<ThirdPhoneOutDto> GetPhoneNumberAsync(ThirdTokenDto dto, CancellationToken token)
     {
         return new ThirdPhoneOutDto
         {
@@ -13,7 +13,7 @@ public class ThirdTestService : IThirdIdentiyService, IScopeDependency
         };
     }
 
-    public async Task<ThirdTokenOutDto> GetTokenAsync(ThirdTokenDto dto)
+    public async Task<ThirdTokenOutDto> GetTokenAsync(ThirdTokenDto dto, CancellationToken token)
     {
         //var resultString = "{\"SessionKey\":\"letVB1m+8ZYsMjo8PxhwUw==\",\"OpenId\":\"oHBwj4_8hQG1Q00HyTO3d47RLuAA\"}";
         //return resultString.FromJson<ThirdTokenOutDto>();

+ 1 - 1
test/Hotline.Tests/Startup.cs

@@ -29,7 +29,6 @@ using Hotline.Snapshot.Interfaces;
 using Hotline.Tests.Mock;
 using Hotline.Tests.Mock.Interfaces;
 using Hotline.Tests.SqlSuger;
-using Hotline.Users;
 using Mapster;
 using MediatR;
 using Microsoft.AspNetCore.Builder;
@@ -53,6 +52,7 @@ using XF.EasyCaching;
 using XF.Utility.MQ;
 using Xunit.DependencyInjection.AspNetCoreTesting;
 using Hotline.Pdf;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 
 namespace Hotline.Tests;
 public class Startup

+ 20 - 7
test/Hotline.Tests/TestBase.cs

@@ -6,9 +6,12 @@ using Hotline.Identity.Roles;
 using Hotline.Settings;
 using Hotline.Share.Dtos.Users;
 using Hotline.Share.Enums.Order;
+using Hotline.Share.Enums.ThirdAccount;
 using Hotline.Share.Enums.User;
 using Hotline.Snapshot.Interfaces;
 using Hotline.Tests.Infrastructure;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
 using IdentityModel;
 using Microsoft.AspNetCore.Http;
@@ -31,8 +34,9 @@ public class TestBase
     public readonly IThirdIdentiyService _thirdIdentiyService;
     public readonly IThirdAccountRepository _thirdAccountRepository;
     private readonly ITypedCache<SystemSetting> _cacheSettingData;
+    public readonly ThirdAccountDomainFactory _thirdAccountDomainFactory;
 
-    public TestBase(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, ITypedCache<SystemSetting> cacheSettingData)
+    public TestBase(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, ITypedCache<SystemSetting> cacheSettingData, ThirdAccountDomainFactory thirdAccountDomainFactory)
     {
         _thirdAccountRepository = thirdAccountRepository;
         _thirdIdentiyService = thirdIdentiyService;
@@ -55,6 +59,7 @@ public class TestBase
         }
 
         _cacheSettingData = cacheSettingData;
+        _thirdAccountDomainFactory = thirdAccountDomainFactory;
     }
 
     public void SetSettingCache(string code, string value)
@@ -123,7 +128,7 @@ public class TestBase
     }
 
     public void Set政法委()
-    { 
+    {
         SetOperator("区县政法委", "自流井区人民政府/自流井区政法委", "单元测试政法委", "001055048", "13408389849", EUserType.Normal, TestSettingConstants.ZFWAccountName);
     }
 
@@ -134,7 +139,7 @@ public class TestBase
 
     public void SetWeiXin()
     {
-        SetOperator("微信用户", "", "", "", "138001389877", EUserType.Normal, TestSettingConstants.WeiXinAccountName);
+        SetOperator("微信用户", "", "", "", "138001389877", EUserType.Normal, TestSettingConstants.WeiXinAccountName, EThirdType.WeChat, EAppType.Snapshot);
     }
 
     public void Set网格员()
@@ -142,7 +147,7 @@ public class TestBase
         SetOperator("网格员", "市民热线服务中心", "单元测试网格员", "001", "13408389849", EUserType.Normal, TestSettingConstants.GuiderAccountName);
     }
 
-    private void SetOperator(string displayName, string fullOrgName, string name, string orgId, string phoneNo, EUserType userType, string userName)
+    private void SetOperator(string displayName, string fullOrgName, string name, string orgId, string phoneNo, EUserType userType, string userName, EThirdType? thirdType = null, EAppType? appType = null)
     {
         var account = _accountRepository.GetExtAsync(
             d => d.UserName == userName,
@@ -174,7 +179,7 @@ public class TestBase
         var user = _userRepository.Queryable()
             .Includes(d => d.Organization)
             .FirstAsync(d => d.Id == account.Id).GetAwaiter().GetResult();
-        var third = _thirdIdentiyService.GetTokenAsync(new Share.Dtos.Snapshot.ThirdTokenDto()).GetAwaiter().GetResult();
+        var third = _thirdIdentiyService.GetTokenAsync(new Share.Dtos.Snapshot.ThirdTokenDto(), CancellationToken.None).GetAwaiter().GetResult();
         var thirdAccount = _thirdAccountRepository.Get(d => d.OpenId == third.OpenId);
 
         var appScope = "ZiGong";
@@ -188,7 +193,6 @@ public class TestBase
         List<Claim> userClaims = [
             new(JwtClaimTypes.Subject, account.Id ?? thirdAccount.Id),
             new(JwtClaimTypes.PhoneNumber, account.PhoneNo ?? thirdAccount.PhoneNumber),
-            new(ClaimTypes.NameIdentifier, user.Id),
             new(AppClaimTypes.UserDisplayName, account.Name),
             new(AppClaimTypes.DepartmentId, user.OrgId ?? string.Empty),
             new(AppClaimTypes.DepartmentIsCenter, user.Organization?.IsCenter.ToString() ?? false.ToString()),
@@ -200,10 +204,19 @@ public class TestBase
             new(AppClaimTypes.OpenId, thirdAccount?.OpenId ?? string.Empty),
             new("AppScope", appScope)
         ];
+        if (appType != null && thirdType != null)
+        {
+            var claims = _thirdAccountDomainFactory.GetClaimAsync(new ThirdAccount { Id = thirdAccount.Id, PhoneNumber = phoneNo, AccountType = thirdType.Value, AppType = appType.Value }, new List<Claim>(), CancellationToken.None).GetAwaiter().GetResult();
+            userClaims.Add(new(ClaimTypes.NameIdentifier, claims.First().Value));
+        }
+        else
+        {
+            userClaims.Add(new(ClaimTypes.NameIdentifier, user.Id));
+        }
         userClaims.AddRange(account.Roles.Select(d => new Claim(JwtClaimTypes.Role, d.Name)));
         ClaimsIdentity identity = new ClaimsIdentity(userClaims);
         var principal = new ClaimsPrincipal(identity);
         _httpContextAccessor.HttpContext.User = principal;
-        
+
     }
 }

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است