admin 1 gadu atpakaļ
vecāks
revīzija
0896553ef1
25 mainītis faili ar 736 papildinājumiem un 36 dzēšanām
  1. 71 12
      src/Hotline.Api/Controllers/OrderController.cs
  2. 60 21
      src/Hotline.Api/Controllers/PbxController.cs
  3. 1 1
      src/Hotline.Api/Controllers/TestController.cs
  4. 26 0
      src/Hotline.Application/Handlers/Order/AddVisitNotifyHandler.cs
  5. 14 0
      src/Hotline.Repository.SqlSugar/Orders/OrderPublishedRepository.cs
  6. 14 0
      src/Hotline.Repository.SqlSugar/Orders/OrderVisitedDetailRepository.cs
  7. 19 0
      src/Hotline.Repository.SqlSugar/Orders/OrderVisitedRepository.cs
  8. 59 0
      src/Hotline.Share/Dtos/Order/OrderDto.cs
  9. 48 0
      src/Hotline.Share/Enums/Order/ESeatEvaluate.cs
  10. 54 0
      src/Hotline.Share/Enums/Order/EVisitType.cs
  11. 36 0
      src/Hotline.Share/Enums/Order/EVisitedState.cs
  12. 24 0
      src/Hotline.Share/Enums/Order/EVisitedType.cs
  13. 54 0
      src/Hotline.Share/Enums/Order/EVoiceEvaluate.cs
  14. 10 0
      src/Hotline/CallCenter/Tels/ITelDomainService.cs
  15. 19 0
      src/Hotline/CallCenter/Tels/TelDomainService.cs
  16. 1 1
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  17. 8 0
      src/Hotline/Orders/IOrderPublishedRepository.cs
  18. 13 0
      src/Hotline/Orders/IOrderVisitedDetailRepository.cs
  19. 8 0
      src/Hotline/Orders/IOrderVisitedRepository.cs
  20. 16 0
      src/Hotline/Orders/Notifications/AddVisitNotify.cs
  21. 10 0
      src/Hotline/Orders/OrderPublished.cs
  22. 63 1
      src/Hotline/Orders/OrderVisited.cs
  23. 66 0
      src/Hotline/Orders/OrderVisitedDetail.cs
  24. 21 0
      src/Hotline/Permissions/EPermission.cs
  25. 21 0
      src/XF.Domain/Constants/SettingConstants.cs

+ 71 - 12
src/Hotline.Api/Controllers/OrderController.cs

@@ -46,6 +46,8 @@ public class OrderController : BaseController
     private readonly ISessionContext _sessionContext;
     private readonly IMapper _mapper;
     private readonly IMediator _mediator;
+    private readonly IOrderPublishedRepository _orderPublishedRepository;
+
 
     public OrderController(
         IOrderDomainService orderDomainService,
@@ -59,7 +61,8 @@ public class OrderController : BaseController
         ISysDicDataCacheManager sysDicDataCacheManager,
         ISessionContext sessionContext,
         IMapper mapper,
-        IMediator mediator)
+        IMediator mediator,
+        IOrderPublishedRepository orderPublishedRepository)
     {
         _orderDomainService = orderDomainService;
         _orderRepository = orderRepository;
@@ -73,6 +76,7 @@ public class OrderController : BaseController
         _sessionContext = sessionContext;
         _mapper = mapper;
         _mediator = mediator;
+        _orderPublishedRepository = orderPublishedRepository;
     }
 
     /// <summary>
@@ -80,12 +84,14 @@ public class OrderController : BaseController
     /// </summary>
     /// <param name="dto"></param>
     /// <returns></returns>
+    [Permission(EPermission.PublishOrderList)]
     [HttpGet("publish-order-list")]
     public async Task<PagedDto<PublishDto>> PublishOrderList([FromQuery] QueryOrderPublishDto dto)
     {
         var (total, items) = await _orderRepository.Queryable()
             .Includes(d => d.OrderPublished)
             .Includes(d => d.Employee)
+            .Where(x=>x.Status == EOrderStatus.Filed)
             .WhereIF(!string.IsNullOrEmpty(dto.OrderTitle), d => d.Title.Contains(dto.OrderTitle!))
             .WhereIF(dto.PubState == EPubState.Pub, d => d.Progress == EProgress.Published || d.Progress == EProgress.Visited)
             .WhereIF(dto.PubState == EPubState.NoPub, d => d.Progress == EProgress.Managing)
@@ -103,17 +109,70 @@ public class OrderController : BaseController
         return new PagedDto<PublishDto>(total, _mapper.Map<IReadOnlyList<PublishDto>>(items));
     }
 
