Dun.Jason 10 ヶ月 前
コミット
418c02de02

+ 72 - 3
src/Hotline.Api/Controllers/OrderController.cs

@@ -44,6 +44,7 @@ using MapsterMapper;
 using MediatR;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
+using Microsoft.OpenApi.Writers;
 using MiniExcelLibs;
 using NPOI.SS.Formula.Functions;
 using NPOI.SS.Util;
@@ -399,6 +400,7 @@ public class OrderController : BaseController
         orderVisit.VisitState = EVisitState.WaitForVisit;
         orderVisit.PublishTime = DateTime.Now;
         orderVisit.IsCanHandle = true;
+        orderVisit.EmployeeId = _sessionContext.RequiredUserId;
 
         if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null })
         {
@@ -640,8 +642,6 @@ public class OrderController : BaseController
         return rsp;
     }
 
-
-
     /// <summary>
     /// 回访详情
     /// </summary>
@@ -720,7 +720,6 @@ public class OrderController : BaseController
         return new PagedDto<OrderVisitDetailDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDetailDto>>(items));
     }
 
-
     /// <summary>
     /// 回访保存
     /// </summary>
@@ -769,7 +768,13 @@ public class OrderController : BaseController
         {
             visit.Order.Visited(first.OrgProcessingResults.Key, first.OrgProcessingResults.Value);
         }
+        visit.OrgJudge = dto.OrgJudge;
+        visit.SeatJudge = dto.SeatJudge;
 
+        if (visit.OrgJudge==true || visit.SeatJudge==true)
+        {
+            visit.JudgeState = EJudgeState.Judging;
+        }
         //_mapper.Map(dto.VisitDetails,visit.OrderVisitDetails);
         for (int i = 0; i < visit.OrderVisitDetails.Count; i++)
         {
@@ -834,6 +839,70 @@ public class OrderController : BaseController
         //}
     }
 
+    /// <summary>
+    /// 扭转列表
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("visit/judge-query")]
+    public async Task<PagedDto<OrderVisitDto>> VisitJudgeQuery([FromQuery] VisitJudgeQueryReq dto)
+    {
+        var (total,items) =await _orderVisitRepository.Queryable()
+            .Includes(x => x.Order)
+            .Includes(x => x.Employee)
+            .Where(x => x.VisitState == EVisitState.Visited)
+            .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No == dto.No)
+            .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Order.Title.Contains(dto.Title))
+            .WhereIF(!string.IsNullOrEmpty(dto.VisitUserName), x => x.Employee.Name.Contains(dto.VisitUserName))
+            .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.Order.AcceptTypeCode)) //受理类型
+            .WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.Order.HotspotId)) //热点类型
+            .WhereIF(dto.OrgCodes.Any(), d => dto.OrgCodes.Contains(d.Order.ActualHandleOrgCode)) //接办部门
+            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.Order.AcceptorName.Contains(dto.NameOrNo!) || d.Order.AcceptorStaffNo.Contains(dto.NameOrNo!)) //受理人/坐席
+             .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
+            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
+            .WhereIF(dto.ActualHandleTimeStart.HasValue, d => d.Order.ActualHandleTime >= dto.ActualHandleTimeStart) //办结时间开始
+            .WhereIF(dto.ActualHandleTimeEnd.HasValue, d => d.Order.ActualHandleTime <= dto.ActualHandleTimeEnd) //办结时间结束
+            .WhereIF(dto.VisitTimeStart.HasValue, d => d.VisitTime >= dto.VisitTimeStart) //回访开始时间
+            .WhereIF(dto.VisitTimeEnd.HasValue, d => d.VisitTime <= dto.VisitTimeEnd)
+            .WhereIF(dto.JudgeState==null,d=>d.JudgeState!= EJudgeState.Judging)
+            .WhereIF(dto.JudgeState!=null,d=>d.JudgeState == dto.JudgeState)
+            .WhereIF(dto.OrgJudge!=null,d=>d.OrgJudge == dto.OrgJudge)
+            .WhereIF(dto.SeatJudge!=null,d=>d.SeatJudge == dto.SeatJudge)
+            .OrderByDescending(x => x.VisitTime)
+            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+        return new PagedDto<OrderVisitDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDto>>(items));
+    }
+
+    /// <summary>
+    /// 扭转满意度
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("visit/judge")]
+    public async Task<JudgeVisitRsp> JudgeVisit([FromBody] JudgeVisitReq dto)
+    {
+        int error = 0;
+        foreach (var id in dto.Ids)
+        {
+            var visit = await _orderVisitRepository.Queryable().FirstAsync(d => d.Id == id, HttpContext.RequestAborted);
+            if (visit!= null && visit.VisitState == EVisitState.WaitForVisit)
+            {
+                visit.JudgeState = dto.IsAgree ? EJudgeState.Agreed : EJudgeState.UnAgreed;
+                visit.JudgeUserId = _sessionContext.RequiredUserId;
+                visit.JudgeUserName = _sessionContext.UserName;
+                visit.JudgeTime = DateTime.Now;
+                await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted);
+            }
+            else
+            {
+                error++;
+            }
+        }
+        return new JudgeVisitRsp() { ErrorCount = error, SuccessCount = dto.Ids.Count - error };
+    }
+
+
+
     /// <summary>
     /// 批量分配回访人员
     /// </summary>

+ 123 - 0
src/Hotline.Share/Dtos/Order/OrderVisitDto.cs

@@ -35,6 +35,100 @@ namespace Hotline.Share.Dtos.Order
         public EVisitType? VisitType { get; set; }
     }
 
