Browse Source

合并代码

tangjiang 6 months ago
parent
commit
25997cff54
33 changed files with 751 additions and 280 deletions
  1. 2 0
      src/Hotline.Api/Controllers/ArticleController.cs
  2. 3 2
      src/Hotline.Api/Controllers/CallController.cs
  3. 12 0
      src/Hotline.Api/Controllers/CommonPController.cs
  4. 5 7
      src/Hotline.Api/Controllers/HotSpotController.cs
  5. 25 19
      src/Hotline.Api/Controllers/IPPbxController.cs
  6. 184 126
      src/Hotline.Api/Controllers/OrderController.cs
  7. 6 5
      src/Hotline.Api/Controllers/WebPortalController.cs
  8. 0 2
      src/Hotline.Api/Controllers/WorkflowController.cs
  9. 14 2
      src/Hotline.Application/CallCenter/DefaultCallApplication.cs
  10. 8 0
      src/Hotline.Application/CallCenter/ICallApplication.cs
  11. 26 8
      src/Hotline.Application/CallCenter/TianRunCallApplication.cs
  12. 6 0
      src/Hotline.Application/FlowEngine/IWorkflowApplication.cs
  13. 70 4
      src/Hotline.Application/FlowEngine/WorkflowApplication.cs
  14. 4 0
      src/Hotline.Application/Mappers/MapperConfigs.cs
  15. 5 3
      src/Hotline.Application/Mappers/OrderMapperConfigs.cs
  16. 46 36
      src/Hotline.Application/Subscribers/DatasharingSubscriber.cs
  17. 1 0
      src/Hotline.Repository.SqlSugar/System/EventCategoryRepository.cs
  18. 10 0
      src/Hotline.Share/Dtos/Article/BulletinDto.cs
  19. 10 6
      src/Hotline.Share/Dtos/FlowEngine/PreviousWorkflowDto.cs
  20. 10 0
      src/Hotline.Share/Dtos/Order/ExternalcitizensDto.cs
  21. 50 19
      src/Hotline.Share/Dtos/Order/OrderDto.cs
  22. 5 0
      src/Hotline.Share/Dtos/WebPortal/ArticleDetailsDto.cs
  23. 2 0
      src/Hotline.Share/Dtos/WebPortal/GetOrderCodePwd.cs
  24. 6 0
      src/Hotline/Article/Bulletin.cs
  25. 6 0
      src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs
  26. 1 0
      src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs
  27. 63 36
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  28. 2 2
      src/Hotline/FlowEngine/Workflows/WorkflowTrace.cs
  29. 6 0
      src/Hotline/Orders/Order.cs
  30. 36 0
      src/Hotline/Permissions/EPermission.cs
  31. 5 0
      src/Hotline/Settings/SysDicTypeConsts.cs
  32. 120 1
      src/Hotline/dataview.md
  33. 2 2
      src/XF.Domain/Entities/IWorkflow.cs

+ 2 - 0
src/Hotline.Api/Controllers/ArticleController.cs

@@ -553,6 +553,7 @@ namespace Hotline.Api.Controllers
             bulletin.BulletinTypeName = dto.BulletinTypeName;
             bulletin.LoseEfficacyTime = dto.LoseEfficacyTime;
             bulletin.PushRanges = dto.PushRanges;
+            bulletin.DisplayLocation = dto.DisplayLocation;
             bulletin.SourceOrgId = dto.SourceOrgId;
             bulletin.SourceOrgName = dto.SourceOrgName;
             await _bulletinRepository.UpdateAsync(bulletin, HttpContext.RequestAborted);
@@ -646,6 +647,7 @@ namespace Hotline.Api.Controllers
             var rsp = new
             {
                 BulletinType = _systemDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.BulletinType),
+                BulletinDisplayLocation = _systemDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.BulletinDisplayLocation),
                 PushRanges = _systemDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.BulletinPushRange),
                 OrgsOptions = await _organizeRepository.GetOrgJson(),
             };

+ 3 - 2
src/Hotline.Api/Controllers/CallController.cs

@@ -105,10 +105,11 @@ namespace Hotline.Api.Controllers
         /// <returns></returns>
         /// <exception cref="NotImplementedException"></exception>
         [HttpGet("{callId}")]
-        public Task<CallNative?> GetCall(string callId)
+        public Task<List<CallNative>> GetCall(string callId)
         {
+            //为兼容天润通话记录返回集合
             if (string.IsNullOrEmpty(callId)) return default;
-            return _callApplication.GetCallAsync(callId, HttpContext.RequestAborted);
+            return _callApplication.GetCallListAsync(callId, HttpContext.RequestAborted);
         }
 
         /// <summary>

+ 12 - 0
src/Hotline.Api/Controllers/CommonPController.cs

@@ -317,6 +317,12 @@ namespace Hotline.Api.Controllers
 				//部门即将超期
 				var nearlyExpiredDataList = await _orderRepository.Queryable(canView: !IsCenter)
 					.Includes(d => d.OrderDelays)
+					.Where(d => SqlFunc.Subqueryable<WorkflowStep>()
+						.Where(step => step.ExternalId == d.Id &&
+						               ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
+						                (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
+						                (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId))))
+						.Any())
 					.Where(d => d.Status < EOrderStatus.Filed && DateTime.Now > d.NearlyExpiredTime && DateTime.Now < d.ExpiredTime)
 					.OrderByDescending(d => d.CreationTime)
 					.Select(d => new HomeOrderDto
@@ -539,6 +545,12 @@ namespace Hotline.Api.Controllers
 				//部门即将超期
 				var nearlyExpiredDataList = await _orderRepository.Queryable(canView: !IsCenter)
 					.Includes(d => d.OrderDelays)
+					.Where(d => SqlFunc.Subqueryable<WorkflowStep>()
+						.Where(step => step.ExternalId == d.Id &&
+						               ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
+						                (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
+						                (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId))))
+						.Any())
 					.Where(d => d.Status < EOrderStatus.Filed && DateTime.Now > d.NearlyExpiredTime && DateTime.Now < d.ExpiredTime)
 					.OrderByDescending(d => d.CreationTime)
 					.Select(d => new HomeOrderDto

+ 5 - 7
src/Hotline.Api/Controllers/HotSpotController.cs

@@ -191,10 +191,6 @@ namespace Hotline.Api.Controllers
                 throw UserFriendlyException.SameMessage("同级别下存在相同名字的事件,不能添加");
             }
             var model = _mapper.Map<EventCategory>(dto);
-            if (model.EventFullName.IndexOf("-")>0)
-            {
-                model.EventFullName = model.EventFullName + "-" + model.EventName;
-            }
             (model.Id,model.EventFullName) = await _eventCategoryRepository.GetNewEventCodeAsync(dto.ParentId,model.EventName);
             await _eventCategoryRepository.AddAsync(model, HttpContext.RequestAborted);
         }
@@ -208,7 +204,7 @@ namespace Hotline.Api.Controllers
         public async Task DelEventCategory(string[] id)
         {
             var list = await _eventCategoryRepository.Queryable().In(id).ToListAsync(HttpContext.RequestAborted);
-            await _eventCategoryRepository.RemoveRangeAsync(list, HttpContext.RequestAborted);
+            await _eventCategoryRepository.RemoveRangeAsync(list,true, HttpContext.RequestAborted);
         }
 
         /// <summary>
@@ -224,9 +220,11 @@ namespace Hotline.Api.Controllers
                 throw UserFriendlyException.SameMessage("无效数据");
 
             model.EventName = dto.EventName;
-            if (dto.EventFullName.IndexOf("-") > 0)
+
+            var parentModel = await _eventCategoryRepository.GetAsync(model.ParentId, HttpContext.RequestAborted);
+            if (parentModel!= null)
             {
-                model.EventFullName = dto.EventFullName + "-" + model.EventName;
+                model.EventFullName = parentModel.EventFullName + "-" + model.EventName;
             }
             model.OrderBy = dto.OrderBy;
             await _eventCategoryRepository.UpdateAsync(model, HttpContext.RequestAborted);

+ 25 - 19
src/Hotline.Api/Controllers/IPPbxController.cs

@@ -781,37 +781,43 @@ namespace Hotline.Api.Controllers
         public async Task LinkCallRecord([FromBody] LinkCallRecordDto dto)
         {
             //var trRecord = await _trCallRecordRepository.GetAsync(x => x.CallAccept == dto.CallId, HttpContext.RequestAborted);//由CallAccept改为OtherAccept
-            var trRecord = await _trCallRecordRepository.GetAsync(x => x.OtherAccept == dto.CallId, HttpContext.RequestAborted);
+            
             if (dto.IsOrder)
             {
-                if (trRecord.CallOrderType == ECallOrderType.Order && !string.IsNullOrEmpty(trRecord.ExternalId))
-                    throw UserFriendlyException.SameMessage("通话记录已经关联工单");
-
-                //工单
-                var order = await _orderRepository.GetAsync(x => x.Id == dto.Id, HttpContext.RequestAborted);
-                if (!string.IsNullOrEmpty(order.CallId))
-                    throw UserFriendlyException.SameMessage("通话记录已经关联工单");
-
-                order.CallId = dto.CallId;
-                order.FromPhone = trRecord.CPN;
-                order.TransferPhone = trRecord.Gateway;
-                await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
-                trRecord.CallOrderType = ECallOrderType.Order;
-                trRecord.ExternalId = order.Id;
-
-                //推省上
-                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineCallConnectWithOrder, new PublishCallRecrodDto() { Order = _mapper.Map<OrderDto>(order), TrCallRecordDto = _mapper.Map<TrCallDto>(trRecord) });
+                var trRecords = await _trCallRecordRepository.Queryable().Where(x => x.OtherAccept == dto.CallId).ToListAsync(HttpContext.RequestAborted);
+                foreach (var trRecord in trRecords)
+                {
+                    if (trRecord.CallOrderType == ECallOrderType.Order && !string.IsNullOrEmpty(trRecord.ExternalId))
+                        throw UserFriendlyException.SameMessage("通话记录已经关联工单");
+
+                    //工单
+                    var order = await _orderRepository.GetAsync(x => x.Id == dto.Id, HttpContext.RequestAborted);
+                    //if (!string.IsNullOrEmpty(order.CallId))
+                    //    throw UserFriendlyException.SameMessage("通话记录已经关联工单");
+
+                    order.CallId = dto.CallId;
+                    order.FromPhone = trRecord.CPN;
+                    order.TransferPhone = trRecord.Gateway;
+                    await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
+                    trRecord.CallOrderType = ECallOrderType.Order;
+                    trRecord.ExternalId = order.Id;
+                    await _trCallRecordRepository.UpdateAsync(trRecord, HttpContext.RequestAborted);
+                    //推省上
+                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineCallConnectWithOrder, new PublishCallRecrodDto() { Order = _mapper.Map<OrderDto>(order), TrCallRecordDto = _mapper.Map<TrCallDto>(trRecord) });
+                }
             }
             else
             {
+                var trRecord = await _trCallRecordRepository.GetAsync(x => x.OtherAccept == dto.CallId, HttpContext.RequestAborted);
                 //回访
                 var visit = await _orderVisitRepository.GetAsync(x => x.Id == dto.Id, HttpContext.RequestAborted);
                 visit.CallId = dto.CallId;
                 await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted);
                 trRecord.CallOrderType = ECallOrderType.Visit;
                 trRecord.ExternalId = visit.Id;