-    ///// <summary>
-    ///// 发布工单
-    ///// </summary>
-    ///// <returns></returns>
-    //[HttpPost("publish-order")]
-    //public async Task PublishOrder([FromBody]PublishOrderDto dto)
-    //{
-    //    OrderPublished orderPublished = new OrderPublished();
-    //    orderPublished.PublishState = dto.PublishState;
-    //    orderPublished.ArrangeContent = dto.ArrangeContent;
-    //}
+    /// <summary>
+    /// 发布工单
+    /// </summary>
+    /// <returns></returns>
+    [Permission(EPermission.PublishOrder)]
+    [HttpPost("publish-order")]
+    public async Task PublishOrder([FromBody] PublishOrderDto dto)
+    {
+        //验证订单
+        var order = await _orderRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
+
+        if (order is null)
+            throw UserFriendlyException.SameMessage("未找到工单,无法发布");
+
+        //新增发布工单
+        OrderPublished orderPublished = new OrderPublished();
+        orderPublished.No = order.No;
+        orderPublished.PublishState = dto.PublishState;
+        orderPublished.ArrangeTitle = dto.ArrangeTitle;
+        orderPublished.ArrangeContent = dto.ArrangeContent;
+        orderPublished.ArrangeOpinion = dto.ArrangeOpinion;
+        string id = await _orderPublishedRepository.AddAsync(orderPublished);
+        //新增回访信息
+        var visitedDetail = new List<OrderVisitedDetail>();
+
+        var seatDetail = new OrderVisitedDetail();
+        seatDetail.VisitedId = id;
+        seatDetail.VisitedType = EVisitedType.Seat;
+
+        visitedDetail.Add(seatDetail);
+
+        foreach (var item in dto.IdNames)
+        {
+            var orgDetail = new OrderVisitedDetail();
+            orgDetail.VisitedId = id;
+            orgDetail.VisitOrgCode = item.Id;
+            orgDetail.VisitOrgName = item.Name;
+            visitedDetail.Add(orgDetail);
+        }
+        await _mediator.Publish(new AddVisitNotify(visitedDetail), HttpContext.RequestAborted);
+    }
+
+    /// <summary>
+    /// 发布页面基础信息
+    /// </summary>
+    /// <returns></returns>
+    [Permission(EPermission.PublishOrderPageBase)]
+    [HttpGet("publish-order-pagebase/{id}")]
+    public async Task<PublishOrderPageBaseDto> PublishOrderPageBase(string id)
+    {
+        var order = await _orderRepository.Queryable()
+            .Includes(d => d.Employee)
+            .Includes(d => d.OrderComplain)
+            .FirstAsync(d => d.Id == id);
+
+        if (order is null)
+            throw UserFriendlyException.SameMessage("未知工单,无法发布");
+
+        var res = new PublishOrderPageBaseDto() { Source = order.Source, OrderTitle = order.Title, Content = order.Content, ActualOpinion = order.ActualOpinion };
+        var (idName,idNames)  = await _workflowDomainService.GetNoVisiteOrgsAsync(order.WorkflowId, HttpContext.RequestAborted);
+        res.ActualHandleOrgName = idName;
+        res.idNames = idNames.ToList();
+        return res;
+    }
 
     /// <summary>
     /// 工单列表

+ 60 - 21
src/Hotline.Api/Controllers/PbxController.cs

@@ -18,6 +18,8 @@ using Microsoft.AspNetCore.Mvc;
 using Org.BouncyCastle.Asn1.Ocsp;
 using SqlSugar;
 using System.Threading;
+using Wex.Sdk;
+using Wex.Sdk.Tel;
 using XF.Domain.Authentications;
 using XF.Domain.Cache;
 using XF.Domain.Constants;
@@ -52,6 +54,7 @@ namespace Hotline.Api.Controllers
         private readonly ILogger<TelController> _logger;
         private readonly ICallDetailRepository _callDetailRepository;
         private readonly IUserRepository _userRepository;
+        private readonly IWexClient _wexClient;
 
         public PbxController(
             ITelRepository telRepository,
@@ -74,7 +77,8 @@ namespace Hotline.Api.Controllers
             IIvrCacheManager ivrCacheManager,
             ILogger<TelController> logger,
             ICallDetailRepository callDetailRepository,
-            IUserRepository userRepository)
+            IUserRepository userRepository,
+            IWexClient wexClient)
         {
             _telRepository = telRepository;
             _telRestRepository = telRestRepository;
@@ -97,6 +101,7 @@ namespace Hotline.Api.Controllers
             _logger = logger;
             _callDetailRepository = callDetailRepository;
             _userRepository = userRepository;
+            _wexClient = wexClient;
         }
 
         #region 话机
