Преглед на файлове

Merge branch 'dev' of http://git.12345lm.cn/Fengwo/hotline into dev

tangjiang преди 10 месеца
родител
ревизия
c3085d223e

+ 4 - 2
src/Hotline.Api/Controllers/AiController.cs

@@ -52,8 +52,9 @@ namespace Hotline.Api.Controllers
         private readonly IRepository<CallOutTemplate> _callOutTemplateRepository;
         private readonly IRepository<CallOutTask> _callOutTaskRepository;
         private readonly IRepository<CallOutTaskDetail> _callOutTaskDetailRepository;
+        private readonly ISessionContext _sessionContext;
 
-        public AiController(ISystemSettingCacheManager systemSettingCacheManager,IRepository<AiOrderVisit> aiOrderVisitRepository,IRepository<AiOrderVisitDetail>  aiOrderVisitDetailRepository,IRepository<OrderVisit> orderVisitRepository,IRepository<OrderVisitDetail> orderVisitDetailRepository,IMapper mapper, /*IOptionsSnapshot<AiVisitConfig> options,*/IAiVisitService aiVisitService, ILogger<AiController> logger,ICapPublisher capPublisher,IOrderRepository orderRepository,IQualityApplication qualityApplication, ISystemDicDataCacheManager sysDicDataCacheManager,IRepository<CallOutTemplate> callOutTemplateRepository, IRepository<CallOutTask> callOutTaskRepository,IRepository<CallOutTaskDetail> callOutTaskDetailRepository)
+        public AiController(ISystemSettingCacheManager systemSettingCacheManager,IRepository<AiOrderVisit> aiOrderVisitRepository,IRepository<AiOrderVisitDetail>  aiOrderVisitDetailRepository,IRepository<OrderVisit> orderVisitRepository,IRepository<OrderVisitDetail> orderVisitDetailRepository,IMapper mapper, /*IOptionsSnapshot<AiVisitConfig> options,*/IAiVisitService aiVisitService, ILogger<AiController> logger,ICapPublisher capPublisher,IOrderRepository orderRepository,IQualityApplication qualityApplication, ISystemDicDataCacheManager sysDicDataCacheManager,IRepository<CallOutTemplate> callOutTemplateRepository, IRepository<CallOutTask> callOutTaskRepository,IRepository<CallOutTaskDetail> callOutTaskDetailRepository,ISessionContext sessionContext)
         {
            _systemSettingCacheManager = systemSettingCacheManager;
             _aiOrderVisitRepository = aiOrderVisitRepository;
@@ -71,6 +72,7 @@ namespace Hotline.Api.Controllers
             _callOutTemplateRepository = callOutTemplateRepository;
             _callOutTaskRepository = callOutTaskRepository;
             _callOutTaskDetailRepository = callOutTaskDetailRepository;
+            _sessionContext = sessionContext;
         }
 
 
@@ -940,7 +942,7 @@ namespace Hotline.Api.Controllers
         {
             var items= await _orderVisitRepository.Queryable()
                 .Includes(x=>x.Order)
-                .Where(x => x.VisitState == Share.Enums.Order.EVisitState.WaitForVisit && x.IsCanAiVisit == true)
+                .Where(x => x.VisitState == Share.Enums.Order.EVisitState.WaitForVisit && x.IsCanAiVisit == true && x.EmployeeId == _sessionContext.RequiredUserId)
                 .WhereIF(dto.HotspotIds.Any(), x => dto.HotspotIds.Contains(x.Order.HotspotId)) //热点类型
                 .WhereIF(dto.AcceptTypes.Any(), x => dto.AcceptTypes.Contains(x.Order.AcceptTypeCode)) //受理类型
                 .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No.Contains(dto.No)) //工单编码

+ 35 - 3
src/Hotline.Api/Controllers/IPPbxController.cs

@@ -1,6 +1,7 @@
 using DotNetCore.CAP;
 using Hotline.Ai.Quality;
 using Hotline.Application.CallCenter.Calls;
+using Hotline.Application.Systems;
 using Hotline.Application.Tels;
 using Hotline.Caching.Interfaces;
 using Hotline.CallCenter.Calls;
@@ -59,7 +60,7 @@ namespace Hotline.Api.Controllers
         private readonly IRepository<QualityTemplate> _qualityTemplate;
         private readonly ISystemSettingCacheManager _systemSettingCacheManager;
         private readonly IRepository<TelActionRecord> _telActionRecordRepository;