+                await _trCallRecordRepository.UpdateAsync(trRecord, HttpContext.RequestAborted);
             }
-            await _trCallRecordRepository.UpdateAsync(trRecord, HttpContext.RequestAborted);
+           
         }
 
 

+ 184 - 126
src/Hotline.Api/Controllers/OrderController.cs

@@ -7,8 +7,6 @@ using Hotline.Application.Orders;
 using Hotline.Application.Quality;
 using Hotline.Application.Systems;
 using Hotline.Caching.Interfaces;
-using Hotline.Caching.Services;
-using Hotline.CallCenter.Calls;
 using Hotline.Configurations;
 using Hotline.ContingencyManagement.Notifies;
 using Hotline.EventBus;
@@ -32,7 +30,6 @@ using Hotline.Settings.Hotspots;
 using Hotline.Settings.TimeLimitDomain;
 using Hotline.Settings.TimeLimits;
 using Hotline.Share.Dtos;
-using Hotline.Share.Dtos.CallCenter;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Dtos.Order;
@@ -44,7 +41,6 @@ using Hotline.Share.Enums.CallCenter;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Push;
-using Hotline.Share.Enums.Quality;
 using Hotline.Share.Enums.Settings;
 using Hotline.Share.Mq;
 using Hotline.Share.Requests;
@@ -59,18 +55,14 @@ using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Options;
 using MiniExcelLibs;
-using MongoDB.Driver;
 using SqlSugar;
-using StackExchange.Redis;
 using System.Text;
-using System.Threading.Tasks;
 using XF.Domain.Authentications;
 using XF.Domain.Cache;
 using XF.Domain.Entities;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
 using XF.Utility.EnumExtensions;
-using static NPOI.SS.Format.CellNumberFormatter;
 
 namespace Hotline.Api.Controllers;
 
@@ -143,6 +135,7 @@ public class OrderController : BaseController
     private readonly ICalcExpireTime _expireTime;
     private readonly IRepository<OrderPushType> _orderPushTypeRepository;
     private readonly IOptions<CityBaseConfiguration> _cityBaseConfiguration;
+    private readonly IRepository<OrderRevoke> _orderRevokeRepository;
 
     public OrderController(
         IOrderDomainService orderDomainService,
@@ -207,7 +200,7 @@ public class OrderController : BaseController
         IRepository<OrderPushType> orderPushTypeRepository,
         ICallNativeRepository callNativeRepository,
         ICallNativeApplication callNativeApplication,
-        BaseDataApplication baseDataApplication)
+        IRepository<OrderRevoke> orderRevokeRepository)
     {
         _orderDomainService = orderDomainService;
         _orderRepository = orderRepository;
@@ -270,7 +263,7 @@ public class OrderController : BaseController
         _orderPushTypeRepository = orderPushTypeRepository;
         _callNativeRepository = callNativeRepository;
         _callNativeApplication = callNativeApplication;
-        _baseDataApplication = baseDataApplication;
+        _orderRevokeRepository = orderRevokeRepository;
     }
     #endregion 
 
@@ -2848,6 +2841,8 @@ public class OrderController : BaseController
         if (order == null) return new();
 
         var dto = _mapper.Map<OrderDto>(order);
+        //处理中心意见
+        dto.CenterOpinion = order.CenterToOrgOpinion;
         //班长代办--  判断不是会签件  流程判断业务类型
         //var setting = _systemSettingCacheManager.GetSetting(SettingConstants.SeatsMonitor);
         //var settingStr = setting?.SettingValue;
@@ -3024,8 +3019,7 @@ public class OrderController : BaseController
         {
             var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true, withTraces: true,
                 cancellationToken: HttpContext.RequestAborted);
-            var centerOpinion = workflow.Steps.Where(x => x.HandlerOrgId == OrgSeedData.CenterId && x.StepType != EStepType.End).MaxBy(d => d.CreationTime)?.Opinion ?? string.Empty;
-            dto.CenterOpinion = centerOpinion;
+
             List<OrderRemarksDto> remarks = workflow.Steps.Where(x => !string.IsNullOrEmpty(x.Remark)).Select(x => new OrderRemarksDto { Remark = x.Remark, RemarkTime = x.CreationTime, RemarkUser = x.CreatorName }).ToList();
             dto.OrderRemarks = remarks;
             if (order.Status == EOrderStatus.SendBack || order.Status == EOrderStatus.SendBackAudit || order.Status == EOrderStatus.BackToUnAccept)
@@ -3041,7 +3035,35 @@ public class OrderController : BaseController
         {
             dto.IsReturnUnderApproval = true;
         }
+        //省退回
+        var orderSendback = await _orderSendBackRepository.Queryable().Where(x => x.OrderId == order.Id).OrderByDescending(x => x.AuditTime).FirstAsync();
+        if (orderSendback is not null)
+        {
+            string stateStr = "";
+            // 0  待审核  1 审核通过  2 审核不通过
+            switch (orderSendback.State)
+            {
+                case 0:
+                    stateStr = "待审核";
+                    break;
+                case 1:
+                    stateStr = "审核通过";
+                    break;
+                case 2:
+                    stateStr = "审核不通过";
+                    break;
+                default:
+                    stateStr = "未知";
+                    break;
+            }
+            dto.ProvinceSendBackString = "该工单已向省平台发送退回申请!退回状态:" + stateStr;
+        }
 
+        var isProvinceorderRevoke = await _orderRevokeRepository.Queryable().AnyAsync(x => x.OrderId == order.Id && x.IsProRevoke == true);
+        if (isProvinceorderRevoke)
+        {
+            dto.ProvinceRevokeString = "该工单已由省平台发送撤单!请直接归档办理!";
+        }
 
         return _sessionContext.OrgIsCenter ? dto : dto.DataMask();
     }
@@ -3161,15 +3183,16 @@ public class OrderController : BaseController
         //    _logger.LogError("新增工单发送短信失败,Error:{err}", e.Message);
         //}
 
-        // 副本工单
-        var copy = new OrderCopy();
-        _mapper.Map(order, copy);
-        copy.OrderId = order.Id;
-        copy.AuditTime = DateTime.Now;
-        copy.AuditUserId = _sessionContext.UserId;
-        copy.AuditUserName = _sessionContext.UserName;
-        copy.InitId();
-        await _orderCopyRepository.AddAsync(copy, HttpContext.RequestAborted);
+        //2024-10-09 取消新增保存副本工单业务
+        //// 副本工单
+        //var copy = new OrderCopy();
+        //_mapper.Map(order, copy);
+        //copy.OrderId = order.Id;
+        //copy.AuditTime = DateTime.Now;
+        //copy.AuditUserId = _sessionContext.UserId;
+        //copy.AuditUserName = _sessionContext.UserName;
+        //copy.InitId();
+        //await _orderCopyRepository.AddAsync(copy, HttpContext.RequestAborted);
         return new { Id = order.Id, No = order.No, Password = order.Password };
     }
 
@@ -3245,9 +3268,19 @@ public class OrderController : BaseController
             .FirstAsync(d => d.Id == dto.Id);
         if (order == null)
             throw UserFriendlyException.SameMessage("无效工单编号");
-        if (order.Status > EOrderStatus.HandOverToUnAccept)
+        if (dto.IsEdit == false && order.Status > EOrderStatus.HandOverToUnAccept)
             throw UserFriendlyException.SameMessage("工单已发起流程,不可编辑");
 
+        // 副本工单
+        var copy = new OrderCopy();
+        _mapper.Map(order, copy);
+        copy.OrderId = order.Id;
+        copy.AuditTime = DateTime.Now;
+        copy.AuditUserId = _sessionContext.UserId;
+        copy.AuditUserName = _sessionContext.UserName;
+        copy.InitId();
+        await _orderCopyRepository.AddAsync(copy, HttpContext.RequestAborted);
+
         if (order.Content != dto.Content)
             await _orderApplication.OrderParticiple(dto.Content, dto.Id, order.CreationTime, HttpContext.RequestAborted);
         if (dto.RepeatableEventDetails?.Any() ?? false)
@@ -3269,6 +3302,11 @@ public class OrderController : BaseController
         if (order.SourceChannelCode != AppDefaults.SourceChannel.DianHua)
             order.CallId = null;
 
+        if (dto.IsEdit && !string.IsNullOrEmpty(dto.CenterOpinion) && order.CenterToOrgOpinion != dto.CenterOpinion)
+            order.CenterToOrgOpinion = dto.CenterOpinion;
+        if (dto.IsEdit && !string.IsNullOrEmpty(dto.FileOpinion) && order.FileOpinion != dto.FileOpinion)
+            order.FileOpinion = dto.FileOpinion;
+
         if (dto.Files.Any())
             order.FileJson = await _fileRepository.AddFileAsync(dto.Files, order.Id, "", HttpContext.RequestAborted);
         else
@@ -3286,6 +3324,32 @@ public class OrderController : BaseController
             var pushTypes = dto.OrderPushTypes.Select(x => x.PushType);
             order.PushType = string.Join(",", pushTypes);
         }
+
+        //处理工单的期满时间
+        //首先是工单编辑页面提交的、流程已经开启、工单未归档的工单才能修改期满时间
+        if (dto.IsEdit && !string.IsNullOrEmpty(order.WorkflowId) && order.Status < EOrderStatus.Filed && dto.AcceptTypeCode != order.AcceptTypeCode)
+        {
+            //自贡业务
+            if (_appOptions.Value.IsZiGong)
+            {
+                //查询当前工单的实际办理节点,如果在热线中心不处理,如果在部门需要更新期满时间
+                var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, withTraces: true, cancellationToken: HttpContext.RequestAborted);
+                var nowWorkflow = workflow.Steps.Where(p => p.Id == order.ActualHandleStepId && p.BusinessType >= EBusinessType.Department && p.BusinessType <= EBusinessType.DepartmentLeader).FirstOrDefault();
+                //在部门、中心到部门的交办时间不为空
+                if (nowWorkflow != null && order.CenterToOrgTime.HasValue)
+                {
+                    //自贡计算期满时间
+                    ExpiredTimeWithConfig expiredTimeConfig = await _expireTime.CalcExpiredTime(order.CenterToOrgTime.Value, EFlowDirection.CenterToOrg, order.Adapt<OrderTimeClacInfo>());
+                    if (expiredTimeConfig is not null && expiredTimeConfig.ExpiredTime > order.ExpiredTime)
+                    {
+                        order.ExpiredTime = expiredTimeConfig.ExpiredTime;
+                        order.NearlyExpiredTime = expiredTimeConfig.NearlyExpiredTime;
+                        order.NearlyExpiredTimeOne = expiredTimeConfig.NearlyExpiredTimeOne;
+                    }
+                }
+            }
+        }
+
         await _orderRepository.UpdateNav(order).Include(d => d.OrderExtension).ExecuteCommandAsync();
 
         //订阅此事件的内部处理工单数据只能更新各自业务的字段,不能全部更新
@@ -3295,15 +3359,7 @@ public class OrderController : BaseController
 
         //敏感分词
         await _orderApplication.OrderSensitiveParticiple(dto.Content, order.Id, HttpContext.RequestAborted);