@@ -278,6 +283,8 @@ namespace Hotline.Api.Controllers
             }
         }
 
+        #region 威尔信
+
         /// <summary>
         /// 分机休息流程开始
         /// </summary>
@@ -287,20 +294,22 @@ namespace Hotline.Api.Controllers
         [HttpPost("rest-flow")]
         public async Task RestFlow([FromBody] StartRestDto dto)
         {
-            //TODO
-            
-            var isApply = await _telRepository.IsApplyingAsync("8029", HttpContext.RequestAborted);
+            var tel = await _wexClient.QueryTelsAsync(new QueryTelRequest() { StaffNo = _sessionContext.StaffNo },HttpContext.RequestAborted);
+            if (tel.Data == null || tel.Data.Count == 0)
+                throw UserFriendlyException.SameMessage("未找到分机信息");
+
+            if (tel.Data[0].Sigin == 0)
+                throw UserFriendlyException.SameMessage("分机未签入,不能休息");
+
+            var isApply = await _telRepository.IsApplyingAsync(tel.Data[0].TelNo, HttpContext.RequestAborted);
             if (isApply)
-                throw  UserFriendlyException.SameMessage("分机休息申请正在审核阶段");
+                throw UserFriendlyException.SameMessage("分机休息申请正在审核阶段");
 
-            //TODO
-            var isResting = await _telRepository.IsRestingAsync("8029", HttpContext.RequestAborted);
+            var isResting = await _telRepository.IsRestingAsync(tel.Data[0].TelNo, HttpContext.RequestAborted);
             if (isResting)
                 throw new UserFriendlyException("当前坐席正在休息");
 
-            var user = _userRepository.Get(_sessionContext.RequiredUserId);
-            //TODO
-            var telRest = new TelRest("5f7099aa-ef27-48bd-959f-13ccc5a1dc1b", "8029", _sessionContext.RequiredUserId, _sessionContext.UserName, dto.Reason, true, user.StaffNo);
+            var telRest = new TelRest(tel.Data[0].TelNo, tel.Data[0].TelNo, _sessionContext.RequiredUserId, _sessionContext.UserName, dto.Reason, true, _sessionContext.StaffNo);
             await _telRestRepository.AddAsync(telRest, HttpContext.RequestAborted);
 
             var startWorkflowDto = _mapper.Map<StartWorkflowDto>(dto);
@@ -319,8 +328,15 @@ namespace Hotline.Api.Controllers
         [HttpGet("begin-rest")]
         public async Task BeginRest()
         {
-            //TODO
-            var telRest = await _telRestRepository.GetAsync(x => !x.EndTime.HasValue && !x.StartTime.HasValue  && x.TelNo == "8029",HttpContext.RequestAborted);
+            var tel = await _wexClient.QueryTelsAsync(new QueryTelRequest() { StaffNo = _sessionContext.StaffNo }, HttpContext.RequestAborted);
+
+            if (tel.Data == null || tel.Data.Count == 0)
+                throw UserFriendlyException.SameMessage("未找到分机信息");
+
+            if (tel.Data[0].Sigin == 0)
+                throw UserFriendlyException.SameMessage("分机未签入,不能休息");
+
+            var telRest = await _telRestRepository.GetAsync(x => !x.EndTime.HasValue && !x.StartTime.HasValue && x.TelNo == tel.Data[0].TelNo, HttpContext.RequestAborted);
 
             if (telRest == null)
                 throw new UserFriendlyException($"错误");
@@ -346,9 +362,15 @@ namespace Hotline.Api.Controllers
         [HttpPost("rest-add")]
         public async Task Rest([FromBody] ResstDto dto)
         {
-            var user = _userRepository.Get(_sessionContext.RequiredUserId);
-            //TODO
-            var telRest = new TelRest("5f7099aa-ef27-48bd-959f-13ccc5a1dc1b", "8029", _sessionContext.RequiredUserId, _sessionContext.UserName, dto.Reason, false, user.StaffNo);
+            var tel = await _wexClient.QueryTelsAsync(new QueryTelRequest() { StaffNo = _sessionContext.StaffNo }, HttpContext.RequestAborted);
+
+            if (tel.Data == null || tel.Data.Count == 0)
+                throw UserFriendlyException.SameMessage("未找到分机信息");
+
+            if (tel.Data[0].Sigin == 0)
+                throw UserFriendlyException.SameMessage("分机未签入,不能休息");
+
+            var telRest = new TelRest("5f7099aa-ef27-48bd-959f-13ccc5a1dc1b", "8029", _sessionContext.RequiredUserId, _sessionContext.UserName, dto.Reason, false, _sessionContext.StaffNo);
             await _telRestRepository.AddAsync(telRest, HttpContext.RequestAborted);
         }
 
@@ -361,25 +383,42 @@ namespace Hotline.Api.Controllers
         [HttpGet("rest-del")]
         public async Task DelRest()
         {
-            //TODO
-            var restingTel = await _telRestRepository.GetAsync(d => d.TelId == "5f7099aa-ef27-48bd-959f-13ccc5a1dc1b" && !d.EndTime.HasValue, HttpContext.RequestAborted);
+            var tel = await _wexClient.QueryTelsAsync(new QueryTelRequest() { StaffNo = _sessionContext.StaffNo }, HttpContext.RequestAborted);
+
+            if (tel.Data == null || tel.Data.Count == 0)
+                throw UserFriendlyException.SameMessage("未找到分机信息");
+
+            if (tel.Data[0].Sigin == 0)
+                throw UserFriendlyException.SameMessage("分机未签入,不能休息");
+
+            var restingTel = await _telRestRepository.GetAsync(d => d.TelId == tel.Data[0].TelNo && !d.EndTime.HasValue, HttpContext.RequestAborted);
             if (restingTel is null)
                 throw new UserFriendlyException("未查询到分机休息信息");
-            await _telRestRepository.RemoveAsync(restingTel.Id,false,HttpContext.RequestAborted);
+            await _telRestRepository.RemoveAsync(restingTel.Id, false, HttpContext.RequestAborted);
         }
 
         /// <summary>
-        /// 分机结束休息
+        /// 分机结束休息(威尔信)
         /// </summary>
         /// <returns></returns>
         [Permission(EPermission.UnRest)]
         [HttpGet("un-rest-wex")]
         public async Task<TelRestDto> UnRestWEX()
         {
-            var telRest = await _telDomainService.UnRestAsync("5f7099aa-ef27-48bd-959f-13ccc5a1dc1b", HttpContext.RequestAborted);
+            var tel = await _wexClient.QueryTelsAsync(new QueryTelRequest() { StaffNo = _sessionContext.StaffNo }, HttpContext.RequestAborted);
+
+            if (tel.Data == null || tel.Data.Count == 0)
+                throw UserFriendlyException.SameMessage("未找到分机信息");
+
+            if (tel.Data[0].Sigin == 0)
+                throw UserFriendlyException.SameMessage("分机未签入,不能休息");
+
+            var telRest = await _telDomainService.UnRestWexAsync(tel.Data[0].TelNo, HttpContext.RequestAborted);
             return _mapper.Map<TelRestDto>(telRest);
         }
-        
+
+        #endregion
+
 
 
         /// <summary>

+ 1 - 1
src/Hotline.Api/Controllers/TestController.cs

@@ -103,7 +103,7 @@ public class TestController : BaseController
     [HttpGet("time")]
     public async Task<string> GetTime()
     {
-        var rsp = await _wexClient.QueryTelsAsync(new QueryTelRequest { StaffNo = "10086" }, HttpContext.RequestAborted);
+        //var rsp = await _wexClient.QueryTelsAsync(new QueryTelRequest { StaffNo = "10086" }, HttpContext.RequestAborted);
 
         //return DateTime.Now.ToString("F");
 

+ 26 - 0
src/Hotline.Application/Handlers/Order/AddVisitNotifyHandler.cs

@@ -0,0 +1,26 @@
+using Hotline.Orders;
+using Hotline.Orders.Notifications;
+using MediatR;
+
+
+namespace Hotline.Application.Handlers.Order
+{
+    public class AddVisitNotifyHandler : INotificationHandler<AddVisitNotify>
+    {
+
+
+        private readonly IOrderVisitedRepository _orderVisitedRepository;
+        private readonly IOrderVisitedDetailRepository _orderVisitedDetailRepository;
+        public AddVisitNotifyHandler(IOrderVisitedRepository orderVisitedRepository,IOrderVisitedDetailRepository orderVisitedDetailRepository)
+        {
+            _orderVisitedRepository = orderVisitedRepository;
+            _orderVisitedDetailRepository = orderVisitedDetailRepository;
+        }
+
+
+        public async Task Handle(AddVisitNotify notification, CancellationToken cancellationToken)
+        {
+            await _orderVisitedDetailRepository.AddRangeAsync(notification.OrderVisitedDetails, cancellationToken);
+        }
+    }
+}

+ 14 - 0
src/Hotline.Repository.SqlSugar/Orders/OrderPublishedRepository.cs

@@ -0,0 +1,14 @@
+using Hotline.Orders;
+using Hotline.Repository.SqlSugar.DataPermissions;
+using SqlSugar;
+using XF.Domain.Dependency;
+
+namespace Hotline.Repository.SqlSugar.Orders
+{
+    public class OrderPublishedRepository : BaseRepository<OrderPublished>, IOrderPublishedRepository, IScopeDependency
+    {
+        public OrderPublishedRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder) : base(uow, dataPermissionFilterBuilder)
+        {
+        }
+    }
+}

+ 14 - 0
src/Hotline.Repository.SqlSugar/Orders/OrderVisitedDetailRepository.cs

@@ -0,0 +1,14 @@
+using Hotline.Orders;
+using Hotline.Repository.SqlSugar.DataPermissions;
+using SqlSugar;
+using XF.Domain.Dependency;
+
+namespace Hotline.Repository.SqlSugar.Orders
+{
+    public class OrderVisitedDetailRepository : BaseRepository<OrderVisitedDetail>, IOrderVisitedDetailRepository, IScopeDependency
+    {
+        public OrderVisitedDetailRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder) : base(uow, dataPermissionFilterBuilder)
+        {
+        }
+    }
+}

+ 19 - 0
src/Hotline.Repository.SqlSugar/Orders/OrderVisitedRepository.cs

@@ -0,0 +1,19 @@
+using Hotline.Orders;
+using Hotline.Repository.SqlSugar.DataPermissions;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+
+namespace Hotline.Repository.SqlSugar.Orders
+{
+    public class OrderVisitedRepository : BaseRepository<OrderVisited>, IOrderVisitedRepository, IScopeDependency
+    {
+        public OrderVisitedRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder) : base(uow, dataPermissionFilterBuilder)
+        {
+        }
+    }
+}