+    public record VisitJudgeQueryReq:PagedKeywordRequest
+    {
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        public string? No { get; set; }
+        /// <summary>
+        /// 工单标题
+        /// </summary>
+        public string? Title { get; set; }
+        /// <summary>
+        /// 回访人
+        /// </summary>
+        public string? VisitUserName { get; set; }
+        /// <summary>
+        /// 来电号码
+        /// </summary>
+        public string? FromPhone { get; set; }
+
+        /// <summary>
+        /// 受理类型
+        /// </summary>
+        public List<string> AcceptTypes { get; set; } = new();
+
+        /// <summary>
+        /// 热点分类
+        /// </summary>
+        public List<string> HotspotIds { get; set; } = new();
+
+        /// <summary>
+        /// 接办部门
+        /// </summary>
+        public List<string> OrgCodes { get; set; } = new();
+
+        /// <summary>
+        /// 受理坐席名字或工号
+        /// </summary>
+        public string? NameOrNo { get; set; }
+
+        /// <summary>
+        /// 受理时间(工单创建时间)
+        /// </summary>
+        public DateTime? CreationTimeStart { get; set; }
+        public DateTime? CreationTimeEnd { get; set; }
+
+        /// <summary>
+        /// 办结时间
+        /// </summary>
+        public DateTime? ActualHandleTimeStart { get; set; }
+        public DateTime? ActualHandleTimeEnd { get; set; }
+        /// <summary>
+        /// 回访时间
+        /// </summary>
+        public DateTime? VisitTimeStart { get; set; }
+
+        public DateTime? VisitTimeEnd { get; set; }
+
+        /// <summary>
+        /// 评判状态
+        /// </summary>
+        public EJudgeState? JudgeState { get; set; }
+
+        /// <summary>
+        /// 部门扭转
+        /// </summary>
+        public bool? OrgJudge { get; set; }
+        /// <summary>
+        /// 坐席扭转
+        /// </summary>
+        public bool? SeatJudge { get; set; }
+    }
+
+    public class JudgeVisitReq
+    {
+        public List<string> Ids { get; set; }
+
+        /// <summary>
+        /// 是否同意
+        /// </summary>
+        public bool IsAgree { get; set; }
+
+        /// <summary>
+        /// 是否
+        /// </summary>
+        public string? JudgeContent { get; set; }
+    }
+
+    public class JudgeVisitRsp
+    {
+        public int ErrorCount { get; set; }
+
+        public int SuccessCount { get; set; }
+    }
+
     public record VisitDetailListDto : PagedKeywordRequest
     {
         public EVisitStateQuery VisitState { get; set; }
@@ -69,6 +163,15 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public bool IsAgain { get; set; }
 
+        /// <summary>
+        /// 部门扭转
+        /// </summary>
+        public bool? OrgJudge { get; set; }
+        /// <summary>
+        /// 坐席扭转
+        /// </summary>
+        public bool? SeatJudge { get; set; }
+
         public List<VisitDetailDto> VisitDetails { get; set; }
     }
 
@@ -362,6 +465,26 @@ namespace Hotline.Share.Dtos.Order
         /// 智能回访录音地址
         /// </summary>
         public string? RecordUrl { get; set; }
+
+        /// <summary>
+        /// 部门扭转
+        /// </summary>
+        public bool? OrgJudge { get; set; }
+        /// <summary>
+        /// 坐席扭转
+        /// </summary>
+        public bool? SeatJudge { get; set; }
+        /// <summary>
+        /// 评判状态
+        /// </summary>
+        public EJudgeState? JudgeState { get; set; }
+
+        public string? JudgeStateText => JudgeState.GetDescription() ?? string.Empty;
+        
+        /// <summary>
+        /// 评判意见
+        /// </summary>
+        public string? JudgeContent { get; set; }
     }
 
     public class OrderVisitDetailDto

+ 19 - 0
src/Hotline.Share/Enums/Order/EVisitState.cs

@@ -39,4 +39,23 @@ namespace Hotline.Share.Enums.Order
         [Description("失效")]
         None = 50,
     }
+
+    public enum EJudgeState
+    {
+        /// <summary>
+        /// 评判中
+        /// </summary>
+        [Description("评判中")]
+        Judging = 0,
+        /// <summary>
+        /// 已同意
+        /// </summary>
+        [Description("已同意")]
+        Agreed = 1,
+        /// <summary>
+        /// 不同意
+        /// </summary>
+        [Description("不同意")]
+        UnAgreed =2,
+    }
 }

+ 31 - 0
src/Hotline/Orders/OrderVisit.cs

@@ -125,6 +125,37 @@ public class OrderVisit : CreationEntity
     /// </summary>
     public string? RecordUrl { get; set; }
 
+    /// <summary>
+    /// 部门扭转
+    /// </summary>
+    public bool? OrgJudge { get; set; }
+    /// <summary>
+    /// 坐席扭转
+    /// </summary>
+    public bool? SeatJudge { get; set; }
+    /// <summary>
+    /// 评判状态
+    /// </summary>
+    public EJudgeState? JudgeState { get; set;}
+    /// <summary>
+    /// 评判意见
+    /// </summary>
+    public string? JudgeContent { get; set;}
+
+    /// <summary>
+    /// 评判人Id
+    /// </summary>
+    public string JudgeUserId { get; set; }
+
+    /// <summary>
+    /// 评判人名称
+    /// </summary>
+    public string JudgeUserName { get; set; }
+
+    /// <summary>
+    /// 评判时间
+    /// </summary>
+    public DateTime? JudgeTime { get; set; }
 
     public void AiVisitTime()
     {