-
+        private readonly ISystemMobilAreaApplication _systemMobilAreaApplication;
 
         public IPPbxController(ITrClient trClient, IMapper mapper, IUserDomainService userDomainService,
             ISessionContext sessionContext, IRepository<TrCallRecord> trCallRecordRepository,
@@ -70,7 +71,8 @@ namespace Hotline.Api.Controllers
             ITelRestRepository telRestRepository, IRepository<User> userRepository,
             ITelApplication telApplication, IRepository<Quality.Quality> qualiteyRepository,
             IAiQualityService aiQualityService, IRepository<QualityTemplate> qualityTemplate, 
-            ISystemSettingCacheManager systemSettingCacheManager,IRepository<TelActionRecord> telActionRecordRepository)
+            ISystemSettingCacheManager systemSettingCacheManager,IRepository<TelActionRecord> telActionRecordRepository,
+            ISystemMobilAreaApplication systemMobilAreaApplication)
         {
             _trClient = trClient;
             _mapper = mapper;
@@ -93,6 +95,7 @@ namespace Hotline.Api.Controllers
             _qualityTemplate = qualityTemplate;
             _systemSettingCacheManager = systemSettingCacheManager;
             _telActionRecordRepository = telActionRecordRepository;
+            _systemMobilAreaApplication = systemMobilAreaApplication;
         }
 
         #region 添添呼
@@ -439,17 +442,43 @@ namespace Hotline.Api.Controllers
             if (model.CallDirection == ECallDirection.In)
             {
                 model.TelNo = model.CDPN;
+                try
+                {
+                    var areaModel = await _systemMobilAreaApplication.GetPhoneCardArea(model.CPN, HttpContext.RequestAborted);
+                    if (areaModel != null)
+                    {
+                        model.MobileAreaName = areaModel.MobileAreaName;
+                        model.OFlag = areaModel.OFlag;
+                        model.OperatorName = areaModel.OperatorName;
+                    }
+                }
+                catch{}
             }
             else
             {
                 model.TelNo = model.CPN;
+                try
+                {
+                    var areaModel = await _systemMobilAreaApplication.GetPhoneCardArea(model.CDPN, HttpContext.RequestAborted);
+                    if (areaModel != null)
+                    {
+                        model.MobileAreaName = areaModel.MobileAreaName;
+                        model.OFlag = areaModel.OFlag;
+                        model.OperatorName = areaModel.OperatorName;
+                    }
+                }
+                catch{}
             }
             //判断是否是内部通话(目前分机都为4位)
             if (model.CPN.Length==4 && model.CDPN.Length ==4) //是内部通话
             {
                 model.TelNo = model.CDPN;//如果是内部通话  响应分机为被叫号码
             }
-
+            if (!string.IsNullOrEmpty(dto.phoneTypes))
+            {
+                model.PhoneTypes = (EPhoneTypes)Convert.ToInt32(dto.phoneTypes);
+            }
+            
 
             //获取关联 工单或是回访
             //var order = await _orderRepository.GetAsync(x => x.CallId == model.CallAccept, HttpContext.RequestAborted);//由CallAccept改为OtherAccept
@@ -590,6 +619,8 @@ namespace Hotline.Api.Controllers
                 .WhereIF(!string.IsNullOrEmpty(dto.Gateway), x => x.Gateway.Contains(dto.Gateway))
                 
                 .WhereIF(dto.IsAiAnswered == true,x=>string.IsNullOrEmpty(x.UserId) == true)
+
+                .WhereIF(dto.PhoneTypes!=null,x=>x.PhoneTypes == dto.PhoneTypes)
                 .OrderByDescending(x => x.CreatedTime)
                 .ToPagedListAsync(dto.PageIndex, dto.PageSize);
             return new PagedDto<TrCallDto>(total, _mapper.Map<IReadOnlyList<TrCallDto>>(items));
@@ -607,6 +638,7 @@ namespace Hotline.Api.Controllers
                 OnState = EnumExts.GetDescriptions<EOnState>(),
                 CallDirection = EnumExts.GetDescriptions<ECallDirection>(),
                 EndBy = EnumExts.GetDescriptions<EEndBy>(),
+                PhoneTypes = EnumExts.GetDescriptions<EPhoneTypes>()
             };
         }
 

+ 13 - 5
src/Hotline.Api/Controllers/OrderController.cs

@@ -3217,7 +3217,7 @@ public class OrderController : BaseController
             .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title!.Contains(dto.Title!))
             .WhereIF(dto is { StCreationTime: not null, EndCreationTime: not null }, x => x.CreationTime >= dto.StCreationTime && x.CreationTime <= dto.EndCreationTime)
             .WhereIF(dto is { StartTimeSt: not null, StartTimeEnd: not null }, x => x.StartTime >= dto.StartTimeSt && x.StartTime <= dto.StartTimeEnd)
-            .WhereIF(!string.IsNullOrEmpty(dto.StepName), x => x.Workflow.Steps.Any(s => s.Name == dto.StepName))
+            .WhereIF(!string.IsNullOrEmpty(dto.StepName), x => x.ActualHandleStepName == dto.StepName)
             .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), x => x.ActualHandleOrgName!.Contains(dto.ActualHandleOrgName!))
             .WhereIF(dto.Status.HasValue, x => x.Status == dto.Status)
             .WhereIF(!string.IsNullOrEmpty(dto.AcceptorName), x => x.AcceptorName!.Contains(dto.AcceptorName!))