+ 59 - 0
src/Hotline.Share/Dtos/Order/OrderDto.cs

@@ -336,12 +336,71 @@ namespace Hotline.Share.Dtos.Order
         public string ArrangeContent { get; set; }
     }
 
+    public class PublishOrderPageBaseDto
+    {
+        /// <summary>
+        /// 来源 0:热线平台  1:省平台 2:110
+        /// </summary>
+        public ESource Source { get; set; }
+
+        /// <summary>
+        /// 工单标题
+        /// </summary>
+        public string OrderTitle { get; set; }
+
+        /// <summary>
+        /// 工单内容
+        /// </summary>
+        public string Content { get; set; }
+
+        /// <summary>
+        /// 办理结果
+        /// </summary>
+        public string ActualOpinion { get; set; }
+
+        /// <summary>
+        /// 实际办理部门名称
+        /// </summary>
+        public IdName ActualHandleOrgName { get; set; }
+
+        /// <summary>
+        /// 需回访部门
+        /// </summary>
+        public List<IdName>? idNames { get; set; }
+    }
+
+
+
     public class PublishOrderDto
     {
+        /// <summary>
+        /// 工单ID
+        /// </summary>
         public string Id { get; set; }
 
+        /// <summary>
+        /// 发布范围
+        /// </summary>
         public EPublishState PublishState { get; set; }
 
+        /// <summary>
+        /// 整理标题
+        /// </summary>
+        public string ArrangeTitle { get; set; }
+
+        /// <summary>
+        /// 整理内容
+        /// </summary>
         public string ArrangeContent { get; set; }
+
+        /// <summary>
+        /// 整理结果
+        /// </summary>
+        public string ArrangeOpinion { get; set; }
+
+        /// <summary>
+        /// 需回访部门
+        /// </summary>
+        public List<IdName> IdNames { get; set; }
     }
 }