-        // 副本工单
-        var copy = new OrderCopy();
-        _mapper.Map(order, copy);
-        copy.OrderId = order.Id;
-        copy.AuditTime = DateTime.Now;
-        copy.AuditUserId = _sessionContext.UserId;
-        copy.AuditUserName = _sessionContext.UserName;
-        copy.InitId();
-        await _orderCopyRepository.AddAsync(copy, HttpContext.RequestAborted);
+
         return new { Id = order.Id, No = order.No, Password = order.Password };
     }
 
@@ -3685,7 +3741,10 @@ public class OrderController : BaseController
         var (total, items) = await _orderRepository
             .Queryable(hasHandled: isHandled, isAdmin: isAdmin)
             .Includes(d => d.OrderSpecials)
-            .Where(d => d.Status != EOrderStatus.WaitForAccept && d.Status != EOrderStatus.BackToUnAccept && d.Status != EOrderStatus.SpecialToUnAccept && d.Status != EOrderStatus.HandOverToUnAccept)
+            .Where(d => d.Status != EOrderStatus.WaitForAccept &&
+                        d.Status != EOrderStatus.BackToUnAccept &&
+                        d.Status != EOrderStatus.SpecialToUnAccept &&
+                        d.Status != EOrderStatus.HandOverToUnAccept)
             .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword))
             .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No)
@@ -3707,58 +3766,6 @@ public class OrderController : BaseController
             .OrderByDescending(d => new { d.IsUrgent, d.StartTime })
             .ToPagedListAsync(dto, HttpContext.RequestAborted);
 
-        //if (isHandled)
-        //{
-        //    var (total, items) = await _orderRepository
-        //        .Queryable(hasHandled: isHandled)
-        //        .Includes(d => d.OrderSpecials)
-        //        .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
-        //        .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword))
-        //        .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No)
-        //        .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
-        //        .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == false, d => !d.CounterSignType.HasValue)
-        //        .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == true, d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //超期 未办
-        //        .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == false, d => d.NearlyExpiredTime < DateTime.Now && d.ExpiredTime > DateTime.Now)//即将超期 未办
-        //        .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
-        //        .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
-        //        //.Where(d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id).NotAny())
-        //        .Where(d => d.OrderSpecials.Any() == false || d.OrderSpecials.Any(s => s.State > 0))
-        //        .WhereIF(dto.StartTime.HasValue, d => d.StartTime >= dto.StartTime)
-        //        .WhereIF(dto.EndTime.HasValue, d => d.StartTime <= dto.EndTime)
-        //        .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent.Value)
-        //        .OrderByDescending(d => d.StartTime)
-        //        .ToPagedListAsync(dto, HttpContext.RequestAborted);
-        //    return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
-        //}
-        //else
-        //{
-        //    var (total, items) = await _orderRepository.Queryable()
-        //        .Where(d => SqlFunc.Subqueryable<WorkflowTrace>()
-        //            .Where(step => step.ExternalId == d.Id && step.TraceState != EWorkflowTraceState.StepRemoveByPrevious &&
-        //                                                         ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
-        //                                                          (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
-        //                                                          (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId))) &&
-        //                                                         step.Status == EWorkflowStepStatus.Handled).Any())
-        //        .Includes(d => d.OrderSpecials)
-        //        .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
-        //        .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword))
-        //        .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No)
-        //        .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
-        //        .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == false, d => !d.CounterSignType.HasValue)
-        //        .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == true, d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //超期 未办
-        //        .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == false, d => d.NearlyExpiredTime < DateTime.Now && d.ExpiredTime > DateTime.Now)//即将超期 未办
-        //        .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
-        //        .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
-        //        //.Where(d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id).NotAny())
-        //        .Where(d => d.OrderSpecials.Any() == false || d.OrderSpecials.Any(s => s.State > 0))
-        //        .WhereIF(dto.StartTime.HasValue, d => d.StartTime >= dto.StartTime)
-        //        .WhereIF(dto.EndTime.HasValue, d => d.StartTime <= dto.EndTime)
-        //        .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent.Value)
-        //        .OrderByDescending(d => d.StartTime)
-
-        //        .ToPagedListAsync(dto, HttpContext.RequestAborted);
-        //    return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
-        //}
         return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
     }
 
@@ -3820,35 +3827,6 @@ public class OrderController : BaseController
              .OrderByIF(dto.IsHandled == false, d => new { IsUrgent = d.IsUrgent, CreationTime = d.CreationTime }, OrderByType.Desc)
             .ToPagedListAsync(dto, HttpContext.RequestAborted);
 
-        //var (total, items) = await _orderRepository.Queryable()
-        //    .LeftJoin<WorkflowStep>((d, step) => d.Id == step.ExternalId)
-        //    .Where((d, step) =>
-        //        ((string.IsNullOrEmpty(d.WorkflowId) && (string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId)) ||
-        //        (!string.IsNullOrEmpty(d.WorkflowId) &&
-        //        ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
-        //         (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
-        //         (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId))) &&
-        //         (((dto.IsHandled.HasValue && dto.IsHandled == false) && step.Status != EWorkflowStepStatus.Handled) ||
-        //        ((dto.IsHandled.HasValue && dto.IsHandled == true) && step.Status == EWorkflowStepStatus.Handled)))))
-        //    .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
-        //    .WhereIF(dto.IsHandled.HasValue, d => handleStatuses.Contains(d.Status))
-        //    .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword!))
-        //    .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No)
-        //    .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
-        //    .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == false, d => !d.CounterSignType.HasValue)
-        //    .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == true, d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //超期 未办
-        //    .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == false, d => d.NearlyExpiredTime < DateTime.Now && d.ExpiredTime > DateTime.Now)//即将超期 未办
-        //    .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
-        //    .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
-        //    .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent.Value)
-        //    .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
-        //    .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
-        //    .OrderBy(d => d.Status)
-        //    .OrderByIF(dto.IsHandled == true, d => d.StartTime, OrderByType.Desc)
-        //    .OrderByIF(dto.IsHandled == false, d => d.CreationTime, OrderByType.Desc)
-        //    .Select((d, step) => d)
-        //    .ToPagedListAsync(dto, HttpContext.RequestAborted);
-
         return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
     }
 
@@ -4060,16 +4038,16 @@ public class OrderController : BaseController
             TraceId = currentStep.Id
         };
         audit.InitId();
-		if (dto.Files.Any())
-	        audit.FileJson = await _fileRepository.AddFileAsync(dto.Files, audit.Id, "", HttpContext.RequestAborted);
-		if (_appOptions.Value.IsZiGong && prevStep.BusinessType == EBusinessType.Send)
+        if (dto.Files.Any())
+            audit.FileJson = await _fileRepository.AddFileAsync(dto.Files, audit.Id, "", HttpContext.RequestAborted);
+        if (_appOptions.Value.IsZiGong && prevStep.BusinessType == EBusinessType.Send)
         {
             // 平均派单
             var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
             if (averageSendOrder)
             {
                 var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
-                dto.NextHandlers = new List<FlowStepHandler> { handler };
+                dto.Handler = handler;
             }
         }
 
@@ -4292,18 +4270,18 @@ public class OrderController : BaseController
     [HttpGet("order_previous/{id}")]
     public async Task<SendBackDto> OrderSendBackEntity(string id)
     {
-        var res =  await _orderSendBackAuditRepository.Queryable()
+        var res = await _orderSendBackAuditRepository.Queryable()
             .Includes(x => x.Order)
             .FirstAsync(x => x.Id == id);
         var resDto = _mapper.Map<SendBackDto>(res);
         if (res.FileJson != null && res.FileJson.Any())
         {
-	        var ids = res.FileJson.Select(x => x.Id).ToList();
-	        var files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
-	        resDto.Files = files.Where(x => x.Classify == "退回附件" && string.IsNullOrEmpty(x.FlowKey)).ToList();
+            var ids = res.FileJson.Select(x => x.Id).ToList();
+            var files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
+            resDto.Files = files.Where(x => x.Classify == "退回附件" && string.IsNullOrEmpty(x.FlowKey)).ToList();
         }
         return resDto;
-	}
+    }
 
     /// <summary>
     /// 列表页面基础数据
@@ -4369,7 +4347,7 @@ public class OrderController : BaseController
                 continue;
             }
 
-            if (order.Status >= EOrderStatus.HandOverToUnAccept)
+            if (order.Status >= EOrderStatus.Filed || order.Status == EOrderStatus.BackToProvince || !order.IsProvince || (!string.IsNullOrEmpty(order.ActualHandleOrgCode) && order.ActualHandleOrgCode != "001"))
             {
                 errorCount++;
                 continue;
@@ -4420,7 +4398,7 @@ public class OrderController : BaseController
         var order = await _orderRepository.GetAsync(dto.OrderId, HttpContext.RequestAborted);
         if (order is null)
             throw UserFriendlyException.SameMessage("无效工单");
-        if (order.Status >= EOrderStatus.HandOverToUnAccept)
+        if (order.Status >= EOrderStatus.Filed || order.Status == EOrderStatus.BackToProvince || !order.IsProvince || (!string.IsNullOrEmpty(order.ActualHandleOrgCode) && order.ActualHandleOrgCode != "001"))
             throw UserFriendlyException.SameMessage("工单状态无效,请确认当前工单状态");
         if (order.Source <= ESource.HotlineImport)
             throw UserFriendlyException.SameMessage("工单来源无效,请确认当前工单来源");
@@ -6177,7 +6155,7 @@ public class OrderController : BaseController
 
                     order.FirstVisitResultCode = _sysDicDataCacheManager
                         .GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction)
-                        .FirstOrDefault(m => m.DicDataName == item.VisitResult)?.DicDataValue 
+                        .FirstOrDefault(m => m.DicDataName == item.VisitResult)?.DicDataValue
                         ?? order.FirstVisitResultCode;
 
                     #endregion
@@ -6185,7 +6163,7 @@ public class OrderController : BaseController
                     if (order.Id.IsNullOrEmpty())
                     {
                         //order.Source = item;
-                        var id = await _orderDomainService.AddAsync(order,false,  HttpContext.RequestAborted);
+                        var id = await _orderDomainService.AddAsync(order, false, HttpContext.RequestAborted);
                         if (!string.IsNullOrEmpty(id))
                         {
                             addCount++;
@@ -6440,6 +6418,52 @@ public class OrderController : BaseController
         return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
     }
 
+    /// <summary>
+    /// 查询工单修改记录
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("order_modify_records/list")]
+    public async Task<PagedDto<OrderDto>> OrderModifyRecordsList([FromQuery] PagedKeywordRequest dto)
+    {
+        var (total, items) = await _orderCopyRepository.Queryable()
+            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.No.Contains(dto.Keyword!))
+            .OrderByDescending(x => x.CreationTime)
+            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+        return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
+    }
+
+    /// <summary>
+    /// 修改明细
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    [HttpGet("order_modify_records/getinfo/{id}")]
+    public async Task<object> GetModifyRecordsInfo(string id)
+    {
+        //修改前数据
+        var modifyRecordsInfo = await _orderCopyRepository.GetAsync(p => p.Id == id, HttpContext.RequestAborted);
+        if (modifyRecordsInfo is null)
+            throw UserFriendlyException.SameMessage("修改明细查询失败!");
+
+        //如何取修改后的数据
+        var copyNew = await _orderCopyRepository.Queryable().OrderBy(x => x.CreationTime)
+               .FirstAsync(p => p.OrderId == modifyRecordsInfo.OrderId && p.CreationTime > modifyRecordsInfo.CreationTime);
+        OrderDto newInfo = null;
+        if (copyNew != null)
+        {
+            newInfo = _mapper.Map<OrderDto>(copyNew);
+        }
+        else
+        {
+            var order = await _orderRepository.Queryable().FirstAsync(d => d.Id == modifyRecordsInfo.OrderId);
+            if (order is not null)
+                newInfo = _mapper.Map<OrderDto>(order);
+        }
+
+        return new { OldInfo = _mapper.Map<OrderDto>(modifyRecordsInfo), NewInfo = newInfo };
+    }
+
     #endregion
 
     #region 外部市民管理