@@ -3242,7 +3242,7 @@ public class OrderController : BaseController
         {
             OrderStatus = EnumExts.GetDescriptions<EOrderStatus>(),
             ExpiredStatus = EnumExts.GetDescriptions<EExpiredStatus>(),
-            StepNames = new string[] { "话务部", "派单组" }
+            StepNames = new string[] { "话务部", "派单组", "班长审批" }
         };
         return rsp;
     }
@@ -3743,7 +3743,9 @@ public class OrderController : BaseController
             //if (dto.AlterTime)
             //{
             var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
-            var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
+            var processType = dto.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter 
+                ? EProcessType.Zhiban 
+                : EProcessType.Jiaoban;
             //var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now,
             //	ETimeType.WorkDay,
             //	dto.TimeLimit.Value, order.AcceptTypeCode);
@@ -3950,7 +3952,10 @@ public class OrderController : BaseController
             //if (dto.AlterTime)
             //{
             var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
-            var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
+            //var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
+            var processType = special.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter
+                ? EProcessType.Zhiban
+                : EProcessType.Jiaoban;
             await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, ProcessType = processType })
                 .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
             var orderDto = _mapper.Map<OrderDto>(order);
@@ -4047,7 +4052,10 @@ public class OrderController : BaseController
                 //if (dto.AlterTime)
                 //{
                 var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
-                var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
+                //var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
+                var processType = special.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter
+                    ? EProcessType.Zhiban
+                    : EProcessType.Jiaoban;
                 await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, ProcessType = processType })
                     .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                 var orderDto = _mapper.Map<OrderDto>(order);

+ 12 - 7
src/Hotline.Api/Controllers/SchedulingController.cs

@@ -54,14 +54,19 @@ namespace Hotline.Api.Controllers
 			{
 				if (string.IsNullOrEmpty(dto.UserId))
 					throw UserFriendlyException.SameMessage("请带上用户信息");
-				
-				var model = _mapper.Map<SchedulingUser>(dto);
-				var sysUser = await _userRepository.Queryable().Includes(u => u.Organization).Where(x => x.Id == dto.UserId).FirstAsync(HttpContext.RequestAborted);
-				model.OrgId = sysUser.Organization.Id;
-				model.OrgIdName = sysUser.Organization.Name;
-				user.Add(model);
+				var schedulingUser = await _schedulingUserRepository.Queryable().Where(x => x.UserId == dto.UserId).AnyAsync();
+				if (!schedulingUser)
+				{
+					var model = _mapper.Map<SchedulingUser>(dto);
+					var sysUser = await _userRepository.Queryable().Includes(u => u.Organization).Where(x => x.Id == dto.UserId).FirstAsync(HttpContext.RequestAborted);
+					model.OrgId = sysUser.Organization.Id;
+					model.OrgIdName = sysUser.Organization.Name;
+					user.Add(model);
+				}
 			}
-			await _schedulingUserRepository.AddRangeAsync(user, HttpContext.RequestAborted);
+
+			if (user.Any())
+				await _schedulingUserRepository.AddRangeAsync(user, HttpContext.RequestAborted);
 		}
 
 		/// <summary>

+ 0 - 94
src/Hotline.Api/Controllers/SysController.cs

@@ -590,99 +590,5 @@ namespace Hotline.Api.Controllers
 
         #endregion
 