+ 48 - 0
src/Hotline.Share/Enums/Order/ESeatEvaluate.cs

@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Enums.Order
+{
+    public enum ESeatEvaluate
+    {
+        /// <summary>
+        /// 非常满意
+        /// </summary>
+        [Description("非常满意")]
+        VerySatisfied = 10,
+
+        /// <summary>
+        /// 满意
+        /// </summary>
+        [Description("满意")]
+        Satisfied = 20,
+
+        /// <summary>
+        /// 一般
+        /// </summary>
+        [Description("一般")]
+        Normal = 40,
+
+        /// <summary>
+        /// 不满意
+        /// </summary>
+        [Description("不满意")]
+        NoSatisfied = 50,
+
+        /// <summary>
+        /// 非常不满意
+        /// </summary>
+        [Description("非常不满意")]
+        VeryNoSatisfied = 60,
+
+        /// <summary>
+        /// 未做评价
+        /// </summary>
+        [Description("未做评价")]
+        NoEvaluate = 100,
+    }
+}

+ 54 - 0
src/Hotline.Share/Enums/Order/EVisitType.cs

@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Enums.Order
+{
+    public enum EVisitType
+    {
+        /// <summary>
+        /// 人工回访
+        /// </summary>
+        [Description("人工回访")]
+        ArtificialVisit = 10,
+
+        /// <summary>
+        /// 智能语音回访
+        /// </summary>
+        [Description("智能语音回访")]
+        ChipVoiceVisit = 20,
+
+        /// <summary>
+        /// 短信回访
+        /// </summary>
+        [Description("短信回访")]
+        SmsVisit = 30,
+
+        /// <summary>
+        /// 网站回访
+        /// </summary>
+        [Description("网站回访")]
+        WebVisit = 40,
+
+        /// <summary>
+        /// App回访
+        /// </summary>
+        [Description("App回访")]
+        AppVisit = 50,
+
+        /// <summary>
+        /// 微信回访
+        /// </summary>
+        [Description("微信回访")]
+        WeChatVisit = 60,
+
+        /// <summary>
+        /// 其他
+        /// </summary>
+        [Description("其他")]
+        OtherVisit = 100,
+    }
+}