@@ -6532,6 +6556,40 @@ public class OrderController : BaseController
         return new PagedDto<ExternalcitizensRep>(total, _mapper.Map<IReadOnlyList<ExternalcitizensRep>>(items));
     }
 
+    /// <summary>
+    /// 删除外部市民
+    /// </summary>
+    /// <param name="ids"></param>
+    /// <returns></returns>
+    [HttpDelete("del-externalcitizens")]
+    public async Task DelExternalcitizens(string[] ids)
+    {
+        var list = await _externalCitizensRepository.Queryable().In(ids).ToListAsync(HttpContext.RequestAborted);
+        await _externalCitizensRepository.RemoveRangeAsync(list, HttpContext.RequestAborted);
+    }
+
+    /// <summary>
+    /// 修改外部市民
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("modify-externalcitizens")]
+    public async Task ModifyExternalcitizens([FromBody] ModifyExternalcitizensDto dto)
+    {
+        if (dto.PhoneNum.Length != 11)
+            throw UserFriendlyException.SameMessage("手机号不合法");
+        bool isHas = await _externalCitizensRepository.Queryable().AnyAsync(x => x.Id != dto.Id && x.PhoneNum == dto.PhoneNum);
+        if (isHas)
+            throw UserFriendlyException.SameMessage("已存在当前电话,请核对后再修改");
+        var model = await _externalCitizensRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
+        if (model == null)
+            throw UserFriendlyException.SameMessage("无效数据");
+        model.PhoneNum = dto.PhoneNum;
+        model.Name = dto.Name;
+        await _externalCitizensRepository.UpdateAsync(model, HttpContext.RequestAborted);
+    }
+
+
     #endregion
 
     #region 工单期满时间、来源方式修改

+ 6 - 5
src/Hotline.Api/Controllers/WebPortalController.cs

@@ -135,17 +135,18 @@ namespace Hotline.Api.Controllers
                 .Where(p => p.IsArrive == true)
                 .Where(p => SqlFunc.JsonListObjectAny(p.PushRanges, "Key", "2"))
                //  .Where(p => p.BulletinTypeId == dto.BulletinTypeId)
-               .WhereIF(!string.IsNullOrEmpty(dto.BulletinTypeId), p => p.BulletinTypeId == dto.BulletinTypeId)
-                 .WhereIF(!string.IsNullOrEmpty(dto.CheckChar), p => p.Content.Contains(dto.CheckChar))
-                 .OrderByDescending(p => p.BulletinTime)
-                 .Select(it => new
+                .WhereIF(!string.IsNullOrEmpty(dto.BulletinTypeId), p => p.BulletinTypeId == dto.BulletinTypeId)
+                .WhereIF(!string.IsNullOrEmpty(dto.CheckChar), p => p.Content.Contains(dto.CheckChar))
+                .WhereIF(!string.IsNullOrEmpty(dto.BulletinDisplayLocation), p => SqlFunc.JsonListObjectAny(p.DisplayLocation, "Key", dto.BulletinDisplayLocation))
+                .OrderByDescending(p => p.BulletinTime)
+                .Select(it => new
                  {
                      DataID = it.Id,
                      it.Title,
                      CreateDate = it.BulletinTime,
                      it.Content
                  })
-                 .Take(dto.Num)
+                .Take(dto.Num)
                 .ToListAsync();
 
             var data = _mapper.Map<IReadOnlyList<DataListTopDto>>(items);

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

@@ -24,8 +24,6 @@ using Hotline.File;
 using Hotline.Orders;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Dtos.FlowEngine.Definition;
-using Microsoft.AspNetCore.Authorization;
-using Hotline.Caching.Services;
 using Hotline.Settings.TimeLimits;
 using Hotline.SeedData;
 

+ 14 - 2
src/Hotline.Application/CallCenter/DefaultCallApplication.cs

@@ -289,10 +289,22 @@ public abstract class DefaultCallApplication : ICallApplication
     /// <summary>
     /// 查询通话记录
     /// </summary>
-    public virtual async Task<CallNative?> GetCallAsync(string callId, CancellationToken cancellationToken)
+    public virtual async Task<CallNative> GetCallAsync(string callId, CancellationToken cancellationToken)
     {
         if (string.IsNullOrEmpty(callId)) return null;
-        return await _callNativeRepository.GetAsync(callId, cancellationToken);
+        return await _callNativeRepository.GetAsync(callId,cancellationToken);
+    }
+
+    /// <summary>
+    /// 查询通话记录列表
+    /// </summary>
+    /// <param name="callId"></param>
+    /// <param name="cancellationToken"></param>
+    /// <returns></returns>
+    public virtual async Task<List<CallNative>> GetCallListAsync(string callId,CancellationToken cancellationToken)
+    {
+        if(string.IsNullOrEmpty(callId)) return null;
+        return await _callNativeRepository.Queryable().Where(x => x.Id == callId).ToListAsync(cancellationToken);
     }
 
     /// <summary>

+ 8 - 0
src/Hotline.Application/CallCenter/ICallApplication.cs

@@ -86,9 +86,17 @@ namespace Hotline.Application.CallCenter
         /// </summary>
         Task<int> UpdateRelationOptLockAsync(CallidRelation relation, CancellationToken cancellationToken);
 
+        /// <summary>
+        /// 查询通话记录列表
+        /// </summary>
+        Task<List<CallNative>> GetCallListAsync(string callId, CancellationToken cancellationToken);
+
         /// <summary>
         /// 查询通话记录
         /// </summary>
+        /// <param name="callId"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
         Task<CallNative?> GetCallAsync(string callId, CancellationToken cancellationToken);
 
         /// <summary>

+ 26 - 8
src/Hotline.Application/CallCenter/TianRunCallApplication.cs

@@ -109,6 +109,8 @@ namespace Hotline.Application.CallCenter
             return callRecord;
         }
 
+        
+
         /// <summary>
         /// 根据转写ID获取通话信息
         /// </summary>
@@ -136,13 +138,16 @@ namespace Hotline.Application.CallCenter
 		/// </summary>
 		public override async Task RelateTianrunCallWithOrderAsync(string callId, string orderId, CancellationToken cancellationToken)
         {
-            var callRecord = await _trCallRecordRepository.GetAsync(
-                p => p.OtherAccept == callId && string.IsNullOrEmpty(p.OtherAccept) == false, cancellationToken);
-            if (callRecord != null && string.IsNullOrEmpty(callRecord.ExternalId))
+            var callRecords = await _trCallRecordRepository.Queryable().Where(p => p.OtherAccept == callId && string.IsNullOrEmpty(p.OtherAccept) == false).ToListAsync(cancellationToken);
+
+            foreach (var callRecord in callRecords)
             {
-                callRecord.ExternalId = orderId;
-                callRecord.CallOrderType = Share.Enums.CallCenter.ECallOrderType.Order;
-                await _trCallRecordRepository.UpdateAsync(callRecord, cancellationToken);
+                if (callRecord != null && string.IsNullOrEmpty(callRecord.ExternalId))
+                {
+                    callRecord.ExternalId = orderId;
+                    callRecord.CallOrderType = Share.Enums.CallCenter.ECallOrderType.Order;
+                    await _trCallRecordRepository.UpdateAsync(callRecord, cancellationToken);
+                }
             }
         }
 
@@ -180,8 +185,21 @@ namespace Hotline.Application.CallCenter
         public override async Task<CallNative?> GetCallAsync(string callId, CancellationToken cancellationToken)
         {
             var call = await _trCallRecordRepository.Queryable()
-                .FirstAsync(d => d.OtherAccept == callId, cancellationToken);
-            return _mapper.Map<CallNative>(call);
+                .FirstAsync(d => d.OtherAccept == callId,cancellationToken);
+            return _mapper.Map<CallNative?>(call);
+        }
+
+        /// <summary>
+        /// 查询通话记录列表
+        /// </summary>
+        /// <param name="callId"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public override async Task<List<CallNative>> GetCallListAsync(string callId, CancellationToken cancellationToken)
+        {
+            var call = await _trCallRecordRepository.Queryable()
+                .Where(d => d.OtherAccept == callId).ToListAsync(cancellationToken);
+            return _mapper.Map<List<CallNative>>(call);
         }
     }
 }

+ 6 - 0
src/Hotline.Application/FlowEngine/IWorkflowApplication.cs

@@ -22,6 +22,12 @@ namespace Hotline.Application.FlowEngine
         Task<string> StartWorkflowAsync(StartWorkflowDto dto, ISessionContext current, string externalId, DateTime? expiredTime = null,
             CancellationToken cancellationToken = default);
 
+        /// <summary>
+        /// 开始流程并停留在开始节点(开始节点作为待办节点)
+        /// </summary>
+        Task<string> StartWorkflowToStartStepAsync(StartWorkflowDto dto, ISessionContext current, string externalId, DateTime? expiredTime = null,
+            CancellationToken cancellationToken = default);
+        
         /// <summary>
         /// 查询下一节点办理对象类型(user or org)及实际办理对象
         /// </summary>

+ 70 - 4
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -212,6 +212,75 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         return workflow.Id;
     }
 
+    /// <summary>
+    /// 开始流程并停留在开始节点(开始节点作为待办节点)
+    /// </summary>
+    public async Task<string> StartWorkflowToStartStepAsync(StartWorkflowDto dto, ISessionContext current, string externalId, DateTime? expiredTime = null,
+        CancellationToken cancellationToken = default)
+    {
+        var validator = new StartWorkflowDtoValidator();
+        var validResult = await validator.ValidateAsync(dto, cancellationToken);
+        if (!validResult.IsValid)
+            throw new UserFriendlyException(
+                $"非法参数, {string.Join(',', validResult.Errors.Select(d => d.ErrorMessage))}");
+
+        var wfModule = await GetWorkflowModuleAsync(dto.DefinitionModuleCode, cancellationToken);
+        var definition = wfModule.Definition;
+        if (definition == null)
+            throw new UserFriendlyException("无效模板编码");
+        if (definition.Status is not EDefinitionStatus.Enable)
+            throw new UserFriendlyException("该模板不可用");
+
+        //如果发起会签需检查是否支持发起会签
+        var startStepDefine = definition.FindStartStepDefine();
+
+        var workflow = await _workflowDomainService.CreateWorkflowAsync(wfModule, dto.Title,
+            current.RequiredUserId, current.RequiredOrgId,
+            externalId, cancellationToken);
+        
+        var defineHandler = startStepDefine.HandlerTypeItems.First();
+        
+        //todo 需求:所有坐席都可以办,临时方案,后期重构:依据策略决定指派对象
+        var startStep = _workflowDomainService.CreateStartStep(workflow, startStepDefine, dto,
+            new FlowStepHandler
+            {
+                Key = current.RequiredUserId,
+                Value = current.UserName,
+                UserId = current.UserId,
+                Username = current.UserName,
+                OrgId = current.RequiredOrgId,
+                OrgName = current.OrgName,
+                RoleId = defineHandler.Key,
+                RoleName = defineHandler.Value,
+            }, expiredTime,
+            EFlowAssignType.Role);
+        
+        if (dto.Files.Any())
+            startStep.FileJson = await _fileRepository.AddFileAsync(dto.Files, workflow.ExternalId, startStep.Id, cancellationToken);
+
+        await _workflowStepRepository.AddAsync(startStep, cancellationToken);
+        workflow.Steps.Add(startStep);
+
+        //starttrace
+        var startTrace = _mapper.Map<WorkflowTrace>(startStep);
+        startTrace.StepId = startStep.Id;
+        startTrace.TraceType = EWorkflowTraceType.Normal;
+        //_mapper.Map(dto, startTrace);
+        await _workflowTraceRepository.AddAsync(startTrace, cancellationToken);
+        workflow.Traces.Add(startTrace);
+        startStep.WorkflowTrace = startTrace;
+
+        //更新受理人信息
+        workflow.UpdateAcceptor(
+            current.RequiredUserId,
+            current.UserName,
+            current.StaffNo,
+            current.RequiredOrgId,
+            current.OrgName);
+        
+        return workflow.Id;
+    }
+
     /// <summary>
     /// 流转至下一节点(节点办理)
     /// </summary>