-        /// <summary>
-        ///  获取电话号码归属地和手机号码卡类型
-        /// </summary>
-        /// <param name="PhoneNum"></param>
-        /// <returns></returns>
-        [HttpGet("getphonecardarea")]
-        public async Task<SystemMobilAreaDto> GetPhoneCardArea(string PhoneNum)
-        {
-            SystemMobilAreaDto areaDto = new SystemMobilAreaDto();
-            if (true == string.IsNullOrEmpty(PhoneNum) || PhoneNum.Length < 6)
-            {
-                return areaDto;
-            }
-
-            // 验证电话号码是否是手机号码
-            bool bCheckMobile = e_VerificationMobile(PhoneNum);
-            // 电话归属编码
-            string strPhoneCode = "";
-            if (bCheckMobile)
-            {
-                // 手机号码第一位是否是0
-                if (PhoneNum.Substring(0, 1) == "0")
-                    strPhoneCode = PhoneNum.Substring(1, 7);
-                else
-                    strPhoneCode = PhoneNum.Substring(0, 7);
-
-                var data = await _systemMobilAreaRepository.GetAsync(p => p.MobileCode.Trim() == strPhoneCode, HttpContext.RequestAborted);
-                if (data != null)
-                {
-                    areaDto.OFlag = data.OFlag == "1" ? "电信" : data.OFlag == "2" ? "移动" : "联通";
-                    areaDto.MobileAreaName = data.MobileAreaName;
-                    areaDto.OperatorName = data.OperatorName;
-                }
-            }
-            else
-            {
-                // 验证电话号码是否是座机号码
-                bCheckMobile = e_VerificationTel(PhoneNum);
-                if (true == bCheckMobile)
-                {
-                    strPhoneCode = PhoneNum.Substring(0, 3);
-
-                    SystemMobilArea data = await _systemMobilAreaRepository.GetAsync(p => p.TelCode.Trim() == strPhoneCode, HttpContext.RequestAborted);
-                    if (data == null)
-                    {
-                        strPhoneCode = PhoneNum.Substring(0, 4);
-                        data = await _systemMobilAreaRepository.GetAsync(p => p.TelCode.Trim() == strPhoneCode, HttpContext.RequestAborted);
-                    }
-                    
-                    if (data != null)
-                    {
-                        areaDto.MobileAreaName = data.MobileAreaName;
-                    }
-                }
-            }
-            return areaDto;
-        }
-
-        #region 验证手机号码
-        /// <summary>
-        /// 验证手机号码
-        /// </summary>
-        /// <param name="strPhoneNum">电话号码</param>
-        /// <returns></returns>
-        public static bool e_VerificationMobile(string strPhoneNum)
-        {
-            // 手机号码正则表达式
-            string strVer = @"^(0)?(13\d|15\d|18\d|17\d|14\d|19\d|16\d)\d{5}(\d{3}|\*{3})$";
-            Regex regex = new Regex(strVer);
-            if (true == regex.IsMatch(strPhoneNum))
-                return true;
-            else
-                return false;
-        }
-        #endregion
-
-        #region 验证座机号码
-        /// <summary>
-        /// 验证座机号码
-        /// </summary>
-        /// <param name="strPhoneNum">电话号码</param>
-        /// <returns></returns>
-        public static bool e_VerificationTel(string strPhoneNum)
-        {
-            // 座机号码正则表达式
-            string strVer = @"^((0\d{2,3})(-)?)?(\d{7,8})(-(\d{3,}))?$";
-            Regex regex = new Regex(strVer);
-            if (true == regex.IsMatch(strPhoneNum))
-                return true;
-            else
-                return false;
-        }
-        #endregion
-
     }
 }

+ 4 - 4
src/Hotline.Api/config/appsettings.Development.json

@@ -16,10 +16,10 @@
     }
   },
   "ConnectionStrings": {
-    "Hotline": "PORT=5432;DATABASE=hotline_dev;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;",
-    "Redis": "110.188.24.182:50179",
-    "MongoDB": "mongodb://192.168.100.121:27017",
-    "Wex": "server=222.212.82.225;Port=4509;Database=fs_kft;Uid=root;Pwd=Wex@12345;"
+    "Hotline": "PORT=5432;DATABASE=hotline;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;",
+    //"Redis": "110.188.24.182:50179",
+    //"MongoDB": "mongodb://192.168.100.121:27017",
+    //"Wex": "server=222.212.82.225;Port=4509;Database=fs_kft;Uid=root;Pwd=Wex@12345;"
   },
   "Cache": {
     "Host": "110.188.24.182",

+ 4 - 4
src/Hotline.Api/config/appsettings.json

@@ -16,10 +16,10 @@
     }
   },
   "ConnectionStrings": {
-    "Hotline": "PORT=5432;DATABASE=hotline_dev;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;",
-    "Redis": "110.188.24.182:50179,password=fengwo22@@",
-    "MongoDB": "mongodb://192.168.100.121:27017",
-    "Wex": "server=222.212.82.225;Port=4509;Database=fs_kft;Uid=root;Pwd=Wex@12345;"
+    "Hotline": "PORT=5432;DATABASE=hotline;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;",
+    //"Redis": "110.188.24.182:50179,password=fengwo22@@",
+    //"MongoDB": "mongodb://192.168.100.121:27017",
+    //"Wex": "server=222.212.82.225;Port=4509;Database=fs_kft;Uid=root;Pwd=Wex@12345;"
   },
   "Cache": {
     "Host": "110.188.24.182",

+ 24 - 14
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -193,6 +193,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         _mapper.Map(dto, startTrace);
         await _workflowTraceRepository.AddAsync(startTrace, cancellationToken);
         workflow.Traces.Add(startTrace);
+        startStep.WorkflowTrace = startTrace;
 
         //更新受理人信息
         workflow.UpdateAcceptor(
@@ -282,8 +283,10 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         //    .Includes(x => x.Organization)
         //    .FirstAsync(x => x.Id == _sessionContext.RequiredUserId, cancellationToken);
         return await _workflowDomainService.PreviousAsync(workflow, dto,
-            _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles,
-            _sessionContext, cancellationToken);
+            _sessionContext.RequiredUserId, _sessionContext.UserName,
+            _sessionContext.RequiredOrgId, _sessionContext.OrgName,
+            _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
+            _sessionContext.OrgIsCenter, _sessionContext.Roles, cancellationToken);
     }
 
     /// <summary>