+ 36 - 0
src/Hotline.Share/Enums/Order/EVisitedState.cs

@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Enums.Order
+{
+    public enum EVisitedState
+    {
+        /// <summary>
+        /// 待回访
+        /// </summary>
+        [Description("待回访")]
+        WaitForVisit = 10,
+
+        /// <summary>
+        /// 回访中
+        /// </summary>
+        [Description("回访中")]
+        Visiting = 20,
+
+        /// <summary>
+        /// 已回访
+        /// </summary>
+        [Description("已回访")]
+        Visited = 30,
+
+        /// <summary>
+        /// 不满意待回访
+        /// </summary>
+        [Description("不满意待回访")]
+        NoSatisfiedWaitForVisit =40,
+    }
+}

+ 24 - 0
src/Hotline.Share/Enums/Order/EVisitedType.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Enums.Order
+{
+    public enum EVisitedType
+    {
+        /// <summary>
+        /// 话务员
+        /// </summary>
+        [Description("话务员")]
+        Seat = 10,
+
+        /// <summary>
+        /// 部门
+        /// </summary>
+        [Description("部门")]
+        Org = 20,
+    }
+}

+ 54 - 0
src/Hotline.Share/Enums/Order/EVoiceEvaluate.cs

@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Enums.Order
+{
+    public enum EVoiceEvaluate
+    {
+        /// <summary>
+        /// 非常满意
+        /// </summary>
+        [Description("非常满意")]
+        VerySatisfied = 10,
+
+        /// <summary>
+        /// 满意
+        /// </summary>
+        [Description("满意")]
+        Satisfied = 20,
+
+        /// <summary>
+        /// 甄别为满意
+        /// </summary>
+        [Description("甄别为满意")]
+        ScreenToSatisfied = 30,
+
+        /// <summary>
+        /// 一般
+        /// </summary>
+        [Description("一般")]
+        Normal = 40,
+
+        /// <summary>
+        /// 不满意
+        /// </summary>
+        [Description("不满意")]
+        NoSatisfied = 50,
+
+        /// <summary>
+        /// 非常不满意
+        /// </summary>
+        [Description("非常不满意")]
+        VeryNoSatisfied = 60,
+
+        /// <summary>
+        /// 未做评价
+        /// </summary>
+        [Description("未做评价")]
+        NoEvaluate = 100,
+    }
+}

+ 10 - 0
src/Hotline/CallCenter/Tels/ITelDomainService.cs

@@ -68,6 +68,16 @@ namespace Hotline.CallCenter.Tels
         /// <returns></returns>
         Task TelRestApplyPassNewAsync(string? id, CancellationToken cancellationToken);
 
+
+        /// <summary>
+        /// 分机结束休息(威尔信)
+        /// </summary>
+        /// <param name="telNo"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        Task<TelRest> UnRestWexAsync(string telNo, CancellationToken cancellationToken);
+
+
         /// <summary>
         /// 分机结束休息
         /// </summary>

+ 19 - 0
src/Hotline/CallCenter/Tels/TelDomainService.cs

@@ -9,6 +9,7 @@ using XF.Domain.Exceptions;
 using Hotline.Share.Enums.CallCenter;
 using Hotline.Caching.Interfaces;
 using Microsoft.Extensions.Options;
+using Hotline.Share.Dtos.CallCenter;
 
 namespace Hotline.CallCenter.Tels;
 
@@ -146,6 +147,24 @@ public class TelDomainService : ITelDomainService, IScopeDependency
 
     }
 