@@ -286,9 +355,6 @@ 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 == _sessionContext.RequiredUserId, cancellationToken);
         return await _workflowDomainService.PreviousAsync(workflow, dto,
             _sessionContext.RequiredUserId, _sessionContext.UserName,
             _sessionContext.RequiredOrgId, _sessionContext.OrgName,
@@ -1622,7 +1688,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             case EHandlerType.AssignedUser:
                 return FlowAssignInfo.Create(EFlowAssignType.User, handlers, isStartCountersign);
             case EHandlerType.AssignedOrgOrRole:
-	            return FlowAssignInfo.Create(EFlowAssignType.OrgOrRole, handlers, isStartCountersign);
+	            return FlowAssignInfo.Create(EFlowAssignType.OrgAndRole, handlers, isStartCountersign);
 
             default:
                 throw new ArgumentOutOfRangeException();

+ 4 - 0
src/Hotline.Application/Mappers/MapperConfigs.cs

@@ -24,6 +24,10 @@ namespace Hotline.Application.Mappers
     {
         public void Register(TypeAdapterConfig config)
         {
+            config.ForType<ExcelContent, Order>()
+                .Map(d => d.FirstVisitResult, x => x.VisitResult)
+                .IgnoreNullValues(true);
+
             config.ForType<SystemDicData, Kv>()
                 .Map(s => s.Key, d => d.DicDataValue)
                 .Map(s => s.Value, d => d.DicDataName);

+ 5 - 3
src/Hotline.Application/Mappers/OrderMapperConfigs.cs

@@ -31,7 +31,7 @@ public class OrderMapperConfigs : IRegister
             .Map(d => d.StartTime, s => s.Order.StartTime)
             .Map(d => d.FiledTime, s => s.Order.FiledTime)
             .Map(d => d.RecordUrl, s => s.OrderVisit.RecordUrl)
-            .Map(d=>d.SeatEvaluate,s=>s.AiSeatEvaluate)
+            .Map(d => d.SeatEvaluate, s => s.AiSeatEvaluate)
             .AfterMapping((s, d) =>
             {
                 //d.SeatEvaluate = s.OrderVisit.OrderVisitDetails.FirstOrDefault(x => x.VisitTarget == EVisitTarget.Seat)?.SeatEvaluate;
@@ -74,7 +74,7 @@ public class OrderMapperConfigs : IRegister
             .Map(d => d.FiledTime, s => s.OrderVisit.Order.FiledTime)
             .AfterMapping((s, d) =>
             {
-                d.OrderScreenStatus = s.OrderVisit.Order.OrderScreens.OrderByDescending(q=>q.CreationTime).FirstOrDefault()?.Status;
+                d.OrderScreenStatus = s.OrderVisit.Order.OrderScreens.OrderByDescending(q => q.CreationTime).FirstOrDefault()?.Status;
                 d.OrgProcessingResults = s.OrgProcessingResults.Value;
             });
 
@@ -97,6 +97,8 @@ public class OrderMapperConfigs : IRegister
         config.ForType<UpdateOrderDto, Order>()
             .Inherits<AddOrderDto, Order>()
             .Map(d => d.OrderExtension.Id, x => x.Id)
+            //.IgnoreIf((s, d) => !string.IsNullOrEmpty(s.FileOpinion), d => d.FileOpinion)
+            //.IgnoreIf((s, d) => !string.IsNullOrEmpty(s.CenterOpinion), d => d.CenterToOrgOpinion)
             .Ignore(d => d.ProvinceNo);
 
         config.ForType<Workflow, Order>()
@@ -107,7 +109,7 @@ public class OrderMapperConfigs : IRegister
             .Ignore(d => d.AcceptorId)
             .Ignore(d => d.AcceptorName)
             .Ignore(d => d.AcceptorStaffNo)
-            .Ignore(d=>d.ExternalId)
+            .Ignore(d => d.ExternalId)
             //.AfterMapping((s, d) =>
             //{
             //    //d.UpdateHandlingStatus(s.IsInCountersign);

+ 46 - 36
src/Hotline.Application/Subscribers/DatasharingSubscriber.cs

@@ -162,8 +162,22 @@ namespace Hotline.Application.Subscribers
                 if (order is null)
                     throw new UserFriendlyException("无效工单编号");
 
-                if (dto.Result is 1)
+                if (!string.IsNullOrEmpty(order.WorkflowId))
+                {
+                    order.Status = EOrderStatus.Handling;
+                }
+                else
                 {
+                    order.Status = EOrderStatus.WaitForAccept;
+                }
+                if (dto.Result is 1)
+                    order.ProvinceSendBack = true;
+                else
+                    order.ProvinceSendBack = false;
+                await _orderRepository.UpdateAsync(order, cancellationToken);
+
+                //if (dto.Result is 1)
+                //{
                     //var now = DateTime.Now;
                     //var handleDuration = order.StartTime.HasValue
                     //    ? _timeLimitDomainService.CalcWorkTime(order.StartTime.Value,
@@ -180,31 +194,33 @@ namespace Hotline.Application.Subscribers
                     //order.File(now, handleDuration, fileDuration, allDuration);
                     //await _orderRepository.UpdateAsync(order, cancellationToken);
 
-                    var current = SessionContextCreator.CreateSessionContext(dto.Source, _cityBaseConfiguration.Value);
-                    if (string.IsNullOrEmpty(order.WorkflowId))
-                    {
-                        var startDto = new StartWorkflowDto
-                        {
-                            DefinitionModuleCode = WorkflowModuleConsts.OrderHandle,
-                            Title = order.Title,
-                            Opinion = dto.Reason ?? "省工单同意退回",
-                        };
-                        await _workflowApplication.StartToEndAsync(startDto, current, order.Id, order.ExpiredTime,
-                            cancellationToken);
-                    }
-                    else
-                    {
-                        //await _workflowApplication.HandleToEndAsync(current, order.WorkflowId, "省工单同意退回", null,
-                        //    EReviewResult.Approval, cancellationToken);
-                        await _workflowApplication.JumpToEndAsync(current, order.WorkflowId, dto.Reason ?? "省工单同意退回",
-                            null, order.ExpiredTime, cancellationToken: cancellationToken);
-                    }
-                }
-                else
-                {
-                    order.Status = EOrderStatus.WaitForAccept;
-                    await _orderRepository.UpdateAsync(order, cancellationToken);
-                }
+                    //var current = SessionContextCreator.CreateSessionContext(dto.Source, _cityBaseConfiguration.Value);
+                    //if (string.IsNullOrEmpty(order.WorkflowId))
+                    //{
+                    //    var startDto = new StartWorkflowDto
+                    //    {
+                    //        DefinitionModuleCode = WorkflowModuleConsts.OrderHandle,
+                    //        Title = order.Title,
+                    //        Opinion = dto.Reason ?? "省工单同意退回",
+                    //    };
+                    //    await _workflowApplication.StartToEndAsync(startDto, current, order.Id, order.ExpiredTime,
+                    //        cancellationToken);
+                    //}
+                    //else
+                    //{
+                    //    //await _workflowApplication.HandleToEndAsync(current, order.WorkflowId, "省工单同意退回", null,
+                    //    //    EReviewResult.Approval, cancellationToken);
+                    //    await _workflowApplication.JumpToEndAsync(current, order.WorkflowId, dto.Reason ?? "省工单同意退回",
+                    //        null, order.ExpiredTime, cancellationToken: cancellationToken);
+                    //}
+
+
+                    //TODO 工单终止
+                //}
+                //else
+                //{
+                   
+                //}
                 await _orderSendBackRepository.UpdateAsync(sendBack, cancellationToken);
             }
 
@@ -240,7 +256,7 @@ namespace Hotline.Application.Subscribers
             };
             await _orderRevokeRepository.AddAsync(orderRevoke, cancellationToken);
 
-            //宜宾需求:特提至中心(派单组?),由派单员归档
+            //宜宾需求:特提至中心(优先派单组无派单组节点就特提至坐席),由派单员归档
             var current = SessionContextCreator.CreateSessionContext(dto.Source, _cityBaseConfiguration.Value);
             if (string.IsNullOrEmpty(order?.WorkflowId))
             {
@@ -250,18 +266,12 @@ namespace Hotline.Application.Subscribers
                     Title = order.Title,
                     Opinion = dto.Opinion,
                 };
-                //await _workflowApplication.StartToEndAsync(startDto, current, order.Id, order.ExpiredTime,
-                //    cancellationToken);
-                await _workflowApplication.StartWorkflowAsync(startDto, current, order.Id, order.ExpiredTime,
-                    cancellationToken);
+              order.WorkflowId =  await _workflowApplication.StartWorkflowToStartStepAsync(startDto, current, order.Id, order.ExpiredTime, cancellationToken);
+              await _orderRepository.UpdateAsync(order, cancellationToken);
             }
             else
             {
-                //await _workflowApplication.HandleToEndAsync(current, order.WorkflowId, dto.Opinion, null,
-                //    cancellationToken: cancellationToken);
-                //await _workflowApplication.JumpToEndAsync(current, order.WorkflowId, dto.Opinion, null, order.ExpiredTime,
-                //    cancellationToken: cancellationToken);
-                await _workflowDomainService.RecallToStartStepAsync(order.WorkflowId, dto.Opinion, current, cancellationToken);
+                await _workflowDomainService.RecallToCenterFirstToSendAsync(order.WorkflowId, dto.Opinion, current, cancellationToken);
             }
         }
 

+ 1 - 0
src/Hotline.Repository.SqlSugar/System/EventCategoryRepository.cs