@@ -294,8 +297,14 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     {
         var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true,
             withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
+        var user = await _userRepository.Queryable()
+            .Includes(x => x.Organization)
+            .FirstAsync(x => x.Id == applicantId, cancellationToken);
         return await _workflowDomainService.PreviousAsync(workflow, dto,
-            applicantId, applicantOrgId, applicantRoleIds, _sessionContext, cancellationToken);
+            applicantId, user.Name,
+            applicantOrgId, user.Organization.Name,
+            user.Organization.AreaCode, user.Organization.AreaName,
+            user.Organization.IsCenter, applicantRoleIds, cancellationToken);
     }
 
     /// <summary>
@@ -563,14 +572,14 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         var currentStep = workflow.Steps.FirstOrDefault(d => d.Id == workflow.ActualHandleStepId);
         if (currentStep is null)
             throw new UserFriendlyException("无效当前节点编号");
-        var quer = workflow.Steps.Where(d =>
+        var query = workflow.Steps.Where(d =>
             d.StepType != EStepType.End &&
             d.IsOrigin);
         if (!isEnd)
         {
-            quer = quer.Where(d => d.Id != currentStep.Id);
+            query = query.Where(d => d.Id != currentStep.Id);
         }
-        var originSteps = quer.ToList();
+        var originSteps = query.ToList();
         var stepCodes = originSteps.Select(d => d.Code).ToList();
         var stepDefines = workflow.WorkflowDefinition.FindStepDefines(stepCodes);
 
@@ -606,14 +615,15 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
 
             stepOption.InputRealHandler = false;
 
-            ////已归档工单,撤回至中心看作otc,撤回至部门看作cto
-            //stepOption.FlowDirection = isWorkflowFiled
-            //    ? stepDefine.BusinessType is EBusinessType.Center or EBusinessType.Send
-            //        ? EFlowDirection.OrgToCenter
-            //        : stepDefine.BusinessType is EBusinessType.Department
-            //            ? EFlowDirection.CenterToOrg
-            //            : null
-            //    : CheckFlowDirection(currentStep.BusinessType, stepDefine.BusinessType);
+            //已归档工单,撤回至中心看作otc,撤回至部门看作cto
+            stepOption.FlowDirection = isWorkflowFiled
+                ? stepDefine.BusinessType is EBusinessType.Center or EBusinessType.Send
+                    ? EFlowDirection.FiledToCenter
+                    : stepDefine.BusinessType is EBusinessType.Department
+                        ? EFlowDirection.FiledToOrg
+                        : null
+                //: CheckFlowDirection(currentStep.BusinessType, stepDefine.BusinessType);
+                : _workflowDomainService.GetFlowDirection(currentStep.BusinessType, stepDefine.BusinessType);
 
             //需求已调整为特提必重算期满时间
 

+ 3 - 3
src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs

@@ -161,7 +161,7 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                 order.FileUserName = notification.Trace.HandlerName;
                 order.FileUserOrgId = notification.Trace.HandlerOrgId;
                 order.FileUserOrgName = notification.Trace.HandlerOrgName;
-                order.FileOpinion = notification.Trace.Opinion;
+                order.FileOpinion = notification.Dto.Opinion;
 
                 //记录冗余归档数据
                 if (notification.Workflow.Steps.Any(x => x.BusinessType == Share.Enums.FlowEngine.EBusinessType.Send))
@@ -178,7 +178,7 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                 }
 
                 //是否已解决
-                order.IsResolved = notification.External == null ? false : notification.External.IsResolved;
+                order.IsResolved = notification.Dto.External == null ? false : notification.Dto.External.IsResolved;
 
                 await _orderRepository.UpdateAsync(order, cancellationToken);
                 //var callRecord = await _trCallRecordRepository.GetAsync(p => p.CallAccept == order.CallId, cancellationToken); //由CallAccept改为OtherAccept
@@ -193,7 +193,7 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                     orderFlowDto.TrCallRecordDto = _mapper.Map<TrCallDto>(callRecord);
                 }
                 //这里需要判断是否是警情退回
-                orderFlowDto.IsNonPoliceReturn = notification.External == null ? false : notification.External.IsPoliceReturn;
+                orderFlowDto.IsNonPoliceReturn = notification.Dto.External == null ? false : notification.Dto.External.IsPoliceReturn;
                 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFiled, orderFlowDto, cancellationToken: cancellationToken);
                 //写入质检  针对受理之后直接结束的工单
                 await _qualityApplication.AddQualityAsync(EQualitySource.Accepted, order.Id, cancellationToken);

+ 14 - 0
src/Hotline.Application/Systems/ISystemMobilAreaApplication.cs

@@ -0,0 +1,14 @@
+using Hotline.Share.Dtos.Settings;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.Systems
+{
+    public interface ISystemMobilAreaApplication
+    {
+        Task<SystemMobilAreaDto> GetPhoneCardArea(string PhoneNum,CancellationToken cancellationToken);
+    }
+}

+ 113 - 0
src/Hotline.Application/Systems/SystemMobilAreaApplication.cs