+
+    /// <summary>
+    /// 分机结束休息(威尔信)
+    /// </summary>
+    /// <param name="telNo"></param>
+    /// <param name="cancellationToken"></param>
+    /// <returns></returns>
+    public async Task<TelRest> UnRestWexAsync(string telNo, CancellationToken cancellationToken)
+    {
+        var restingTel = await _telRestRepository.GetAsync(d => d.TelId == telNo && !d.EndTime.HasValue, cancellationToken);
+        if (restingTel is null)
+            throw UserFriendlyException.SameMessage("未查询到分机休息信息");
+        restingTel.EndRest();
+        await _telRestRepository.UpdateAsync(restingTel, cancellationToken);
+        return restingTel;
+    }
+
+
     /// <summary>
     /// 分机结束休息
     /// </summary>

+ 1 - 1
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -611,7 +611,7 @@ namespace Hotline.FlowEngine.Workflows
         {
             var workflow = await GetWorkflowAsync(workflowId, withSteps: true, cancellationToken: cancellationToken);
             if (workflow.CounterSignType is not ECounterSignType.Center)
-                return new(new IdName(), new List<IdName>());
+                return new(new IdName(workflow.ActualHandleOrgCode, workflow.ActualHandleOrgName), new List<IdName>());
             var steps = workflow.StepBoxes
                 .Where(d => d.StepType is EStepType.Normal && d.BusinessProperty is EBusinessProperty.Department)
                 .SelectMany(d => d.Steps)

+ 8 - 0
src/Hotline/Orders/IOrderPublishedRepository.cs

@@ -0,0 +1,8 @@
+using XF.Domain.Repository;
+
+namespace Hotline.Orders
+{
+    public interface IOrderPublishedRepository: IRepository<OrderPublished>
+    {
+    }
+}

+ 13 - 0
src/Hotline/Orders/IOrderVisitedDetailRepository.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Orders
+{
+    public interface IOrderVisitedDetailRepository: IRepository<OrderVisitedDetail>
+    {
+    }
+}

+ 8 - 0
src/Hotline/Orders/IOrderVisitedRepository.cs

@@ -0,0 +1,8 @@
+using XF.Domain.Repository;
+
+namespace Hotline.Orders
+{
+    public interface IOrderVisitedRepository: IRepository<OrderVisited>
+    {
+    }
+}

+ 16 - 0
src/Hotline/Orders/Notifications/AddVisitNotify.cs

@@ -0,0 +1,16 @@
+using MediatR;
+
+
+namespace Hotline.Orders.Notifications
+{
+    public class AddVisitNotify:INotification
+    {
+        public AddVisitNotify(List<OrderVisitedDetail> orderVisitedDetails)
+        {
+            OrderVisitedDetails = orderVisitedDetails;
+        }
+
+
+        public List<OrderVisitedDetail> OrderVisitedDetails { get; set; }
+    }
+}

+ 10 - 0
src/Hotline/Orders/OrderPublished.cs

@@ -19,12 +19,22 @@ public class OrderPublished : CreationEntity
     /// </summary>
     public EPublishState PublishState { get; set; }
 
+    /// <summary>
+    /// 整理标题
+    /// </summary>
+    public string ArrangeTitle { get; set; }
+
     /// <summary>
     /// 整理内容
     /// </summary>
     [SugarColumn(ColumnDataType = "varchar(2000)")]
     public string ArrangeContent { get; set; }
 
+    /// <summary>
+    /// 整理结果
+    /// </summary>
+    public string ArrangeOpinion { get; set; }
+
     /// <summary>
     /// 已发布工单
     /// </summary>

+ 63 - 1
src/Hotline/Orders/OrderVisited.cs

@@ -1,4 +1,7 @@
-using XF.Domain.Repository;
+using Hotline.Share.Enums.Order;
+using Hotline.Users;
+using SqlSugar;
+using XF.Domain.Repository;
 
 namespace Hotline.Orders;
 
@@ -11,4 +14,63 @@ public class OrderVisited : CreationEntity
     /// 工单编码(冗余)
     /// </summary>
     public string No { get; set; }
+
+    /// <summary>
+    /// 工单ID
+    /// </summary>
+    public string OrderId { get; set; }
+
+    /// <summary>
+    /// 工单
+    /// </summary>
+    [Navigate(NavigateType.OneToOne,nameof(OrderId))]
+    public Order Order { get; set; }
+
+    /// <summary>
+    /// 回访状态
+    /// </summary>
+    public EVisitedState VisitedState { get; set; }
+
+    /// <summary>
+    /// 回访方式
+    /// </summary>
+    [SugarColumn(IsNullable = true)]
+    public EVisitType? VisitType { get; set; }
+    
+
+    /// <summary>
+    /// 发布时间
+    /// </summary>
+    public DateTime PublishTime { get; set; }
+
+    /// <summary>
+    /// 回访人
+    /// </summary>
+    [SugarColumn(IsNullable = true)]
+    public string EmployeeId { get; set; }
+
+    /// <summary>
+    /// 回访人(对象)
+    /// </summary>
+    [Navigate(NavigateType.OneToOne, nameof(EmployeeId))]
+    public User Employee { get; set; }
+
+    /// <summary>
+    /// 是否接通
+    /// </summary>
+    [SugarColumn(IsNullable = true)]
+    public bool? IsPutThrough { get; set; }
+
+    /// <summary>
+    /// 回访时间
+    /// </summary>
+    [SugarColumn(IsNullable = true)]
+    public DateTime? VisitTime { get; set; }
+
+
+    /// <summary>
+    /// 回访明细
+    /// </summary>
+    public List<OrderVisitedDetail>? VisitedDetail { get; set; }
+
 }