@@ -14,6 +14,7 @@ namespace Hotline.Repository.SqlSugar.System
 
         public async Task<(string,string)> GetNewEventCodeAsync(string? parentId,string name)
         {
+            Db.QueryFilter.Clear();
             if (string.IsNullOrEmpty(parentId))
             {
                 //一级

+ 10 - 0
src/Hotline.Share/Dtos/Article/BulletinDto.cs

@@ -55,6 +55,11 @@ namespace Hotline.Share.Dtos.Article
         /// </summary>
         public List<Kv> PushRanges { get; set; }
 
+        /// <summary>
+        /// 显示位置(多选) 位枚举  BulletinDisplayLocation
+        /// </summary>
+        public List<Kv> DisplayLocation { get; set; }
+
         /// <summary>
         /// 来源单位ID
         /// </summary>
@@ -376,6 +381,11 @@ namespace Hotline.Share.Dtos.Article
 		/// </summary>
 		public List<Kv> PushRanges { get; set; }
 
+        /// <summary>
+        /// 显示位置(多选) 位枚举  BulletinDisplayLocation
+        /// </summary>
+        public List<Kv> DisplayLocation { get; set; }
+
         /// <summary>
         /// 来源单位ID
         /// </summary>

+ 10 - 6
src/Hotline.Share/Dtos/FlowEngine/PreviousWorkflowDto.cs

@@ -12,12 +12,16 @@ public class PreviousWorkflowDto : EndWorkflowIdDto
     /// </summary>
     public DateTime? ExpiredTime { get; set; }
 
+    ///// <summary>
+    ///// 根据办理者类型不同,此字段为不同内容
+    ///// <example>
+    ///// 部门等级/分类为:depCodes, 角色为:userIds
+    ///// </example>
+    ///// </summary>
+    //public List<FlowStepHandler> NextHandlers { get; set; } = new();
+
     /// <summary>
-    /// 根据办理者类型不同,此字段为不同内容
-    /// <example>
-    /// 部门等级/分类为:depCodes, 角色为:userIds
-    /// </example>
+    /// 指定办理对象
     /// </summary>
-    public List<FlowStepHandler> NextHandlers { get; set; } = new();
-
+    public FlowStepHandler? Handler { get; set; }
 }

+ 10 - 0
src/Hotline.Share/Dtos/Order/ExternalcitizensDto.cs

@@ -16,10 +16,20 @@ namespace Hotline.Share.Dtos.Order
 
     public class ExternalcitizensRep
     {
+        public string Id { get; set; }
         public string PhoneNum { get; set;}
 
         public string Name { get; set; }
 
         public DateTime CreationTime { get; set; }
     }
+
+    public class ModifyExternalcitizensDto
+    {
+        public string Id { get; set; }
+
+        public string PhoneNum { get; set; }
+
+        public string Name { get; set; }
+    }
 }

+ 50 - 19
src/Hotline.Share/Dtos/Order/OrderDto.cs

@@ -97,10 +97,10 @@ namespace Hotline.Share.Dtos.Order
         public DateTime? FiledTime { get; set; }
 
 
-        /// <summary>
-        /// 归档意见
-        /// </summary>
-        public string? FileOpinion { get; set; }
+        ///// <summary>
+        ///// 归档意见
+        ///// </summary>
+        //public string? FileOpinion { get; set; }
 
         /// <summary>
         /// 办结时长(分钟)
@@ -509,7 +509,7 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public int SpecialNum { get; set; }
 
-		private string CalculateExpiredText()
+        private string CalculateExpiredText()
         {
             //todo 完整处理方案:1.创建待过期表,Id,过期时间,即将过期时间等字段。2.延迟消息通知处理过期,删除子表数据,处理order过期状态字段。3.此处即可采用expiredStatus进行判断
             //todo 目前暂时采用过期时间计算
@@ -718,18 +718,49 @@ namespace Hotline.Share.Dtos.Order
         /// <summary>
         /// 是否退回审批中
         /// </summary>
-        public bool IsReturnUnderApproval {  get; set; }
+        public bool IsReturnUnderApproval { get; set; }
 
         /// <summary>
         /// 退回截至时间
         /// </summary>
         public DateTime? SendBackAuditEndTime { get; set; }
 
+        /// <summary>
+        /// 省退回信息
+        /// </summary>
+        public string ProvinceSendBackString { get; set; }
+
+        /// <summary>
+        /// 省撤单信息
+        /// </summary>
+        public string ProvinceRevokeString { get; set; }
+
+        /// <summary>
+        /// 省工单退回
+        /// </summary>
+        public bool? ProvinceSendBack { get; set; }
+
+
     }
 
     public class UpdateOrderDto : AddOrderDto
     {
         public string Id { get; set; }
+
+        /// <summary>
+        /// 中心意见
+        /// </summary>
+        public string CenterOpinion { get; set; }
+        /// <summary>
+        /// 归档意见
+        /// </summary>
+        public string? FileOpinion { get; set; }
+
+        /// <summary>
+        /// 能否编辑,true:任何节点可以编辑;false:未发起流程可以编辑
+        /// </summary>
+        public bool IsEdit { get; set; }
+
     }
 
     public class AddOrderDto : Position
@@ -881,16 +912,16 @@ namespace Hotline.Share.Dtos.Order
         public List<string>? DuplicateIds { get; set; }
 
 
-		/// <summary>
-		/// 推送分类 -- 弃用 转为表存储
-		/// </summary>
-		public string? PushTypeCode { get; set; }
+        /// <summary>
+        /// 推送分类 -- 弃用 转为表存储
+        /// </summary>
+        public string? PushTypeCode { get; set; }
 
 
-		/// <summary>
-		/// 推送分类 -- 弃用 转为表存储
-		/// </summary>
-		public string? PushType { get; set; }
+        /// <summary>
+        /// 推送分类 -- 弃用 转为表存储
+        /// </summary>
+        public string? PushType { get; set; }
 
         /// <summary>
         /// 附件
@@ -1052,10 +1083,10 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public bool IsThreePartyConference { get; set; }
 
-		/// <summary>
-		/// 是否政民互动公开
-		/// </summary>
-		public bool IsProvinceZmhd { get; set; }
+        /// <summary>
+        /// 是否政民互动公开
+        /// </summary>
+        public bool IsProvinceZmhd { get; set; }
 
         /// <summary>
         /// 初审人姓名
@@ -1076,7 +1107,7 @@ namespace Hotline.Share.Dtos.Order
         /// 工单推送分类
         /// </summary>
         public List<OrderPushTypeDto>? OrderPushTypes { get; set; }
-	}
+    }
 
     public record CanLinkCallRecordOrderDto : PagedKeywordRequest
     {

+ 5 - 0
src/Hotline.Share/Dtos/WebPortal/ArticleDetailsDto.cs

@@ -29,6 +29,11 @@ namespace Hotline.Share.Dtos.WebPortal
         /// 是否查询图片
         /// </summary>
         public string CheckChar { get; set; }
+
+        /// <summary>
+        /// 显示位置
+        /// </summary>
+        public string? BulletinDisplayLocation { get; set; }
     }
 
     /// <summary>

+ 2 - 0
src/Hotline.Share/Dtos/WebPortal/GetOrderCodePwd.cs

@@ -353,5 +353,7 @@ namespace Hotline.Share.Dtos.WebPortal
         public DateTime? CreateDate { get; set; }
 
         public string? Content { get; set; }
+
+        public string? BulletinTypeName { get; set; }
     }
 }

+ 6 - 0
src/Hotline/Article/Bulletin.cs

@@ -87,6 +87,12 @@ namespace Hotline.Article
         /// </summary>
         public bool? IsArrive { get; set; }
 
+        /// <summary>
+        /// 显示位置(多选) 位枚举  BulletinDisplayLocation
+        /// </summary>
+        [SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
+        public List<Kv>? DisplayLocation { get; set; }
+
         /// <summary>
         /// 阅读量+1
         /// </summary>

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

@@ -79,6 +79,12 @@ namespace Hotline.FlowEngine.Workflows
         /// </summary>
         Task RecallToSendStepAsync(string workflowId, string opinion, ISessionContext current, CancellationToken cancellationToken);
 
+        /// <summary>
+        /// 特提至中心(优先派单组其次坐席)
+        /// </summary>
+        /// <returns></returns>
+        Task RecallToCenterFirstToSendAsync(string workflowId, string opinion, ISessionContext current, CancellationToken cancellationToken);
+        
         ///// <summary>
         ///// 跳转(直接将流程跳转至任意节点)
         ///// </summary>

+ 1 - 0
src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs

@@ -471,6 +471,7 @@ public abstract class StepBasicEntity : CreationEntity
             EFlowAssignType.Org => new Kv(HandlerOrgId, HandlerOrgName),
             EFlowAssignType.User => new Kv(HandlerId, HandlerName),
             EFlowAssignType.Role => new Kv(RoleId, RoleName),
+            EFlowAssignType.OrgAndRole => new Kv(RoleId, $"{HandlerOrgName} - {RoleName}"),
             _ => throw new ArgumentOutOfRangeException()
         };
     }

+ 63 - 36
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -21,6 +21,7 @@ using XF.Domain.Dependency;
 using XF.Domain.Entities;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