@@ -0,0 +1,113 @@
+using Hotline.Settings;
+using Hotline.Share.Dtos.Settings;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.Systems
+{
+    public class SystemMobilAreaApplication : ISystemMobilAreaApplication, IScopeDependency
+    {
+        private readonly IRepository<SystemMobilArea> _systemMobilAreaRepository;
+
+        public SystemMobilAreaApplication(IRepository<SystemMobilArea> systemMobilAreaRepository)
+        {
+            _systemMobilAreaRepository = systemMobilAreaRepository;
+        }
+
+        public async Task<SystemMobilAreaDto> GetPhoneCardArea(string PhoneNum, CancellationToken cancellationToken)
+        {
+            SystemMobilAreaDto areaDto = new SystemMobilAreaDto();
+            if (true == string.IsNullOrEmpty(PhoneNum) || PhoneNum.Length < 6)
+            {
+                return areaDto;
+            }
+
+            // 验证电话号码是否是手机号码
+            bool bCheckMobile = e_VerificationMobile(PhoneNum);
+            // 电话归属编码
+            string strPhoneCode = "";
+            if (bCheckMobile)
+            {
+                // 手机号码第一位是否是0
+                if (PhoneNum.Substring(0, 1) == "0")
+                    strPhoneCode = PhoneNum.Substring(1, 7);
+                else
+                    strPhoneCode = PhoneNum.Substring(0, 7);
+
+                var data = await _systemMobilAreaRepository.GetAsync(p => p.MobileCode.Trim() == strPhoneCode, cancellationToken);
+                if (data != null)
+                {
+                    areaDto.OFlag = data.OFlag == "1" ? "电信" : data.OFlag == "2" ? "移动" : "联通";
+                    areaDto.MobileAreaName = data.MobileAreaName;
+                    areaDto.OperatorName = data.OperatorName;
+                }
+            }
+            else
+            {
+                // 验证电话号码是否是座机号码
+                bCheckMobile = e_VerificationTel(PhoneNum);
+                if (true == bCheckMobile)
+                {
+                    strPhoneCode = PhoneNum.Substring(0, 3);
+
+                    var data = await _systemMobilAreaRepository.GetAsync(p => p.TelCode.Trim() == strPhoneCode, cancellationToken);
+                    if (data == null)
+                    {
+                        strPhoneCode = PhoneNum.Substring(0, 4);
+                        data = await _systemMobilAreaRepository.GetAsync(p => p.TelCode.Trim() == strPhoneCode, cancellationToken);
+                    }
+
+                    if (data != null)
+                    {
+                        areaDto.MobileAreaName = data.MobileAreaName;
+                    }
+                }
+            }
+            return areaDto;
+        }
+
+
+        #region 验证手机号码
+        /// <summary>
+        /// 验证手机号码
+        /// </summary>
+        /// <param name="strPhoneNum">电话号码</param>
+        /// <returns></returns>
+        public static bool e_VerificationMobile(string strPhoneNum)
+        {
+            // 手机号码正则表达式
+            string strVer = @"^(0)?(13\d|15\d|18\d|17\d|14\d|19\d|16\d)\d{5}(\d{3}|\*{3})$";
+            Regex regex = new Regex(strVer);
+            if (true == regex.IsMatch(strPhoneNum))
+                return true;
+            else
+                return false;
+        }
+        #endregion
+
+        #region 验证座机号码
+        /// <summary>
+        /// 验证座机号码
+        /// </summary>
+        /// <param name="strPhoneNum">电话号码</param>
+        /// <returns></returns>
+        public static bool e_VerificationTel(string strPhoneNum)
+        {
+            // 座机号码正则表达式
+            string strVer = @"^((0\d{2,3})(-)?)?(\d{7,8})(-(\d{3,}))?$";
+            Regex regex = new Regex(strVer);
+            if (true == regex.IsMatch(strPhoneNum))
+                return true;
+            else
+                return false;
+        }
+        #endregion
+    }
+}

+ 3 - 3
src/Hotline.Share/Dtos/Settings/SystemMobilAreaDto.cs

@@ -5,16 +5,16 @@
         /// <summary>
         /// 归属地
         /// </summary>
-        public string MobileAreaName { get; set; }
+        public string? MobileAreaName { get; set; }
 
         /// <summary>
         /// 运营商
         /// </summary>
-        public string OFlag { get; set; }
+        public string? OFlag { get; set; }
 
         /// <summary>
         /// 卡类型
         /// </summary>
-        public string OperatorName { get; set; }
+        public string? OperatorName { get; set; }
     }
 }

+ 22 - 0
src/Hotline.Share/Dtos/TrCallCenter/TrTelDao.cs

@@ -369,6 +369,8 @@ namespace Hotline.Share.Dtos.TrCallCenter
         /// IVR按键对应动作,需解码
         /// </summary>
         public string? dtmf_type { get; set; }
+
+        public string? phoneTypes { get; set; }
     }
 
 
@@ -542,6 +544,11 @@ namespace Hotline.Share.Dtos.TrCallCenter
         /// </summary>
         public bool IsAiAnswered { get; set; }
 
+        /// <summary>
+        /// 电话类型
+        /// </summary>
+        public EPhoneTypes? PhoneTypes { get; set; }
+
     }
 
 