+ 66 - 0
src/Hotline/Orders/OrderVisitedDetail.cs

@@ -0,0 +1,66 @@
+using Hotline.Share.Enums.Order;
+using SqlSugar;
+using XF.Domain.Repository;
+
+namespace Hotline.Orders
+{
+    public class OrderVisitedDetail: CreationEntity
+    {
+
+        /// <summary>
+        /// 回访主表ID
+        /// </summary>
+        public string VisitedId { get; set; }
+
+        /// <summary>
+        /// 语音评价(话务评价)
+        /// </summary>
+        public EVoiceEvaluate? VoiceEvaluate { get; set; }
+
+        /// <summary>
+        /// 话务员评价(话务评价)
+        /// </summary>
+        public ESeatEvaluate? SeatEvaluate { get; set; }
+
+        /// <summary>
+        /// 部门办件结果
+        /// </summary>
+        [SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
+        public string OrgProcessingResults { get; set; }
+
+        /// <summary>
+        /// 不满意原因
+        /// </summary>
+        [SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
+        public string OrgNoSatisfiedReason { get; set; }
+
+        /// <summary>
+        /// 部门办件态度
+        /// </summary>
+        [SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
+        public string OrgHandledAttitude { get; set; }
+
+        /// <summary>
+        /// 回访内容
+        /// </summary>
+        [SugarColumn(IsNullable = true)]
+        public string VisitContent { get; set; }
+
+        /// <summary>
+        /// 回访部门ID
+        /// </summary>
+        [SugarColumn(IsNullable = true)]
+        public string VisitOrgCode { get; set; }
+
+        /// <summary>
+        /// 回访部门名称
+        /// </summary>
+        [SugarColumn(IsNullable = true)]
+        public string VisitOrgName { get; set; }
+
+        /// <summary>
+        /// 回访对象类型 10:话务员 20:部门
+        /// </summary>
+        public EVisitedType VisitedType { get; set; }
+    }
+}

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

@@ -849,6 +849,27 @@ namespace Hotline.Permissions
         GetOrder = 500106,
         #endregion
 
+
+        #region 发布管理
+        /// <summary>
+        /// 发布管理列表
+        /// </summary>
+        [Display(GroupName = "OrderPublish",Name ="发布管理列表",Description ="发布管理列表")]
+        PublishOrderList = 500200,
+
+        /// <summary>
+        /// 发布页面基础信息
+        /// </summary>
+        [Display(GroupName = "OrderPublish",Name ="发布页面基础信息",Description ="发布页面基础信息")]
+        PublishOrderPageBase = 500201,
+
+        /// <summary>
+        /// 发布工单
+        /// </summary>
+        [Display(GroupName = "OrderPublish",Name ="发布工单",Description ="发布工单")]
+        PublishOrder= 500202,
+        #endregion
+
         #endregion
 
         #region 公用(999)

+ 21 - 0
src/XF.Domain/Constants/SettingConstants.cs

@@ -25,5 +25,26 @@ namespace XF.Domain.Constants
         /// 系统名称
         /// </summary>
         public const string SysName = "SysName";
+
+        /// <summary>
+        /// 是否通话后挂起
+        /// </summary>
+        public const string IsAutoTalkingDeal = "IsAutoTalkingDeal";
+
+        /// <summary>
+        /// 通话后挂起时间
+        /// </summary>
+        public const string TalkingDealTime = "TalkingDealTime";
+
+        /// <summary>
+        /// 中心节假日工作时间
+        /// </summary>
+        public const string CallCenterWorkTime = "CallCenterWorkTime";
+
+        /// <summary>
+        /// 工作日工作时间
+        /// </summary>
+        public const string WorkTime = "WorkTime";
+
     }
 }