+using System.Reflection.Metadata;
 
 namespace Hotline.FlowEngine.Workflows
 {
@@ -111,7 +112,7 @@ namespace Hotline.FlowEngine.Workflows
 
                 //firstStep是否为end,t: 实际办理节点为startStep, 并且handlerId赋值 f: 实际办理节点为firstStep, handlerId未赋值
                 workflow.UpdateActualStepWhenHandle(startStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
-                
+
                 workflow.UpdateCurrentStepWhenHandle(startStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
 
                 var endTrace = await EndAsync(workflow, dto, firstStepDefine, startStep, current, expiredTime, cancellationToken);
@@ -458,7 +459,6 @@ namespace Hotline.FlowEngine.Workflows
 
             //var trace = await NextTraceAsync(workflow, dto, currentStep, cancellationToken);
 
-
             #endregion
 
             #region 处理流程
@@ -622,21 +622,23 @@ namespace Hotline.FlowEngine.Workflows
                 applicantOrgAreaCode, applicantOrgAreaName,
                 applicantIsCenter, dto.Opinion);
 
-			//await _workflowTraceRepository.UpdateAsync(trace, cancellationToken);
+            //await _workflowTraceRepository.UpdateAsync(trace, cancellationToken);
 
-			//如果有传入期满时间 新节点为传入的期满时间
-			if (dto.ExpiredTime.HasValue)
+            //如果有传入期满时间 新节点为传入的期满时间
+            if (dto.ExpiredTime.HasValue)
                 prevStep.StepExpiredTime = dto.ExpiredTime;
-			//退给派单组节点,需按照平均分配原则派给一个派单员 禅道299 TODO
-			if (dto.NextHandlers.Any())
-            {
-                var handle = dto.NextHandlers.FirstOrDefault();
-                prevStep.Assign(handle.UserId, handle.Username, handle.OrgId, handle.OrgName, handle.RoleId, handle.RoleName);
-			}
+            
             //复制上一个节点为待接办
             var newPrevStep =
                 await DuplicateStepWithTraceAsync(workflow, prevStep, EWorkflowTraceType.Previous, cancellationToken);
 
+            //退给派单组节点,需按照平均分配原则派给一个派单员 禅道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);
+            }
+
             //remove workflow.steps
             await _workflowStepRepository.RemoveRangeAsync(removeSteps, cancellationToken);
             //await _workflowStepRepository.RemoveNav(removeSteps)
@@ -651,7 +653,7 @@ namespace Hotline.FlowEngine.Workflows
                 workflow.SetStatusRunnable();
 
             //更新实际办理节点信息
-            workflow.UpdateActualStepWhenAssign(newPrevStep,new FlowStepHandler
+            workflow.UpdateActualStepWhenAssign(newPrevStep, new FlowStepHandler
             {
                 UserId = prevStep.HandlerId,
                 Username = prevStep.HandlerName,
@@ -839,7 +841,7 @@ namespace Hotline.FlowEngine.Workflows
                     if (step.WorkflowTrace is null)
                         throw new UserFriendlyException("未查询节点对应快照信息");
                     step.WorkflowTrace.FlowAssignType = EFlowAssignType.User;
-					step.WorkflowTrace.Assign(handler.userId, handler.username,
+                    step.WorkflowTrace.Assign(handler.userId, handler.username,
                         handler.orgId, handler.orgName, handler.roleId, handler.roleName);
                 }
             }
@@ -924,7 +926,7 @@ namespace Hotline.FlowEngine.Workflows
             CancellationToken cancellation)
         {
             return await _workflowStepRepository.Queryable()
-                .Where(d => d.WorkflowId == workflowId && d.HandlerOrgId == orgId && d.StepType != EStepType.End && d.StepType !=  EStepType.Summary)
+                .Where(d => d.WorkflowId == workflowId && d.HandlerOrgId == orgId && d.StepType != EStepType.End && d.StepType != EStepType.Summary)
                 //.Where(d => d.StepHandlers.Any(sh => sh.OrgId == orgId) && d.WorkflowId == workflowId)
                 .OrderByDescending(d => d.HandleTime)
                 .FirstAsync(cancellation);
@@ -937,13 +939,13 @@ namespace Hotline.FlowEngine.Workflows
         public async Task<WorkflowStep> FindTopHandleStepAsync(string workflowId, CancellationToken cancellation)
         {
             var workflow = await GetWorkflowAsync(workflowId, withSteps: true, cancellationToken: cancellation);
-			return workflow.Steps.FirstOrDefault(x => x.Id == workflow.TopCountersignStepId);
+            return workflow.Steps.FirstOrDefault(x => x.Id == workflow.TopCountersignStepId);
         }
 
-		/// <summary>
-		/// 查询流转方向
-		/// </summary>
-		public EFlowDirection GetFlowDirection(EBusinessType sourceStepBusinessType,
+        /// <summary>
+        /// 查询流转方向
+        /// </summary>
+        public EFlowDirection GetFlowDirection(EBusinessType sourceStepBusinessType,
             EBusinessType directionStepBusinessType)
         {
             switch (sourceStepBusinessType)
@@ -1092,7 +1094,8 @@ namespace Hotline.FlowEngine.Workflows
             var workflow = await GetWorkflowAsync(workflowId, withDefine: true, withSteps: true, withTraces: true,
                 cancellationToken: cancellationToken);
             var startStep = workflow.Steps.First(d => d.StepType == EStepType.Start);
-
+            if (startStep is null)
+                throw new UserFriendlyException($"数据异常, workflowId: {workflowId}", "该流程无开始节点");
 
             await RecallToTargetStepAsync(workflow, startStep, opinion, current, cancellationToken);
         }
@@ -1103,14 +1106,36 @@ namespace Hotline.FlowEngine.Workflows
         public async Task RecallToSendStepAsync(string workflowId, string opinion, ISessionContext current,
             CancellationToken cancellationToken)
         {
-            //todo 1.当前待办节点删掉 2.当前待办trace更新(status, opinion) 3.复制startStep为待办 4.更新workflow(status, csStatus, handlers) 5.publish event
             var workflow = await GetWorkflowAsync(workflowId, withDefine: true, withSteps: true, withTraces: true,
                 cancellationToken: cancellationToken);
-            var startStep = workflow.Steps.FirstOrDefault(d => d.BusinessType == EBusinessType.Send);
-            if (startStep is null)
+            var sendStep = workflow.Steps.FirstOrDefault(d => d.BusinessType == EBusinessType.Send);
+            if (sendStep is null)
                 throw new UserFriendlyException($"未找到派单节点, workflowId: {workflowId}", "该流程无派单节点");
 
-            await RecallToTargetStepAsync(workflow, startStep, opinion, current, cancellationToken);
+            await RecallToTargetStepAsync(workflow, sendStep, opinion, current, cancellationToken);
+        }
+
+        /// <summary>
+        /// 特提至中心(优先派单组其次坐席)
+        /// </summary>
+        /// <returns></returns>
+        public async Task RecallToCenterFirstToSendAsync(string workflowId, string opinion, ISessionContext current,
+            CancellationToken cancellationToken)
+        {
+            var workflow = await GetWorkflowAsync(workflowId, withDefine: true, withSteps: true, withTraces: true,
+                cancellationToken: cancellationToken);
+            var sendStep = workflow.Steps.FirstOrDefault(d => d.BusinessType == EBusinessType.Send);
+            if (sendStep is not null)
+            {
+                await RecallToTargetStepAsync(workflow, sendStep, opinion, current, cancellationToken);
+            }
+            else
+            {
+                var startStep = workflow.Steps.First(d => d.StepType == EStepType.Start);
+                if (startStep is null)
+                    throw new UserFriendlyException($"数据异常, workflowId: {workflowId}", "该流程无开始节点");
+                await RecallToTargetStepAsync(workflow, startStep, opinion, current, cancellationToken);
+            }
         }
 
         private async Task RecallToTargetStepAsync(Workflow workflow, WorkflowStep targetStep, string opinion, ISessionContext current,
@@ -1130,7 +1155,7 @@ namespace Hotline.FlowEngine.Workflows
             var newStartStep =
                 await DuplicateStepWithTraceAsync(workflow, targetStep, EWorkflowTraceType.Recall, cancellationToken);
 
-            workflow.UpdateActualStepWhenAssign(targetStep,new FlowStepHandler
+            workflow.UpdateActualStepWhenAssign(targetStep, new FlowStepHandler
             {
                 UserId = targetStep.HandlerId,
                 Username = targetStep.HandlerName,
@@ -1364,7 +1389,8 @@ namespace Hotline.FlowEngine.Workflows
             var steps = workflow.Traces
                 .Where(d => d.StepType is EStepType.Normal)
                 .ToList();
-            var items = steps.Where(d=> d.TraceType == EWorkflowTraceType.Normal || d.TraceType == EWorkflowTraceType.Jump).Select(d => new Kv(d.HandlerOrgId, d.HandlerOrgName))
+            var items = steps.Where(d => d.TraceType == EWorkflowTraceType.Normal || d.TraceType == EWorkflowTraceType.Jump)
+                .Select(d => new Kv(d.HandlerOrgId, d.HandlerOrgName))
                 .DistinctBy(d => d.Key).ToList();
             return (new Kv(workflow.ActualHandleOrgCode, workflow.ActualHandleOrgName), items);
         }
@@ -1500,11 +1526,11 @@ namespace Hotline.FlowEngine.Workflows
             workflow.UpdateCurrentStepWhenHandle(endStep,
                 current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
             workflow.UpdateCurrentStepAcceptTime(endStep.AcceptTime.Value);
-            
+
             //workflow.UpdateActualStepWhenHandle(endStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
             //workflow.UpdateActualStepAcceptTime(endStep.AcceptTime.Value);
 
-            if(string.IsNullOrEmpty(workflow.OrgLevelOneCode))
+            if (string.IsNullOrEmpty(workflow.OrgLevelOneCode))
                 workflow.UpdateLevelOneOrg(workflow.ActualHandleOrgCode, workflow.ActualHandleOrgName);
 
             await _workflowRepository.UpdateAsync(workflow, cancellationToken);
@@ -1612,7 +1638,7 @@ namespace Hotline.FlowEngine.Workflows
             else
             {
                 var nextHandler = dto.NextHandlers.First();
-                workflow.UpdateActualStepWhenAssign(nextSteps.First(),nextHandler);
+                workflow.UpdateActualStepWhenAssign(nextSteps.First(), nextHandler);
             }
 
             //if ( /*workflow.FlowType is EFlowType.Handle &&*/
@@ -1803,10 +1829,10 @@ namespace Hotline.FlowEngine.Workflows
 
             var handlerType = stepDefine.CountersignPolicy switch
             {
-	            EDynamicPolicyCountersign.OrgUpCenterTop => EHandlerType.OrgLevel,
-	            EDynamicPolicyCountersign.OrgUp => EHandlerType.OrgLevel,
-	            EDynamicPolicyCountersign.OrgDownCenterTop => EHandlerType.OrgLevel,
-	            EDynamicPolicyCountersign.OrgDown => EHandlerType.OrgLevel,
+                EDynamicPolicyCountersign.OrgUpCenterTop => EHandlerType.OrgLevel,
+                EDynamicPolicyCountersign.OrgUp => EHandlerType.OrgLevel,
+                EDynamicPolicyCountersign.OrgDownCenterTop => EHandlerType.OrgLevel,
+                EDynamicPolicyCountersign.OrgDown => EHandlerType.OrgLevel,
                 null => throw new ArgumentOutOfRangeException(),
                 _ => throw new ArgumentOutOfRangeException()
             };
@@ -2022,7 +2048,9 @@ namespace Hotline.FlowEngine.Workflows
             {
                 //newStep.FlowAssignType = EFlowAssignType.User;
                 // 是否中心  临时紧急修改 后续在流程模版定义是否原办理人退回类型 来实现流程 禅道200
-                newStep.FlowAssignType = step.HandlerOrgIsCenter!.Value ? step.BusinessType is EBusinessType.Send ? EFlowAssignType.User : EFlowAssignType.Role : EFlowAssignType.Org;
+                newStep.FlowAssignType = step.HandlerOrgIsCenter!.Value
+                    ? step.BusinessType is EBusinessType.Send ? EFlowAssignType.User : EFlowAssignType.Role
+                    : EFlowAssignType.Org;
                 //if (newStep is { FlowAssignType: EFlowAssignType.Role, BusinessType: EBusinessType.Send })
                 //    newStep.FlowAssignType = EFlowAssignType.User;
 
@@ -2309,7 +2337,7 @@ namespace Hotline.FlowEngine.Workflows
                     null, expiredTime, cancellationToken: cancellationToken)).First();
 
             //更新实际办理节点信息
-            workflow.UpdateActualStepWhenAssign(targetStepNew,new FlowStepHandler
+            workflow.UpdateActualStepWhenAssign(targetStepNew, new FlowStepHandler
             {
                 UserId = targetStep.HandlerId,
                 Username = targetStep.HandlerName,
@@ -2797,5 +2825,4 @@ namespace Hotline.FlowEngine.Workflows
 
         #endregion
     }
-
 }

+ 2 - 2
src/Hotline/FlowEngine/Workflows/WorkflowTrace.cs

@@ -60,12 +60,12 @@ public enum EWorkflowTraceState
     StepRemoveByPrevious = 10,
 
     /// <summary>
-    /// 对应节点因撤回被删除(工单未归档)
+    /// 对应节点因特提被删除(工单未归档)
     /// </summary>
     StepRemoveByRecall = 20,
 
     /// <summary>
-    /// 对应节点因撤回被删除(工单已归档)
+    /// 对应节点因特提被删除(工单已归档)
     /// </summary>
     StepRemoveByRecallWhenFiled = 21,
 }

+ 6 - 0
src/Hotline/Orders/Order.cs

@@ -867,6 +867,12 @@ namespace Hotline.Orders
         [SugarColumn(ColumnDescription = "工单标签")]
         public string? TagNames { get; set; }
 
+        /// <summary>
+        /// 省退回结果
+        /// </summary>
+        [SugarColumn(ColumnDescription ="省退回结果")]
+        public bool? ProvinceSendBack { get; set; }
+
         #endregion
 
         #region 附件冗余

+ 36 - 0
src/Hotline/Permissions/EPermission.cs

@@ -311,6 +311,12 @@ namespace Hotline.Permissions
         /// </summary>
         [Display(GroupName = "业务管理", Name = "申请甄别", Description = "申请甄别")]
         ApplyScreen = 200305,
+
+        /// <summary>
+        /// 修改甄别提起时限
+        /// </summary>
+        [Display(GroupName ="业务管理",Name ="修改甄别提起时限",Description = "修改甄别提起时限")]
+        ModifyScreenTimeLimit = 200309,
         #endregion
 
 
@@ -851,6 +857,25 @@ namespace Hotline.Permissions
 
         #endregion
         #endregion
+
+        #region 工单修改
+        /// <summary>
+        /// 工单修改列表
+        /// </summary>
+        [Display(GroupName ="工单修改列表",Name = "工单修改列表", Description = "工单修改列表")]
+        ModifyOrderList = 201600,
+        /// <summary>
+        /// 交办单导出
+        /// </summary>
+        [Display(GroupName ="工单修改",Name ="交办单导出",Description ="交办单导出")]
+        ModifyOrderOrderJbdExport = 201601,
+
+        /// <summary>
+        /// 工单修改
+        /// </summary>
+        [Display(GroupName ="工单修改",Name ="工单修改",Description ="工单修改")]
+        ModifyOrder = 201602,
+        #endregion
         #endregion
 
         #region 质检管理(40,00,00)
@@ -1965,6 +1990,17 @@ namespace Hotline.Permissions
         [Display(GroupName ="外部市民管理",Name ="模板下载",Description ="模板下载")]
         ExtemaiCitzenTemplateDown = 701302,
 
+        /// <summary>
+        /// 外部市民修改
+        /// </summary>
+        [Display(GroupName ="外部市民管理",Name ="外部市民修改",Description ="外部市民修改")]
+        ExtemaiCitzenModify = 701303,
+        /// <summary>
+        /// 外部市民删除
+        /// </summary>
+        [Display(GroupName ="外部市民管理",Name ="外部市民删除",Description ="外部市民删除")]
+        ExtemaiCitzenDel = 701304,
+
         #endregion
 
         #region 短信任务

+ 5 - 0
src/Hotline/Settings/SysDicTypeConsts.cs

@@ -175,6 +175,11 @@ public class SysDicTypeConsts
     /// </summary>
     public const string BulletinPushRange = "BulletinPushRange";
 
+    /// <summary>
+    /// 公告显示位置
+    /// </summary>
+    public const string BulletinDisplayLocation = "BulletinDisplayLocation";
+
     /// <summary>
     /// 通知类型
     /// </summary>

+ 120 - 1
src/Hotline/dataview.md

@@ -338,4 +338,123 @@ WHERE ordervisitdetailtemp."VisitTarget" = 20 and ordervisittemp."VisitTime">='2
  SUM(( CASE  WHEN ((( "CallDirection" = 0 ) AND ( "Duration" > 0 )) AND ( "Duration" <= 5 )) THEN 1  ELSE 0 END )) AS "ConnectByeCount" , 
  SUM(( CASE  WHEN ((( "CallDirection" = 0 ) AND ( "OnState" = 1 )) AND ( "RingTimes" <= 15 )) THEN 1  ELSE 0 END )) AS "TimelyAnswerCount"  
  FROM "tr_call_record"  WHERE (( "CreatedTime" >= '2024-09-12 17:00:00' ) AND ( "CreatedTime" <= '2024-09-13 17:00:00' ))  AND ( "Gateway" = '12333' )GROUP BY "Gateway") aaa
- 
+ 
+
+
+ ###信件清单查询(新)
+ select '' as "序号",
+aaa.信件状态,aaa."是否超期",aaa.来源,aaa.转接来源,aaa.当前节点,aaa.重办次数,aaa.甄别状态,aaa.受理编号,aaa.省编号,aaa.受理时间,aaa.标题,aaa.期满时间,aaa."一级部门",
+aaa.二级部门,aaa."接办部门",aaa."办结时间",aaa."受理类型",aaa."热点类型",aaa.热点全称,aaa."区域",aaa.区域全称,aaa."受理人",aaa."姓名",aaa."联系电话",aaa."来电电话",
+aaa."事发地址",aaa."具体对象",aaa."来电人主体",aaa."性别",ccc."SeatVisitResult" as "坐席满意度",bbb."OrgProcessingResults" as "满意度",aaa."推送分类",aaa."受理内容",
+aaa."承办意见",aaa."归档意见" from 
+(select 
+CASE "ordertemp"."Status"
+	WHEN 500 THEN '已回访'
+	WHEN 400 THEN '已发布'
+	WHEN 300 THEN '已归档'
+	WHEN 200 THEN '会签中'
+	WHEN 105 THEN '退回审批中'
+	WHEN 104 THEN '特提审批中'
+	WHEN 103 THEN '移交信件'
+	WHEN 102 THEN '退回信件'
+	WHEN 101 THEN '特提信件'
+	WHEN 100 THEN '办理中'
+	WHEN 9 THEN '退回省平台'
+	WHEN 2 THEN '特提待受理'
+	WHEN 1 THEN '退回待受理'
+	WHEN 0 THEN '待受理'
+	ELSE	'未知'
+END AS "信件状态",
+CASE 	WHEN "Status">=300 and "ExpiredTime">"FiledTime" THEN '正常'
+		  WHEN "Status">=300 AND "ExpiredTime"<"FiledTime" THEN '超期'
+			WHEN "Status"<300 AND "ExpiredTime"> now() AND now()> "NearlyExpiredTime" THEN '即将超期'
+			WHEN "Status"<300 AND "ExpiredTime">now() AND now()< "NearlyExpiredTime" THEN '正常'
+		  WHEN "Status"<300 AND "ExpiredTime"<now() THEN '超期'
+	ELSE '未知'
+END AS "是否超期",
+"SourceChannel" AS "来源" , 
+CASE 
+	WHEN "TransferPhone" is null or "TransferPhone"='undefined' THEN '12345'
+	ELSE
+		"TransferPhone"
+END AS "转接来源" ,
+"ActualHandleStepName" AS "当前节点" ,
+"ReTransactNum" AS "重办次数" , 
+(select CASE "screentemp"."Status"
+	WHEN 0 THEN '待办'
+	WHEN 1 THEN '审批中'
+	WHEN 2 THEN '审批完成'
+	WHEN 3 THEN '审批拒绝'
+	ELSE '-'
+END AS "OrderScreenStatus"
+ from order_screen screentemp WHERE "OrderId"="ordertemp"."Id" order by "CreationTime" DESC LIMIT 1) as "甄别状态", 
+"No" AS "受理编号" , 
+"ProvinceNo" AS "省编号" , 
+to_char("CreationTime", 'YYYY-MM-DD HH24:MI:SS') AS "受理时间" , 
+"Title" AS "标题" , 
+to_char("ExpiredTime", 'YYYY-MM-DD HH24:MI:SS') AS "期满时间" , 
+"OrgLevelOneName" AS "一级部门" , 
+
+CASE 
+	WHEN length("ActualHandleOrgCode")>=9 THEN
+		(select "Name" from system_organize orgtemp WHERE orgtemp."Id"="substring"("ordertemp"."ActualHandleOrgCode", 1, 9))
+	ELSE
+		'-'
+END AS "二级部门" , 
+"ActualHandleOrgName" AS "接办部门" , 
+to_char("FiledTime", 'YYYY-MM-DD HH24:MI:SS') AS "办结时间" , 
+"AcceptType" AS "受理类型" , 
+"HotspotName" AS "热点类型",
+"HotspotSpliceName" AS "热点全称",
+CASE 
+	WHEN "Town" is not NULL and "Town" <>'' THEN "Town"
+  WHEN "County" is not null and "County" <>'' THEN "County"
+	ELSE "City"
+END AS "区域",
+"Address"  As "区域全称",
+"AcceptorName" AS "受理人" ,
+ "FromName" AS "姓名" , 
+ "Contact" AS "联系电话" , 
+ "FromPhone" AS "来电电话" , 
+ "Street" AS "事发地址" ,
+ '' AS "具体对象",
+ CASE "IdentityType"
+	WHEN 1 THEN '市民'
+	WHEN 2 THEN '企业'
+	ELSE
+		'市民'
+END AS "来电人主体",
+CASE "FromGender"
+	WHEN 0 THEN '女士'
+	WHEN 1 THEN '先生'
+	ELSE '未知'
+END AS "性别" , 
+"PushType" AS "推送分类" , 
+"Content" AS "受理内容" , 
+"ActualOpinion" AS "承办意见" ,
+"FileOpinion" AS "归档意见" ,
+"Id" AS "SugarNav_Id" FROM "order" ordertemp  WHERE (( "CreationTime" >= '2024-08-29' ) AND ( "CreationTime" <= '2024-08-30' ))  AND ( "IsDeleted" = FALSE )ORDER BY "CreationTime" ASC) aaa
+left JOIN
+(select 
+ string_agg(visitdetailtemptwo."OrgProcessingResults"::JSON->>'Value','/') as "OrgProcessingResults",visittemptwo."OrderId" as "OrderId"
+from order_visit visittemptwo
+left join order_visit_detail visitdetailtemptwo on visittemptwo."Id" = visitdetailtemptwo."VisitId"
+where  visittemptwo."CreationTime">='2024-08-29' and visitdetailtemptwo."VisitTarget"=20 AND visittemptwo."VisitState"=30 group by visittemptwo."OrderId") as bbb
+on aaa."SugarNav_Id" = bbb."OrderId"
+left join
+(select string_agg(CASE visitdetailtemp."SeatEvaluate"
+	WHEN 0 THEN '默认满意'
+	WHEN 2 THEN '不满意'
+	WHEN 4 THEN '满意'
+	WHEN 5 THEN '非常满意'
+	WHEN 6 THEN '未接通'
+	WHEN 7 THEN '未做评价'
+	ELSE
+		'-'
+END, '/') AS "SeatVisitResult",visittemp."OrderId" AS "OrderId"
+ from order_visit visittemp
+left join order_visit_detail visitdetailtemp on visittemp."Id"= visitdetailtemp."VisitId"  
+where visittemp."CreationTime">='2024-08-29' and visitdetailtemp."VisitTarget"=10 AND visittemp."VisitState"=30 GROUP BY visittemp."OrderId") as "ccc"
+on aaa."SugarNav_Id" = ccc."OrderId"
+
+

+ 2 - 2
src/XF.Domain/Entities/IWorkflow.cs

@@ -78,9 +78,9 @@ public enum EFlowAssignType
     Role = 2,
 
 	/// <summary>
-	/// 指派到部门与角色
+	/// 指派到指定部门的指定角色
 	/// </summary>
-	OrgOrRole = 3,
+	OrgAndRole = 3,
 }
 
 /// <summary>