@@ -715,6 +722,21 @@ namespace Hotline.Share.Dtos.TrCallCenter
         /// </summary>
         public OrderDto Order { get; set; }
 
+        /// <summary>
+        /// 归属地
+        /// </summary>
+        public string? MobileAreaName { get; set; }
+
+        /// <summary>
+        /// 运营商
+        /// </summary>
+        public string? OFlag { get; set; }
+
+        /// <summary>
+        /// 卡类型
+        /// </summary>
+        public string? OperatorName { get; set; }
+
         #endregion
     }
 

+ 27 - 0
src/Hotline.Share/Enums/CallCenter/EPhoneTypes.cs

@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Enums.CallCenter
+{
+    public enum EPhoneTypes
+    {
+        [Description("普通")]
+        Ordinary = 0,
+
+        [Description("呼入VIP")]
+        CallInVip = 1,
+
+        [Description("呼入黑名单")]
+        CallInBlackList = 2,
+
+        [Description("呼出黑名单")]
+        CallOutBlackList = 3,
+
+        [Description("呼入呼出黑名单")]
+        CallIntAndOutBlackList =4,
+    }
+}

+ 10 - 0
src/Hotline.Share/Enums/FlowEngine/EFlowDirection.cs

@@ -13,4 +13,14 @@ public enum EFlowDirection
     CenterToFile = 4,
 
     OrgToFile = 5,
+
+    /// <summary>
+    /// 已归档回到中心
+    /// </summary>
+    FiledToCenter = 6,
+
+    /// <summary>
+    /// 已归档回到部门
+    /// </summary>
+    FiledToOrg = 7
 }

+ 19 - 0
src/Hotline/CallCenter/Calls/TrCallRecord.cs

@@ -168,6 +168,25 @@ namespace Hotline.CallCenter.Calls
         [Navigate(NavigateType.OneToOne, nameof(ExternalId))]
         public Order? Order { get; set; }
 
+        /// <summary>
+        /// 呼入号码类型
+        /// </summary>
+        public EPhoneTypes? PhoneTypes { get; set; }
+
+        /// <summary>
+        /// 归属地
+        /// </summary>
+        public string? MobileAreaName { get; set; }
+
+        /// <summary>
+        /// 运营商
+        /// </summary>
+        public string? OFlag { get; set; }
+
+        /// <summary>
+        /// 卡类型
+        /// </summary>
+        public string? OperatorName { get; set; }
 
         #endregion
     }

+ 1 - 1
src/Hotline/FlowEngine/Notifications/WorkflowNotify.cs

@@ -36,7 +36,7 @@ public record RedoNotify(Workflow Workflow, RecallDto Dto, bool IsOrgToCenter) :
 ///// </summary>
 //public record RejectNotify(Workflow Workflow, BasicWorkflowDto Dto) : INotification;
 
-public record EndWorkflowNotify(Workflow Workflow, WorkflowTrace Trace, External External) : INotification;
+public record EndWorkflowNotify(Workflow Workflow, WorkflowTrace Trace, BasicWorkflowDto Dto) : INotification;
 
 public record TerminalWorkflowNotify(Workflow Workflow) : INotification;
 

+ 5 - 2
src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs

@@ -57,8 +57,11 @@ namespace Hotline.FlowEngine.Workflows
         /// </summary>
         /// <returns></returns>
         Task<EFlowDirection> PreviousAsync(Workflow workflow, PreviousWorkflowDto dto,
-            string applicantId, string applicantOrgId, string[] applicantRoleIds,
-            ISessionContext current, CancellationToken cancellationToken);
+            string applicantId, string applicantName,
+            string applicantOrgId, string applicantOrgName,
+            string applicantOrgAreaCode, string applicantOrgAreaName,
+            bool applicantIsCenter, string[] applicantRoleIds,
+            CancellationToken cancellationToken);
 
         /// <summary>
         /// 撤回(返回到之前任意节点)

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

