Parcourir la source

Merge branch 'release/yibin' of http://110.188.24.182:10023/Fengwo/hotline into release/yibin

田爽 il y a 10 mois
Parent
commit
0b5f2ae242

+ 31 - 2
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,10 +442,32 @@ 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) //是内部通话
@@ -453,6 +478,7 @@ namespace Hotline.Api.Controllers
             {
                 model.PhoneTypes = (EPhoneTypes)Convert.ToInt32(dto.phoneTypes);
             }
+            
 
             //获取关联 工单或是回访
             //var order = await _orderRepository.GetAsync(x => x.CallId == model.CallAccept, HttpContext.RequestAborted);//由CallAccept改为OtherAccept
@@ -593,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));
@@ -610,6 +638,7 @@ namespace Hotline.Api.Controllers
                 OnState = EnumExts.GetDescriptions<EOnState>(),
                 CallDirection = EnumExts.GetDescriptions<ECallDirection>(),
                 EndBy = EnumExts.GetDescriptions<EEndBy>(),
+                PhoneTypes = EnumExts.GetDescriptions<EPhoneTypes>()
             };
         }
 

+ 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
-
     }
 }

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

@@ -24,7 +24,7 @@
   "Cache": {
     "Host": "110.188.24.182",
     "Port": 50179,
-    "Password": "fengwo!$!$",
+    "Password": "fengwo123!$!$",
     "Database": 3 //release:3, dev:5
   },
   "Swagger": true,

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

@@ -24,7 +24,7 @@
   "Cache": {
     "Host": "110.188.24.182",
     "Port": 50179,
-    "Password": "fengwo!$!$",
+    "Password": "fengwo123!$!$",
     "Database": 3
   },
   "Swagger": true,

+ 11 - 3
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -283,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>
@@ -295,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>

+ 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; }
     }
 }

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

@@ -544,6 +544,11 @@ namespace Hotline.Share.Dtos.TrCallCenter
         /// </summary>
         public bool IsAiAnswered { get; set; }
 
+        /// <summary>
+        /// 电话类型
+        /// </summary>
+        public EPhoneTypes? PhoneTypes { get; set; }
+
     }
 
 
@@ -717,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
     }
 

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

@@ -173,6 +173,21 @@ namespace Hotline.CallCenter.Calls
         /// </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>
         /// 撤回(返回到之前任意节点)

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

@@ -13,6 +13,7 @@ using MapsterMapper;
 using MediatR;
 using Microsoft.Extensions.Logging;
 using SqlSugar;
+using System.Diagnostics;
 using XF.Domain.Authentications;
 using XF.Domain.Dependency;
 using XF.Domain.Entities;
@@ -516,8 +517,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);
 
@@ -550,10 +554,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
@@ -562,7 +571,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);
@@ -573,6 +586,10 @@ namespace Hotline.FlowEngine.Workflows
             //    .Include(d => d.StepHandlers)
             //    .ExecuteCommandAsync();
 
+            var stepIds = removeSteps.Select(d => d.Id).ToList();
+            var updateTraces = workflow.Traces.Where(d => stepIds.Contains(d.StepId)).ToList();
+            await UpdateTracesStateAsync(updateTraces, EWorkflowTraceState.StepRemoveByPrevious, cancellationToken);
+
             if (workflow.Status is EWorkflowStatus.Completed)
                 workflow.SetStatusRunnable();
 
@@ -592,6 +609,16 @@ namespace Hotline.FlowEngine.Workflows
             return GetFlowDirection(currentStep.BusinessType, prevStep.BusinessType);
         }
 
+        private async Task UpdateTracesStateAsync(List<WorkflowTrace> traces, EWorkflowTraceState traceState, CancellationToken cancellationToken)
+        {
+            foreach (var trace in traces)
+            {
+                trace.TraceState = traceState;
+            }
+
+            await _workflowTraceRepository.UpdateRangeAsync(traces, cancellationToken);
+        }
+
         /// <summary>
         /// 查询退回节点信息
         /// </summary>
@@ -1333,7 +1360,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;
         }
@@ -1886,12 +1913,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;
         }
@@ -2002,6 +2040,11 @@ namespace Hotline.FlowEngine.Workflows
                 //    .Include(d => d.StepHandlers)
                 //    .ExecuteCommandAsync();
                 workflow.Steps.RemoveAll(d => removeSteps.Contains(d));
+
+                //更新快照对应节点状态
+                var stepIds = removeSteps.Select(d => d.Id).ToList();
+                var updateTraces = workflow.Traces.Where(d => stepIds.Contains(d.StepId)).ToList();
+                await UpdateTracesStateAsync(updateTraces, EWorkflowTraceState.StepRemoveByRecall, cancellationToken);
             }
 
             workflow.EndCountersign();

+ 27 - 0
src/Hotline/FlowEngine/Workflows/WorkflowTrace.cs

@@ -30,10 +30,37 @@ public class WorkflowTrace : StepBasicEntity
     [SugarColumn(DefaultValue = "0")]
     public int SendHandleTimes { get; set; }
 
+    /// <summary>
+    /// 快照对应节点状态
+    /// </summary>
+    [SugarColumn(DefaultValue = "0")]
+    public EWorkflowTraceState TraceState { get; set; }
+
     /// <summary>
     /// 会签流转记录
     /// </summary>
     [SugarColumn(IsIgnore = true)]
     public List<WorkflowTrace> Traces { get; set; }
 
+}
+
+/// <summary>
+/// 快照对应节点状态
+/// </summary>
+public enum EWorkflowTraceState
+{
+    /// <summary>
+    /// 正常办理
+    /// </summary>
+    Normal = 0,
+
+    /// <summary>
+    /// 对应节点因退回被删除
+    /// </summary>
+    StepRemoveByPrevious = 10,
+
+    /// <summary>
+    /// 对应节点因撤回被删除
+    /// </summary>
+    StepRemoveByRecall = 20,
 }