@@ -102,6 +102,8 @@ namespace Hotline.FlowEngine.Workflows
 
             if (firstStepDefine.StepType is EStepType.End)
             {
+                await _mediator.Publish(new StartWorkflowNotify(workflow, dto, flowAssignInfo, startStep.WorkflowTrace), cancellationToken);
+
                 //firstStep是否为end,t: 实际办理节点为startStep, 并且handlerId赋值 f: 实际办理节点为firstStep, handlerId未赋值
                 workflow.UpdateActualStepWhenHandle(startStep,
                     current.RequiredUserId, current.UserName,
@@ -514,8 +516,11 @@ namespace Hotline.FlowEngine.Workflows
         /// </summary>
         /// <returns></returns>
         public async Task<EFlowDirection> PreviousAsync(Workflow workflow, PreviousWorkflowDto dto,
-            string applicantId, string applicantOrgId, string[] applicantRoleIds,
-            ISessionContext current, CancellationToken cancellationToken)
+            string applicantId, string applicantName,
+            string applicantOrgId, string applicantOrgName,
+            string applicantOrgAreaCode, string applicantOrgAreaName,
+            bool applicantIsCenter,
+            string[] applicantRoleIds, CancellationToken cancellationToken)
         {
             //ValidatePermission(workflow, operater.OrgId, operater.Id);
 
@@ -548,10 +553,15 @@ namespace Hotline.FlowEngine.Workflows
                 //updateSteps.Add(countersignStartStep);
 
                 //结束会签
+                //currentCountersign.End(currentStep.Id, currentStep.Code, currentStep.BusinessType,
+                //    current.RequiredUserId, current.UserName,
+                //    current.RequiredOrgId, current.OrgName,
+                //    current.OrgAreaCode, current.OrgAreaName);
                 currentCountersign.End(currentStep.Id, currentStep.Code, currentStep.BusinessType,
-                    current.RequiredUserId, current.UserName,
-                    current.RequiredOrgId, current.OrgName,
-                    current.OrgAreaCode, current.OrgAreaName);
+                    applicantId, applicantName,
+                    applicantOrgId, applicantOrgName,
+                    applicantOrgAreaCode, applicantOrgAreaName);
+
                 await _workflowCountersignRepository.UpdateAsync(currentCountersign, cancellationToken);
 
                 //update workflow cs status
@@ -560,7 +570,11 @@ namespace Hotline.FlowEngine.Workflows
             }
 
             //update trace
-            var trace = await PreviousTraceAsync(workflow.Id, dto, currentStep, current, cancellationToken);
+            var trace = await PreviousTraceAsync(workflow.Id, dto, currentStep,
+                applicantId, applicantName,
+                applicantOrgId, applicantOrgName,
+                applicantOrgAreaCode, applicantOrgAreaName,
+                applicantIsCenter, cancellationToken);
 
             //复制上一个节点为待接办
             var newPrevStep = await DuplicateStepWithTraceAsync(workflow, prevStep, EWorkflowTraceType.Previous, cancellationToken);
@@ -1331,7 +1345,7 @@ namespace Hotline.FlowEngine.Workflows
 
             await _workflowRepository.UpdateAsync(workflow, cancellationToken);
 
-            await _mediator.Publish(new EndWorkflowNotify(workflow, endTrace, dto.External), cancellationToken);
+            await _mediator.Publish(new EndWorkflowNotify(workflow, endTrace, dto), cancellationToken);
 
             return endTrace;
         }
@@ -1884,12 +1898,23 @@ namespace Hotline.FlowEngine.Workflows
             }
         }
 
-        private async Task<WorkflowTrace> PreviousTraceAsync(string workflowId, PreviousWorkflowDto dto,
-            WorkflowStep step, ISessionContext current, CancellationToken cancellationToken)
+        private async Task<WorkflowTrace> PreviousTraceAsync(string workflowId,
+            PreviousWorkflowDto dto, WorkflowStep step,
+            string applicantId, string applicantName,
+            string applicantOrgId, string applicantOrgName,
+            string applicantOrgAreaCode, string applicantOrgAreaName,
+            bool applicantIsCenter, CancellationToken cancellationToken)
         {
             var trace = await GetWorkflowTraceAsync(workflowId, step.Id, cancellationToken);
             _mapper.Map(dto, trace);
-            HandleTrace(trace, dto.Opinion, current);
+            
+            //HandleTrace(trace, dto.Opinion, current);
+            
+            trace.Handle(applicantId, applicantName,
+                applicantOrgId, applicantOrgName,
+                applicantOrgAreaCode, applicantOrgAreaName,
+                applicantIsCenter, dto.Opinion);
+
             await _workflowTraceRepository.UpdateAsync(trace, cancellationToken);
             return trace;
         }

+ 4 - 1
src/Hotline/Orders/OrderDomainService.cs

@@ -13,6 +13,7 @@ using Hotline.CallCenter.Calls;
 using Hotline.File;
 using Hotline.FlowEngine.Workflows;
 using Hotline.Schedulings;
+using Hotline.SeedData;
 using Hotline.Users;
 using Hotline.Share.Dtos;
 using Hotline.Settings.Hotspots;
@@ -197,7 +198,9 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
                 Value = "待派单池",
                 UserId = OrderDefaults.SourceChannel.SendPoolId,
                 Username = "待派单池",
-            };
+                OrgId = OrgSeedData.CenterId,
+                OrgName = "市民热线服务中心"
+			};
         scheduling.SendOrderNum++;
         await _schedulingRepository.UpdateAsync(scheduling, cancellationToken);
         var user = scheduling.SchedulingUser;

+ 1 - 1
src/XF.EasyCaching/StartupExtensions.cs

@@ -43,7 +43,7 @@ namespace XF.EasyCaching
                     .WithRedisBus(busConf =>
                     {
                         busConf.Endpoints.Add(new ServerEndPoint(options.Host, options.Port));
-
+                        busConf.Password = options.Password;
                         // do not forget to set the SerializerName for the bus here !!
                         busConf.SerializerName = "xjson";
                     });