Sfoglia il codice sorgente

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

田爽 9 mesi fa
parent
commit
a2b85fc706
33 ha cambiato i file con 1566 aggiunte e 468 eliminazioni
  1. 7 0
      Hotline.sln
  2. 26 189
      src/Hotline.Api/Controllers/CallController.cs
  3. 217 0
      src/Hotline.Api/Controllers/CalloldController.cs
  4. 1 1
      src/Hotline.Api/Controllers/IPPbxController.cs
  5. 360 229
      src/Hotline.Api/Controllers/JudicialManagementOrdersController.cs
  6. 1 1
      src/Hotline.Api/Controllers/OrderProvinceZmhdController.cs
  7. 14 8
      src/Hotline.Api/Controllers/UserController.cs
  8. 5 1
      src/Hotline.Api/StartupExtensions.cs
  9. 3 3
      src/Hotline.Api/config/appsettings.json
  10. 1 1
      src/Hotline.Application.Contracts/Validators/CallCenter/AddBlacklistDtoValidator.cs
  11. 42 0
      src/Hotline.Application/CallCenter/ICallApplication.cs
  12. 68 0
      src/Hotline.Application/CallCenter/TianRunCallApplication.cs
  13. 128 0
      src/Hotline.Application/CallCenter/XingTangCallApplication.cs
  14. 331 8
      src/Hotline.Application/JudicialManagement/EnforcementApplication.cs
  15. 72 1
      src/Hotline.Application/JudicialManagement/IEnforcementApplication.cs
  16. 3 1
      src/Hotline.Repository.SqlSugar/Extensions/XingTangDbExtensions.cs
  17. 1 1
      src/Hotline.Share/Dtos/CallCenter/AddBlacklistDto.cs
  18. 29 0
      src/Hotline.Share/Dtos/CallCenter/SignInDto.cs
  19. 17 0
      src/Hotline.Share/Dtos/CallCenter/TelDto.cs
  20. 22 0
      src/Hotline.Share/Dtos/JudicialManagement/EmDepartmentalProcessingStatisticsDto.cs
  21. 58 6
      src/Hotline.Share/Dtos/JudicialManagement/EnforcementOrderListDto.cs
  22. 4 1
      src/Hotline.Share/Dtos/JudicialManagement/EventClassificationOrderCountDto.cs
  23. 6 0
      src/Hotline.Share/Dtos/JudicialManagement/JudicialManagementAddOrderDto.cs
  24. 2 1
      src/Hotline.Share/Dtos/JudicialManagement/QueryEventClassificationStatisticsDto.cs
  25. 6 6
      src/Hotline.Share/Enums/CallCenter/ETelStatus.cs
  26. 14 0
      src/Hotline.XingTang/Hotline.XingTang.csproj
  27. 2 2
      src/Hotline/CallCenter/BlackLists/BlacklistDomainService.cs
  28. 111 0
      src/Hotline/CallCenter/Calls/CallNative.cs
  29. 0 1
      src/Hotline/CallCenter/Calls/ICallDomainService.cs
  30. 3 1
      src/Hotline/JudicialManagement/JudicialManagementOrders.cs
  31. 5 4
      src/Hotline/JudicialManagement/JudicialManagementOrdersService.cs
  32. 1 1
      src/Hotline/Users/Work.cs
  33. 6 1
      src/XingTang.Sdk/XingtangCall.cs

+ 7 - 0
Hotline.sln

@@ -51,6 +51,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hotline.YbEnterprise.Sdk",
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XingTang.Sdk", "src\XingTang.Sdk\XingTang.Sdk.csproj", "{CF2A8B80-FF4E-4291-B383-D735BB629F32}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hotline.XingTang", "src\Hotline.XingTang\Hotline.XingTang.csproj", "{9F99C272-5BC2-452C-9D97-BC756AF04669}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -129,6 +131,10 @@ Global
 		{CF2A8B80-FF4E-4291-B383-D735BB629F32}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{CF2A8B80-FF4E-4291-B383-D735BB629F32}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{CF2A8B80-FF4E-4291-B383-D735BB629F32}.Release|Any CPU.Build.0 = Release|Any CPU
+		{9F99C272-5BC2-452C-9D97-BC756AF04669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9F99C272-5BC2-452C-9D97-BC756AF04669}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9F99C272-5BC2-452C-9D97-BC756AF04669}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9F99C272-5BC2-452C-9D97-BC756AF04669}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -156,6 +162,7 @@ Global
 		{1634234A-379C-44DC-BFEC-7BBDEF50B47B} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
 		{C3F289D5-C50B-46DB-852C-9543EF9B0355} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
 		{CF2A8B80-FF4E-4291-B383-D735BB629F32} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
+		{9F99C272-5BC2-452C-9D97-BC756AF04669} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {4B8EA790-BD13-4422-8D63-D6DBB77B823F}

+ 26 - 189
src/Hotline.Api/Controllers/CallController.cs

@@ -1,217 +1,54 @@
-using Hotline.CallCenter.BlackLists;
-using Hotline.CallCenter.Calls;
-using Hotline.Permissions;
-using Hotline.Repository.SqlSugar.Extensions;
-using Hotline.Share.Dtos;
+using Hotline.Application.CallCenter;
+using Hotline.CallCenter.BlackLists;
 using Hotline.Share.Dtos.CallCenter;
-using Hotline.Share.Enums.CallCenter;
-using Hotline.Share.Enums.Order;
-using Hotline.Share.Requests;
-using MapsterMapper;
-using Microsoft.AspNetCore.Http.Features;
+using Hotline.Share.Dtos.TrCallCenter;
 using Microsoft.AspNetCore.Mvc;
-using XF.Domain.Repository;
-using XF.Utility.EnumExtensions;
 
 namespace Hotline.Api.Controllers
 {
-    /// <summary>
-    /// 通话相关接口
-    /// </summary>
     public class CallController : BaseController
     {
-        private readonly ICallRepository _callRepository;
-        private readonly IMapper _mapper;
-        private readonly IBlacklistDomainService _blacklistDomainService;
-        private readonly IBlacklistRepository _blacklistRepository;
-        private readonly IRepository<WexCallRecord> _wexCallRecordRepository;
+        private readonly ICallApplication _callApplication;
 
-        /// <summary>
-        /// 通话相关接口构造
-        /// </summary>
-        /// <param name="callRepository"></param>
-        /// <param name="mapper"></param>
-        /// <param name="blacklistDomainService"></param>
-        /// <param name="blacklistRepository"></param>
-        /// <param name="wexCallRecordRepository"></param>
-        public CallController(
-            ICallRepository callRepository,
-            IMapper mapper,
-            IBlacklistDomainService blacklistDomainService,
-            IBlacklistRepository blacklistRepository,
-            IRepository<WexCallRecord> wexCallRecordRepository)
-        {
-            _callRepository = callRepository;
-            _mapper = mapper;
-            _blacklistDomainService = blacklistDomainService;
-            _blacklistRepository = blacklistRepository;
-            _wexCallRecordRepository = wexCallRecordRepository;
-        }
-
-        #region 威而信通话记录
-        /// <summary>
-        /// 威而信通话记录
-        /// </summary>
-        /// <param name="request"></param>
-        /// <returns></returns>
-        [HttpGet("wexpaged")]
-        public async Task<PagedDto<CallWexDto>> GetCallListWex([FromQuery] GetCallListWexRequest request)
-        {
-             var (total,items) = await _wexCallRecordRepository.Queryable()
-                .WhereIF(!string.IsNullOrEmpty(request.CDPN), d => d.CDPN.Contains(request.CDPN!))
-                .WhereIF(!string.IsNullOrEmpty(request.CPN), d => d.CPN.Contains(request.CPN!))
-                .WhereIF(request.Direction is not null, d => d.Direction == request.Direction)
-                .WhereIF(request.OnState is not null, d => d.OnState == request.OnState)
-                .WhereIF(!string.IsNullOrEmpty(request.StaffNo), d => d.StaffNo.Contains(request.StaffNo))
-                .OrderByDescending(d => d.BeginTime)
-                .ToPagedListAsync(request.PageIndex, request.PageSize);
-            return new PagedDto<CallWexDto>(total, _mapper.Map<IReadOnlyList<CallWexDto>>(items));
-        }
-
-        /// <summary>
-        /// 页面基础信息
-        /// </summary>
-        /// <returns></returns>
-        [HttpGet("base-data")]
-        public async Task<object> BaseData()
+        public CallController(ICallApplication callApplication)
         {
-            var rsp = new
-            {
-                CallDirectionOption = EnumExts.GetDescriptions<ECallDirection>(),
-                OnStateOption = EnumExts.GetDescriptions<EOnState>()
-            };
-            return rsp;
+            _callApplication = callApplication;
         }
 
-
-
-        #endregion
-
-
-        #region 通话记录
-
         /// <summary>
-        /// 分页通话记录列表
+        /// 查询分机
         /// </summary>
-        /// <param name="request"></param>
-        /// <returns></returns>
-        [HttpGet("paged")]
-        public async Task<PagedDto<CallDto>> GetCallList([FromQuery] GetCallListRequest request)
-        {
-            var (total, items) = await _callRepository.Queryable()
-                .Includes(d => d.CallDetails)
-                .WhereIF(!string.IsNullOrEmpty(request.PhoneNum), d => d.FromNo.Contains(request.PhoneNum!))
-                .WhereIF(!string.IsNullOrEmpty(request.ToNum), d => d.ToNo.Contains(request.ToNum!))
-                .WhereIF(request.Direction is not null, d => d.CallDirection == request.Direction)
-                .WhereIF(request.CallState is not null, request.CallState == ECallState.On ? d => d.CallDetails.Any(q => q.EventName == "ANSWERED") : d => !d.CallDetails.Any(q => q.EventName == "ANSWERED"))
-                .WhereIF(!string.IsNullOrEmpty(request.UserName), d => d.UserName.Contains(request.UserName))
-                .OrderByDescending(d => d.CreationTime)
-                .ToPagedListAsync(request.PageIndex, request.PageSize);
-            return new PagedDto<CallDto>(total, _mapper.Map<IReadOnlyList<CallDto>>(items));
-        }
+        [HttpGet("tels")]
+        public Task<IReadOnlyList<TelDto>> QueryTelsAsync()
+            => _callApplication.QueryTelsAsync(HttpContext.RequestAborted);
 
         /// <summary>
-        /// 查询未接通话记录
+        /// 查询分机组
         /// </summary>
-        /// <param name="request"></param>
-        /// <returns></returns>
-        [HttpGet("messed-paged")]
-        public async Task<PagedDto<CallDto>> GetCallListMissed([FromQuery] GetCallListRequest request)
-        {
-            var (total, items) = await _callRepository.Queryable()
-                .Where(x => !x.CallDetails.Any(d => d.EventName == "ANSWERED"))
-                .WhereIF(!string.IsNullOrEmpty(request.PhoneNum), d => d.FromNo.Contains(request.PhoneNum!))
-                .WhereIF(!string.IsNullOrEmpty(request.ToNum), d => d.ToNo.Contains(request.ToNum!))
-                .WhereIF(request.Direction is not null, d => d.CallDirection == request.Direction)
-                .Includes(d => d.CallDetails)
-                .OrderByDescending(d => d.CreationTime)
-                .ToPagedListAsync(request.PageIndex, request.PageSize);
-            return new PagedDto<CallDto>(total, _mapper.Map<IReadOnlyList<CallDto>>(items));
-        }
+        [HttpGet("groups")]
+        public Task<IReadOnlyList<TelGroupDto>> QueryTelGroupsAsync()
+            => _callApplication.QueryTelGroupsAsync(HttpContext.RequestAborted);
 
+        #region 黑名单
 
-        #endregion
-
-        #region 对外通话记录
-
-        /// <summary>
-        /// 通话记录(外部对接)
-        /// </summary>
-        /// <param name="request"></param>
-        /// <returns></returns>
-        [HttpGet("out-calllist")]
-        public async Task<IReadOnlyList<OutCallDto>> GetOutCallList([FromQuery] GetOutCallListRequest request)
-        {
-            var list = await _callRepository.QueryPartAsync(request.time);
-            List<OutCallDto> outCallList = new List<OutCallDto>();
-            foreach (var item in list)
-            {
-                OutCallDto outCallDto = new OutCallDto();
-                outCallDto.CallId = item.Id;
-                outCallDto.InfoType = EInfoType.Call;//TODO目前写死(只有电话)
-                outCallDto.Direction = item.CallDirection;
-                outCallDto.Cpn = item.FromNo ?? "";
-                outCallDto.Cdpn = item.ToNo ?? "";
-                outCallDto.Answered = item.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.AnswerNo ?? "";
-                outCallDto.BeginTime = item.CreationTime;
-                outCallDto.OnTime = item.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.CreationTime;//TODO 接通时间是否可以为空
-                outCallDto.ByeTime = item.CallDetails?.FirstOrDefault(x => x.EventName == "BYE")?.CreationTime;
-                outCallDto.TalkTime = item.Duration;
-                outCallDto.SoundFileName = item.CallDetails?.FirstOrDefault(x => x.EventName == "BYE")?.Recording ?? "";
-                outCallDto.EvaluateResult = "";
-                outCallDto.EndBy = item.EndBy;
-                outCallDto.OnState = item.CallDetails?.Any(x => x.EventName == "ANSWERED") == true ? EOnState.On : EOnState.NoOn;
-                outCallList.Add(outCallDto);
-            }
-            return outCallList;
-        }
+        //Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken);
+        //Task RemoveBlackListAsync(string id, CancellationToken cancellationToken);
+        //Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken);
 
         #endregion
 
-        #region 黑名单
-
-        /// <summary>
-        /// 添加电话号至黑名单
-        /// </summary>
-        /// <param name="dto"></param>
-        /// <returns></returns>
-        [Permission(EPermission.AddBlackList)]
-        [HttpPost("blacklist")]
-        public async Task AddBlacklist([FromBody] AddBlacklistDto dto)
-        {
-            await _blacklistDomainService.AddAsync(dto, HttpContext.RequestAborted);
-        }
-
         /// <summary>
-        /// 删除黑名单数据
+        /// 签入
         /// </summary>
-        /// <param name="phone"></param>
-        [Permission(EPermission.RemoveBlacklist)]
-        [HttpDelete("blacklist/{phone}")]
-        public void RemoveBlacklist(string phone)
-        {
-            _blacklistDomainService.RemoveAsync(phone);
-        }
+        [HttpPost("signin")]
+        public Task<TrOnDutyResponseDto> SignInAsync([FromBody] SignInDto dto)
+            => _callApplication.SignInAsync(dto, HttpContext.RequestAborted);
 
         /// <summary>
-        /// 分页查询黑名单
+        /// 签出
         /// </summary>
-        /// <param name="dto"></param>
-        /// <returns></returns>
-        [Permission(EPermission.QueryPagedBlack)]
-        [HttpGet("blacklist/paged")]
-        public async Task<PagedDto<Blacklist>> QueryPaged([FromQuery] BlacklistPagedDto dto)
-        {
-            var (total, items) = await _blacklistRepository.QueryPagedAsync(
-                d => !d.IsDeleted,
-                d => d.OrderByDescending(x => x.CreationTime),
-                dto.PageIndex,
-                dto.PageSize,
-                whereIfs: (!string.IsNullOrEmpty(dto.PhoneNo), d => d.PhoneNo.Contains(dto.PhoneNo!)));
-            return new PagedDto<Blacklist>(total, items);
-        }
-
-        #endregion
-
+        [HttpPost("signout")]
+        public Task SingOutAsync()
+            => _callApplication.QueryTelsAsync(HttpContext.RequestAborted);
     }
 }

+ 217 - 0
src/Hotline.Api/Controllers/CalloldController.cs

@@ -0,0 +1,217 @@
+using Hotline.CallCenter.BlackLists;
+using Hotline.CallCenter.Calls;
+using Hotline.Permissions;
+using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.CallCenter;
+using Hotline.Share.Enums.CallCenter;
+using Hotline.Share.Enums.Order;
+using Hotline.Share.Requests;
+using MapsterMapper;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.AspNetCore.Mvc;
+using XF.Domain.Repository;
+using XF.Utility.EnumExtensions;
+
+namespace Hotline.Api.Controllers
+{
+    /// <summary>
+    /// 通话相关接口
+    /// </summary>
+    public class CalloldController : BaseController
+    {
+        private readonly ICallRepository _callRepository;
+        private readonly IMapper _mapper;
+        private readonly IBlacklistDomainService _blacklistDomainService;
+        private readonly IBlacklistRepository _blacklistRepository;
+        private readonly IRepository<WexCallRecord> _wexCallRecordRepository;
+
+        /// <summary>
+        /// 通话相关接口构造
+        /// </summary>
+        /// <param name="callRepository"></param>
+        /// <param name="mapper"></param>
+        /// <param name="blacklistDomainService"></param>
+        /// <param name="blacklistRepository"></param>
+        /// <param name="wexCallRecordRepository"></param>
+        public CalloldController(
+            ICallRepository callRepository,
+            IMapper mapper,
+            IBlacklistDomainService blacklistDomainService,
+            IBlacklistRepository blacklistRepository,
+            IRepository<WexCallRecord> wexCallRecordRepository)
+        {
+            _callRepository = callRepository;
+            _mapper = mapper;
+            _blacklistDomainService = blacklistDomainService;
+            _blacklistRepository = blacklistRepository;
+            _wexCallRecordRepository = wexCallRecordRepository;
+        }
+
+        #region 威而信通话记录
+        /// <summary>
+        /// 威而信通话记录
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [HttpGet("wexpaged")]
+        public async Task<PagedDto<CallWexDto>> GetCallListWex([FromQuery] GetCallListWexRequest request)
+        {
+             var (total,items) = await _wexCallRecordRepository.Queryable()
+                .WhereIF(!string.IsNullOrEmpty(request.CDPN), d => d.CDPN.Contains(request.CDPN!))
+                .WhereIF(!string.IsNullOrEmpty(request.CPN), d => d.CPN.Contains(request.CPN!))
+                .WhereIF(request.Direction is not null, d => d.Direction == request.Direction)
+                .WhereIF(request.OnState is not null, d => d.OnState == request.OnState)
+                .WhereIF(!string.IsNullOrEmpty(request.StaffNo), d => d.StaffNo.Contains(request.StaffNo))
+                .OrderByDescending(d => d.BeginTime)
+                .ToPagedListAsync(request.PageIndex, request.PageSize);
+            return new PagedDto<CallWexDto>(total, _mapper.Map<IReadOnlyList<CallWexDto>>(items));
+        }
+
+        /// <summary>
+        /// 页面基础信息
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("base-data")]
+        public async Task<object> BaseData()
+        {
+            var rsp = new
+            {
+                CallDirectionOption = EnumExts.GetDescriptions<ECallDirection>(),
+                OnStateOption = EnumExts.GetDescriptions<EOnState>()
+            };
+            return rsp;
+        }
+
+
+
+        #endregion
+
+
+        #region 通话记录
+
+        /// <summary>
+        /// 分页通话记录列表
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [HttpGet("paged")]
+        public async Task<PagedDto<CallDto>> GetCallList([FromQuery] GetCallListRequest request)
+        {
+            var (total, items) = await _callRepository.Queryable()
+                .Includes(d => d.CallDetails)
+                .WhereIF(!string.IsNullOrEmpty(request.PhoneNum), d => d.FromNo.Contains(request.PhoneNum!))
+                .WhereIF(!string.IsNullOrEmpty(request.ToNum), d => d.ToNo.Contains(request.ToNum!))
+                .WhereIF(request.Direction is not null, d => d.CallDirection == request.Direction)
+                .WhereIF(request.CallState is not null, request.CallState == ECallState.On ? d => d.CallDetails.Any(q => q.EventName == "ANSWERED") : d => !d.CallDetails.Any(q => q.EventName == "ANSWERED"))
+                .WhereIF(!string.IsNullOrEmpty(request.UserName), d => d.UserName.Contains(request.UserName))
+                .OrderByDescending(d => d.CreationTime)
+                .ToPagedListAsync(request.PageIndex, request.PageSize);
+            return new PagedDto<CallDto>(total, _mapper.Map<IReadOnlyList<CallDto>>(items));
+        }
+
+        /// <summary>
+        /// 查询未接通话记录
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [HttpGet("messed-paged")]
+        public async Task<PagedDto<CallDto>> GetCallListMissed([FromQuery] GetCallListRequest request)
+        {
+            var (total, items) = await _callRepository.Queryable()
+                .Where(x => !x.CallDetails.Any(d => d.EventName == "ANSWERED"))
+                .WhereIF(!string.IsNullOrEmpty(request.PhoneNum), d => d.FromNo.Contains(request.PhoneNum!))
+                .WhereIF(!string.IsNullOrEmpty(request.ToNum), d => d.ToNo.Contains(request.ToNum!))
+                .WhereIF(request.Direction is not null, d => d.CallDirection == request.Direction)
+                .Includes(d => d.CallDetails)
+                .OrderByDescending(d => d.CreationTime)
+                .ToPagedListAsync(request.PageIndex, request.PageSize);
+            return new PagedDto<CallDto>(total, _mapper.Map<IReadOnlyList<CallDto>>(items));
+        }
+
+
+        #endregion
+
+        #region 对外通话记录
+
+        /// <summary>
+        /// 通话记录(外部对接)
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [HttpGet("out-calllist")]
+        public async Task<IReadOnlyList<OutCallDto>> GetOutCallList([FromQuery] GetOutCallListRequest request)
+        {
+            var list = await _callRepository.QueryPartAsync(request.time);
+            List<OutCallDto> outCallList = new List<OutCallDto>();
+            foreach (var item in list)
+            {
+                OutCallDto outCallDto = new OutCallDto();
+                outCallDto.CallId = item.Id;
+                outCallDto.InfoType = EInfoType.Call;//TODO目前写死(只有电话)
+                outCallDto.Direction = item.CallDirection;
+                outCallDto.Cpn = item.FromNo ?? "";
+                outCallDto.Cdpn = item.ToNo ?? "";
+                outCallDto.Answered = item.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.AnswerNo ?? "";
+                outCallDto.BeginTime = item.CreationTime;
+                outCallDto.OnTime = item.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.CreationTime;//TODO 接通时间是否可以为空
+                outCallDto.ByeTime = item.CallDetails?.FirstOrDefault(x => x.EventName == "BYE")?.CreationTime;
+                outCallDto.TalkTime = item.Duration;
+                outCallDto.SoundFileName = item.CallDetails?.FirstOrDefault(x => x.EventName == "BYE")?.Recording ?? "";
+                outCallDto.EvaluateResult = "";
+                outCallDto.EndBy = item.EndBy;
+                outCallDto.OnState = item.CallDetails?.Any(x => x.EventName == "ANSWERED") == true ? EOnState.On : EOnState.NoOn;
+                outCallList.Add(outCallDto);
+            }
+            return outCallList;
+        }
+
+        #endregion
+
+        #region 黑名单
+
+        /// <summary>
+        /// 添加电话号至黑名单
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [Permission(EPermission.AddBlackList)]
+        [HttpPost("blacklist")]
+        public async Task AddBlacklist([FromBody] AddBlacklistDto dto)
+        {
+            await _blacklistDomainService.AddAsync(dto, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 删除黑名单数据
+        /// </summary>
+        /// <param name="phone"></param>
+        [Permission(EPermission.RemoveBlacklist)]
+        [HttpDelete("blacklist/{phone}")]
+        public void RemoveBlacklist(string phone)
+        {
+            _blacklistDomainService.RemoveAsync(phone);
+        }
+
+        /// <summary>
+        /// 分页查询黑名单
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [Permission(EPermission.QueryPagedBlack)]
+        [HttpGet("blacklist/paged")]
+        public async Task<PagedDto<Blacklist>> QueryPaged([FromQuery] BlacklistPagedDto dto)
+        {
+            var (total, items) = await _blacklistRepository.QueryPagedAsync(
+                d => !d.IsDeleted,
+                d => d.OrderByDescending(x => x.CreationTime),
+                dto.PageIndex,
+                dto.PageSize,
+                whereIfs: (!string.IsNullOrEmpty(dto.PhoneNo), d => d.PhoneNo.Contains(dto.PhoneNo!)));
+            return new PagedDto<Blacklist>(total, items);
+        }
+
+        #endregion
+
+    }
+}

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

@@ -307,7 +307,7 @@ namespace Hotline.Api.Controllers
             var isResting = await _telRestRepository.IsRestingAsync(work.TelNo, HttpContext.RequestAborted);
             if (isResting)
                 throw UserFriendlyException.SameMessage("当前坐席正在休息");
-
+            
             var user = await _userRepository.GetAsync(work.UserId, HttpContext.RequestAborted);
             var telRest = new TelRest(work.TelNo, work.TelNo, work.UserId, work.UserName, dto.Reason, false, user.StaffNo);
             await _telRestRepository.AddAsync(telRest, HttpContext.RequestAborted);

+ 360 - 229
src/Hotline.Api/Controllers/JudicialManagementOrdersController.cs

@@ -1,8 +1,8 @@
 using Hotline.Api.Filter;
+using Hotline.Application.JudicialManagement;
 using Hotline.Caching.Interfaces;
 using Hotline.File;
 using Hotline.JudicialManagement;
-using Hotline.Orders;
 using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Settings;
 using Hotline.Settings.TimeLimits;
@@ -10,7 +10,8 @@ using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.JudicialManagement;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.JudicialManagement;
-using Hotline.Share.Enums.Order;
+using Hotline.Share.Requests;
+using Hotline.Tools;
 using MapsterMapper;
 using Microsoft.AspNetCore.Mvc;
 using SqlSugar;
@@ -33,6 +34,7 @@ namespace Hotline.Api.Controllers
         private readonly IFileRepository _fileRepository;
         private readonly IJudicialManagementOrdersService _judicialManagementOrdersService;
         private readonly IRepository<EnforcementOrdersHandler> _enforcementOrdersHandlerRepository;
+        private readonly IEnforcementApplication _enforcementApplication;
 
         /// <summary>
         /// 
@@ -48,6 +50,7 @@ namespace Hotline.Api.Controllers
         /// <param name="fileRepository"></param>
         /// <param name="judicialManagementOrdersService"></param>
         /// <param name="enforcementOrdersHandlerRepository"></param>
+        /// <param name="enforcementApplication"></param>
         public JudicialManagementOrdersController(
          IRepository<JudicialComplaintsEventType> judicialComplaintsEventTypeRepository,
          IRepository<EnforcementHotspot> enforcementHotspotRepository,
@@ -59,7 +62,8 @@ namespace Hotline.Api.Controllers
          IRepository<JudicialManagementOrders> judicialManagementOrdersRepository,
           IFileRepository fileRepository,
           IJudicialManagementOrdersService judicialManagementOrdersService,
-           IRepository<EnforcementOrdersHandler> enforcementOrdersHandlerRepository
+           IRepository<EnforcementOrdersHandler> enforcementOrdersHandlerRepository,
+           IEnforcementApplication enforcementApplication
          )
         {
             _judicialComplaintsEventTypeRepository = judicialComplaintsEventTypeRepository;
@@ -73,6 +77,7 @@ namespace Hotline.Api.Controllers
             _fileRepository = fileRepository;
             _judicialManagementOrdersService = judicialManagementOrdersService;
             _enforcementOrdersHandlerRepository = enforcementOrdersHandlerRepository;
+            _enforcementApplication = enforcementApplication;
         }
 
         /// <summary>
@@ -154,53 +159,13 @@ namespace Hotline.Api.Controllers
             }
         }
 
-        /// <summary>
-        /// 受理工单
-        /// </summary>
-        /// <param name="dto"></param>
-        /// <returns></returns>
-        [HttpGet("getownorderlist")]
-        public async Task<PagedDto<EnforcementOrderListDto>> GetOwnOrderList([FromQuery] QueryEnforcementOrderNewDto dto)
-        {
-            var (total, items) = await _judicialManagementOrdersRepository.Queryable()
-                .Where(d => d.CreatorId == _sessionContext.UserId)
-                  .WhereIF(dto.IsEnforcementOrder.HasValue, d => d.IsEnforcementOrder == dto.IsEnforcementOrder)//是否行政执法类
-                  .WhereIF(dto.IsPassTheBuckOrder.HasValue, d => d.IsPassTheBuckOrder == dto.IsPassTheBuckOrder)//是否推诿
-                   .WhereIF(dto.IsTheClueTrue.HasValue, d => d.IsTheClueTrue == dto.IsTheClueTrue)//线索是否属实
-                   .WhereIF(!string.IsNullOrEmpty(dto.EventTypeId), d => dto.EventTypeId == d.EventTypeId)//事项分类
-                   .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title!)) //标题
-                   .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No)) //工单编码
-                   .WhereIF(!string.IsNullOrEmpty(dto.AcceptTypeCode), d => d.AcceptTypeCode == dto.AcceptTypeCode) //受理类型
-                   .WhereIF(!string.IsNullOrEmpty(dto.ChannelCode), d => d.SourceChannelCode == dto.ChannelCode) //来源渠道
-                    .WhereIF(!string.IsNullOrEmpty(dto.HotspotId), d => d.TransferPhone == dto.HotspotId) //热点类型
-                    .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName.Contains(dto.NameOrNo!) || d.AcceptorStaffNo.Contains(dto.NameOrNo!)) //受理人/坐席
-                    .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
-                   .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
-                     .WhereIF(!string.IsNullOrEmpty(dto.FromName), d => d.FromName == dto.FromName) //来电人姓名
-                     .WhereIF(!string.IsNullOrEmpty(dto.AreaCode), d => d.AreaCode == dto.AreaCode) //区域
-                     .WhereIF(!string.IsNullOrEmpty(dto.OrgCode), d => SqlFunc.JsonListObjectAny(d.EnforcementOrdersHandler, "Value", dto.OrgCode))//执法部门
-                     .OrderByDescending(d => d.CreationTime)
-                     .ToPagedListAsync(dto, HttpContext.RequestAborted);
-
-            var data = _mapper.Map<List<EnforcementOrderListDto>>(items);
-
-            if (_sessionContext.RequiredOrgId == "001188")
-            {
-                foreach (var item in data)
-                {
-                    if (item.IsTheClueTrue.HasValue)
-                        item.IsShowUpdateButton = true;
-                }
-            }
-            return new PagedDto<EnforcementOrderListDto>(total, data);
-        }
-
         /// <summary>
         /// 启用/禁用
         /// </summary>
         /// <param name="id"></param>
         /// <returns></returns>
         [HttpGet]
+        [LogFilter("启用/禁用司法工单")]
         public async Task Update(string id)
         {
             var order = await _judicialManagementOrdersRepository.GetAsync(id, HttpContext.RequestAborted);
@@ -230,7 +195,6 @@ namespace Hotline.Api.Controllers
             {
                 var ids = order.FileJson.Select(x => x.Id).ToList();
                 var files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
-                //x.Classify == "办理上传" &&
                 dto.Files = files.Where(x => string.IsNullOrEmpty(x.FlowKey)).ToList();
             }
             return dto;
@@ -252,6 +216,51 @@ namespace Hotline.Api.Controllers
             await _judicialManagementOrdersRepository.RemoveAsync(order);
         }
 
+        /// <summary>
+        /// 受理工单
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("getownorderlist")]
+        public async Task<PagedDto<EnforcementOrderListDto>> GetOwnOrderList([FromQuery] QueryEnforcementOrderNewDto dto)
+        {
+            var (total, items) = await _enforcementApplication.GetOwnOrderList(dto).ToPagedListAsync(dto, HttpContext.RequestAborted);
+            return new PagedDto<EnforcementOrderListDto>(total, _mapper.Map<List<EnforcementOrderListDto>>(items));
+        }
+
+        /// <summary>
+        /// 受理工单--导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("getownorderlist_export")]
+        public async Task<FileStreamResult> GetOwnOrderListExport([FromBody] ExportExcelDto<QueryEnforcementOrderNewDto> dto)
+        {
+            var query = _enforcementApplication.GetOwnOrderList(dto.QueryDto);
+            List<JudicialManagementOrders> data;
+            if (dto.IsExportAll)
+            {
+                data = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                data = items;
+            }
+
+            var dataDtos = _mapper.Map<ICollection<EnforcementOrderListDto>>(data);
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+            var dtos = dataDtos
+                .Select(stu => _mapper.Map(stu, typeof(EnforcementOrderListDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+            return ExcelStreamResult(stream, "自定义工单数据");
+        }
+
         /// <summary>
         /// 司法行政监督管理工单查询
         /// </summary>
@@ -260,28 +269,7 @@ namespace Hotline.Api.Controllers
         [HttpGet("getorderlist")]
         public async Task<PagedDto<EnforcementOrderListDto>> GetOrderList([FromQuery] QueryEnforcementOrderNewDto dto)
         {
-            var areaCode = _sessionContext.OrgAreaCode ?? "511500";
-
-            var (total, items) = await _judicialManagementOrdersRepository.Queryable()
-                  .WhereIF(areaCode != "511500", d => d.AreaCode.StartsWith(areaCode))
-                  .WhereIF(dto.IsEnforcementOrder.HasValue, d => d.IsEnforcementOrder == dto.IsEnforcementOrder)//是否行政执法类
-                  .WhereIF(dto.IsPassTheBuckOrder.HasValue, d => d.IsPassTheBuckOrder == dto.IsPassTheBuckOrder)//是否推诿
-                   .WhereIF(dto.IsTheClueTrue.HasValue, d => d.IsTheClueTrue == dto.IsTheClueTrue)//线索是否属实
-                   .WhereIF(!string.IsNullOrEmpty(dto.EventTypeId), d => dto.EventTypeId == d.EventTypeId)//事项分类
-                   .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title!)) //标题
-                   .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No)) //工单编码
-                   .WhereIF(!string.IsNullOrEmpty(dto.AcceptTypeCode), d => d.AcceptTypeCode == dto.AcceptTypeCode) //受理类型
-                   .WhereIF(!string.IsNullOrEmpty(dto.ChannelCode), d => d.SourceChannelCode == dto.ChannelCode) //来源渠道
-                    .WhereIF(!string.IsNullOrEmpty(dto.HotspotId), d => d.TransferPhone == dto.HotspotId) //热点类型
-                    .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName.Contains(dto.NameOrNo!) || d.AcceptorStaffNo.Contains(dto.NameOrNo!)) //受理人/坐席
-                    .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
-                   .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
-                     .WhereIF(!string.IsNullOrEmpty(dto.FromName), d => d.FromName == dto.FromName) //来电人姓名
-                     .WhereIF(!string.IsNullOrEmpty(dto.AreaCode), d => d.AreaCode == dto.AreaCode) //区域
-                     .WhereIF(!string.IsNullOrEmpty(dto.OrgCode), d => SqlFunc.JsonListObjectAny(d.EnforcementOrdersHandler, "Value", dto.OrgCode))//执法部门
-                     .OrderByDescending(d => d.CreationTime)
-                     .ToPagedListAsync(dto, HttpContext.RequestAborted);
-
+            var (total, items) = await _enforcementApplication.GetOrderList(dto).ToPagedListAsync(dto, HttpContext.RequestAborted);
             var data = _mapper.Map<List<EnforcementOrderListDto>>(items);
 
             if (_sessionContext.RequiredOrgId == "001188")
@@ -295,6 +283,40 @@ namespace Hotline.Api.Controllers
             return new PagedDto<EnforcementOrderListDto>(total, data);
         }
 
+        /// <summary>
+        /// 司法行政监督管理工单查询---导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("getorderlist_export")]
+        public async Task<FileStreamResult> GetOrderListExport([FromBody] ExportExcelDto<QueryEnforcementOrderNewDto> dto)
+        {
+            var query = _enforcementApplication.GetOrderList(dto.QueryDto);
+            List<JudicialManagementOrders> data;
+            if (dto.IsExportAll)
+            {
+                data = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                data = items;
+            }
+
+            var dataDtos = _mapper.Map<ICollection<EnforcementOrderListDto>>(data);
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+            var dtos = dataDtos
+                .Select(stu => _mapper.Map(stu, typeof(EnforcementOrderListDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+            return ExcelStreamResult(stream, "工单中心数据");
+
+        }
+
         /// <summary>
         /// 列表页面基础数据
         /// </summary>
@@ -336,26 +358,38 @@ namespace Hotline.Api.Controllers
         }
 
         /// <summary>
-        /// 获取省市区树形
+        /// 根据当前部门获取区域
         /// </summary>
         /// <returns></returns>
         [HttpGet("area/tree")]
-        public async Task<List<SystemArea>> GetAreaTree()
+        public async Task<object> GetAreaTree()
         {
             var areaCode = _sessionContext.OrgAreaCode;
             if (string.IsNullOrEmpty(areaCode))
                 areaCode = "511500";
             if (areaCode == "511500")
             {
-                return await _systemAreaRepository.Queryable().OrderBy(x => x.Id).ToTreeAsync(x => x.Children, q => q.ParentId, "510000");
+                return await _systemAreaRepository.Queryable()
+                              .Where(p => p.Id == "511500" || p.ParentId == "511500")
+                              .Select(p => new
+                              {
+                                  p.AreaName,
+                                  p.Id
+                              })
+                              .OrderBy(p => p.Id)
+                              .ToListAsync();
             }
             else
             {
-                string parentId = "510000";
-                var data = await _systemAreaRepository.GetAsync(p => p.Id == areaCode);
-                if (data != null)
-                    parentId = data.ParentId;
-                return await _systemAreaRepository.Queryable().Where(p => p.Id.StartsWith(areaCode)).OrderBy(x => x.Id).ToTreeAsync(x => x.Children, q => q.ParentId, parentId);
+                return await _systemAreaRepository.Queryable()
+                             .Where(p => p.Id == _sessionContext.OrgAreaCode)
+                             .Select(p => new
+                             {
+                                 p.AreaName,
+                                 p.Id
+                             })
+                             .OrderBy(p => p.Id)
+                             .ToListAsync();
             }
         }
 
@@ -436,11 +470,20 @@ namespace Hotline.Api.Controllers
         [HttpGet("event_classification_statistics")]
         public async Task<object> GetEventClassificationStatisticsAsync(DateTime StartTime, DateTime EndTime, string Id, string AreaCode)
         {
+            string areCodeText = "";
+            if (string.IsNullOrEmpty(AreaCode))
+            {
+                if (_sessionContext.OrgAreaCode != "511500")
+                    areCodeText = _sessionContext.OrgAreaCode;
+            }
+            else
+                areCodeText = AreaCode;
 
-            var items = await _judicialComplaintsEventTypeRepository.Queryable()
-             .LeftJoin<JudicialManagementOrders>((x, o) => o.EventTypeSpliceName != null && (x.EventTypeName == o.EventTypeSpliceName || o.EventTypeSpliceName.Contains(x.EventTypeName)))
+             var items = await _judicialComplaintsEventTypeRepository.Queryable()
+             .LeftJoin<JudicialManagementOrders>((x, o) => o.EventTypeSpliceName != null &&
+             (x.EventTypeName == o.EventTypeSpliceName || o.EventTypeSpliceName.Contains(x.EventTypeName)))
             .Where((x, o) => o.CreationTime >= StartTime && o.CreationTime <= EndTime)
-            .WhereIF(!string.IsNullOrEmpty(AreaCode), (x, o) => o.AreaCode.StartsWith(AreaCode))
+            .WhereIF(!string.IsNullOrEmpty(areCodeText), (x, o) => o.AreaCode.StartsWith(areCodeText))
              .Where((x, o) => x.ParentId == Id)
              .GroupBy((x, o) => new { x.Id, x.EventTypeName })
              .Select((x, o) => new
@@ -455,13 +498,15 @@ namespace Hotline.Api.Controllers
 
             var data = await _judicialManagementOrdersRepository.Queryable()
                 .Where(d => d.CreationTime >= StartTime && d.CreationTime <= EndTime)
+                .WhereIF(!string.IsNullOrEmpty(areCodeText), p => p.AreaCode.StartsWith(areCodeText))
                 .GroupBy(d => d.Id)
                  .Select(d => new EventClassificationOrderCountDto
                  {
                      TheClueIsTrue = SqlFunc.AggregateSum(SqlFunc.IIF(d.IsTheClueTrue.HasValue && d.IsTheClueTrue.Value == true, 1, 0)),
                      TheClueIsNotTrue = SqlFunc.AggregateSum(SqlFunc.IIF(d.IsTheClueTrue.HasValue && d.IsTheClueTrue.Value == false, 1, 0)),
                      EnforcementOrder = SqlFunc.AggregateSum(SqlFunc.IIF(d.IsEnforcementOrder.HasValue && d.IsEnforcementOrder.Value == true, 1, 0)),
-                     PassTheBuckOrder = SqlFunc.AggregateSum(SqlFunc.IIF(d.IsPassTheBuckOrder, 1, 0))
+                     PassTheBuckOrder = SqlFunc.AggregateSum(SqlFunc.IIF(d.IsPassTheBuckOrder, 1, 0)),
+                     ToBeVerified = SqlFunc.AggregateSum(SqlFunc.IIF(d.IsTheClueTrue == null, 1, 0)),
                  })
                    .ToListAsync();
 
@@ -471,6 +516,7 @@ namespace Hotline.Api.Controllers
                 TheClueIsNotTrue = data.Sum(x => x.TheClueIsNotTrue),
                 EnforcementOrder = data.Sum(x => x.EnforcementOrder),
                 PassTheBuckOrder = data.Sum(x => x.PassTheBuckOrder),
+                ToBeVerified = data.Sum(x => x.ToBeVerified)
             };
 
             return new { List = items, OrderCount = orderCount };
@@ -484,47 +530,86 @@ namespace Hotline.Api.Controllers
         [HttpGet("event_classification_statistics_order_list")]
         public async Task<PagedDto<EnforcementOrderListDto>> GetEventClassificationStatisticsOrderListAsync([FromQuery] QueryEventClassificationStatisticsDto dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
+            var (total, items) = await _enforcementApplication.GetEventClassificationStatisticsOrderListAsync(dto).ToPagedListAsync(dto, HttpContext.RequestAborted);
+            return new PagedDto<EnforcementOrderListDto>(total, _mapper.Map<List<EnforcementOrderListDto>>(items));
+        }
 
-            var (total, items) = await _judicialManagementOrdersRepository.Queryable()
-            .Where(d => d.CreationTime >= dto.StartTime && d.CreationTime <= dto.EndTime && d.EventTypeId != null)
-            .WhereIF(!string.IsNullOrEmpty(dto.EventTypeId), d => d.EventTypeId.StartsWith(dto.EventTypeId))
-            .WhereIF(!string.IsNullOrEmpty(dto.AreaCode), d => d.AreaCode.StartsWith(dto.AreaCode))
-            .OrderByDescending(d => d.CreationTime)
-           .ToPagedListAsync(dto, HttpContext.RequestAborted);
+        /// <summary>
+        /// 事项分类统计--明细--导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("event_classification_statistics_order_list_export")]
+        public async Task<FileStreamResult> GetEventClassificationStatisticsOrderListExportAsync([FromBody] ExportExcelDto<QueryEventClassificationStatisticsDto> dto)
+        {
+            var query = _enforcementApplication.GetEventClassificationStatisticsOrderListAsync(dto.QueryDto);
+            List<JudicialManagementOrders> data;
+            if (dto.IsExportAll)
+            {
+                data = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                data = items;
+            }
+
+            var dataDtos = _mapper.Map<ICollection<EnforcementOrderListDto>>(data);
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+            var dtos = dataDtos
+                .Select(stu => _mapper.Map(stu, typeof(EnforcementOrderListDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+            return ExcelStreamResult(stream, "事项分类统计明细数据");
 
-            return new PagedDto<EnforcementOrderListDto>(total, _mapper.Map<List<EnforcementOrderListDto>>(items));
         }
 
         /// <summary>
         /// 执法部门办件统计
         /// </summary>
-        /// <param name="StartTime"></param>
-        /// <param name="EndTime"></param>
+        /// <param name="dto"></param>
         /// <returns></returns>
         [HttpGet("enforcement_departmental_processing_statistics")]
-        public async Task<object> GetDepartmentalProcessingStatisticsAsync(DateTime StartTime, DateTime EndTime)
+        public async Task<List<EmDepartmentalProcessingStatisticsDto>> GetDepartmentalProcessingStatisticsAsync([FromQuery] QueryDepartmentalProcessingStatisticsDto dto)
+        {
+            return await _enforcementApplication.GetDepartmentalProcessingStatisticsAsync(dto.StartTime, dto.EndTime).ToListAsync();
+
+        }
+
+        /// <summary>
+        /// 执法部门办件统计--导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("enforcement_departmental_processing_statistics_export")]
+        public async Task<FileStreamResult> GetDepartmentalProcessingStatisticsExportAsync([FromBody] ExportExcelDto<QueryDepartmentalProcessingStatisticsDto> dto)
         {
-            var data = await _enforcementOrdersHandlerRepository.Queryable()
-                  .LeftJoin<JudicialManagementOrders>((h, o) => h.OrderId == o.Id)
-                  .Where((x, o) => o.CreationTime >= StartTime && o.CreationTime <= EndTime)
-                   .GroupBy((x, o) => new
-                   {
-                       OrgCode = x.OrgCode,
-                       OrgName = x.OrgName
-                   })
-                   .Select((x, o) => new
-                   {
-                       OrgCode = x.OrgCode,
-                       OrgName = x.OrgName,
-                       CountNum = SqlFunc.AggregateSum(SqlFunc.IIF(x.OrgCode != null, 1, 0)),
-                       TheClueIsTrue = SqlFunc.AggregateSum(SqlFunc.IIF(o.IsTheClueTrue.HasValue && o.IsTheClueTrue.Value == true, 1, 0)),
-                       TheClueIsNotTrue = SqlFunc.AggregateSum(SqlFunc.IIF(o.IsTheClueTrue.HasValue && o.IsTheClueTrue.Value == false, 1, 0)),
-                       EnforcementOrder = SqlFunc.AggregateSum(SqlFunc.IIF(o.IsEnforcementOrder.HasValue && o.IsEnforcementOrder.Value == true, 1, 0))
-                   })
-                     .ToListAsync();
-
-            return data;
+            var list = await _enforcementApplication.GetDepartmentalProcessingStatisticsAsync(dto.QueryDto.StartTime, dto.QueryDto.EndTime).ToListAsync();
+
+            list.Add(new EmDepartmentalProcessingStatisticsDto
+            {
+                OrgCode = "",
+                OrgName = "合计",
+                CountNum = list.Sum(p => p.CountNum),
+                TheClueIsTrue = list.Sum(p => p.TheClueIsTrue),
+                TheClueIsNotTrue = list.Sum(p => p.TheClueIsNotTrue),
+                EnforcementOrder = list.Sum(p => p.EnforcementOrder)
+            });
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+            var dtos = list
+                .Select(stu => _mapper.Map(stu, typeof(EmDepartmentalProcessingStatisticsDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+
+            return ExcelStreamResult(stream, "执法部门办件统计数据");
+
         }
 
         /// <summary>
@@ -535,25 +620,40 @@ namespace Hotline.Api.Controllers
         [HttpGet("enforcement_departmental_processing_statistics_order_list")]
         public async Task<PagedDto<EnforcementOrderListDto>> GetDepartmentalProcessingStatisticsOrderListAsync([FromQuery] QueryDepartmentalProcessingStatisticsDto dto)
         {
-            RefAsync<int> total = 0;
-            var queryData = await _enforcementOrdersHandlerRepository.Queryable()
-                .LeftJoin<JudicialManagementOrders>((h, o) => h.OrderId == o.Id)
-                .Where((x, o) => o.CreationTime >= dto.StartTime && o.CreationTime <= dto.EndTime && o.Id != null)
-                .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.OrgCode == "001", (x, o) => x.OrgCode == dto.OrgCode)
-                .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.OrgCode != "001", (x, o) => x.OrgCode.StartsWith(dto.OrgCode))
-                .WhereIF(dto.TheClueIsTrue == true, (x, o) => o.IsTheClueTrue == true)
-                .WhereIF(dto.TheClueIsNotTrue == true, (x, o) => o.IsTheClueTrue == false)
-                .WhereIF(dto.EnforcementOrder == true, (x, o) => o.IsEnforcementOrder == true)
-                .OrderByDescending((x, o) => o.CreationTime)
-                 .Select((x, o) => new { o })
-                .ToPageListAsync(dto.PageIndex, dto.PageSize, total, HttpContext.RequestAborted);
-
-            var dtos = queryData.Select(d =>
+            var (total, items) = await _enforcementApplication.GetDepartmentalProcessingStatisticsOrderListAsync(dto).ToPagedListAsync(dto, HttpContext.RequestAborted);
+            return new PagedDto<EnforcementOrderListDto>(total, items);
+        }
+
+        /// <summary>
+        /// 执法部门办件统计---明细---导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("enforcement_departmental_processing_statistics_order_list_export")]
+        public async Task<FileStreamResult> GetDepartmentalProcessingStatisticsOrderListExportAsync([FromBody] ExportExcelDto<QueryDepartmentalProcessingStatisticsDto> dto)
+        {
+            var query = _enforcementApplication.GetDepartmentalProcessingStatisticsOrderListAsync(dto.QueryDto);
+            List<EnforcementOrderListDto> data;
+            if (dto.IsExportAll)
             {
-                var dto = _mapper.Map<EnforcementOrderListDto>(d.o);
-                return dto;
-            }).ToList();
-            return new PagedDto<EnforcementOrderListDto>(total, dtos);
+                data = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                data = items;
+            }
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+            var dtos = data
+                .Select(stu => _mapper.Map(stu, typeof(EnforcementOrderListDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+            return ExcelStreamResult(stream, "执法部门办件统计明细数据");
+
         }
 
         /// <summary>
@@ -561,32 +661,38 @@ namespace Hotline.Api.Controllers
         /// </summary>
         /// <returns></returns>
         [HttpGet("regional_classification_statistics")]
-        public async Task<object> GetRegionalClassificationStatisticsAsync(DateTime StartTime, DateTime EndTime)
+        public async Task<object> GetRegionalClassificationStatisticsAsync([FromQuery] QueryRegionalClassificationStatisticsDto dto)
+        {
+            return await _enforcementApplication.GetRegionalClassificationStatisticsAsync(dto.StartTime, dto.EndTime).ToListAsync();
+        }
+
+        /// <summary>
+        /// 区域分类统计--导出
+        /// </summary>
+        /// <returns></returns>
+        [HttpPost("regional_classification_statistics_export")]
+        public async Task<FileStreamResult> GetRegionalClassificationStatisticsExportAsync([FromBody] ExportExcelDto<QueryRegionalClassificationStatisticsDto> dto)
         {
+            var list= await _enforcementApplication.GetRegionalClassificationStatisticsAsync(dto.QueryDto.StartTime, dto.QueryDto.EndTime).ToListAsync();
 
-            var areaCode = _sessionContext.OrgAreaCode ?? "511500";
-            var list = await _judicialManagementOrdersRepository.Queryable()
-               .Where(x => x.CreationTime >= StartTime && x.CreationTime <= EndTime)
-               .LeftJoin<SystemArea>((x, o) => x.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) == o.Id)
-               .WhereIF(areaCode != "511500", (x, o) => x.AreaCode.StartsWith(areaCode))
-               .GroupBy((x, o) => new
-               {
-                   AreaCode = x.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
-                   o.AreaName,
-               })
-               .Select((x, o) => new
-               {
-                   AreaCode = x.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
-                   AreaName = o.AreaName,
-                   OrderCountNum = SqlFunc.AggregateCount(x.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6"))),
-                   TheClueIsTrue = SqlFunc.AggregateSum(SqlFunc.IIF(x.IsTheClueTrue.HasValue && x.IsTheClueTrue.Value == true, 1, 0)),
-                   TheClueIsNotTrue = SqlFunc.AggregateSum(SqlFunc.IIF(x.IsTheClueTrue.HasValue && x.IsTheClueTrue.Value == false, 1, 0)),
-                   EnforcementOrder = SqlFunc.AggregateSum(SqlFunc.IIF(x.IsEnforcementOrder.HasValue && x.IsEnforcementOrder.Value == true, 1, 0))
-               }).MergeTable()
-                .Where(x => x.AreaCode != "519800" && x.AreaCode != "519900")
-                .OrderByDescending(it => it.OrderCountNum)
-                .ToListAsync();
-            return list;
+            list.Add(new RegionalClassificationStatisticsDto()
+            {
+                AreaCode="",
+                AreaName = "总计",
+                OrderCountNum = list.Sum(x => x.OrderCountNum),
+                TheClueIsTrue = list.Sum(x => x.TheClueIsTrue),
+                TheClueIsNotTrue = list.Sum(x => x.TheClueIsNotTrue),
+                EnforcementOrder = list.Sum(x => x.EnforcementOrder)
+            });
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+            var dtos = list
+                .Select(stu => _mapper.Map(stu, typeof(RegionalClassificationStatisticsDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+
+            return ExcelStreamResult(stream, "部门满意度统计数据");
         }
 
         /// <summary>
@@ -597,69 +703,53 @@ namespace Hotline.Api.Controllers
         [HttpGet("regional_classification_statistics_order_list")]
         public async Task<PagedDto<EnforcementOrderListDto>> GetRegionalClassificationStatisticsOrderListAsync([FromQuery] QueryRegionalClassificationStatisticsDto dto)
         {
-            var (total, items) = await _judicialManagementOrdersRepository.Queryable()
-            .Where(d => d.CreationTime >= dto.StartTime && d.CreationTime <= dto.EndTime)
-            .WhereIF(!string.IsNullOrEmpty(dto.AreaCode), d => d.AreaCode.StartsWith(dto.AreaCode))
-            .WhereIF(dto.TheClueIsTrue == true, d => d.IsTheClueTrue == true)
-            .WhereIF(dto.TheClueIsNotTrue == true, d => d.IsTheClueTrue == false)
-            .WhereIF(dto.EnforcementOrder == true, d => d.IsEnforcementOrder == true)
-              .OrderByDescending(d => d.CreationTime)
-           .ToPagedListAsync(dto, HttpContext.RequestAborted);
-
+            var (total, items) = await _enforcementApplication.GetRegionalClassificationStatisticsOrderListAsync(dto).ToPagedListAsync(dto, HttpContext.RequestAborted);
             return new PagedDto<EnforcementOrderListDto>(total, _mapper.Map<List<EnforcementOrderListDto>>(items));
         }
 
+        /// <summary>
+        /// 区域分类统计---明细---导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("regional_classification_statistics_order_list_export")]
+        public async Task<FileStreamResult> GetRegionalClassificationStatisticsOrderListExportAsync([FromBody] ExportExcelDto<QueryRegionalClassificationStatisticsDto> dto)
+        {
+            var query = _enforcementApplication.GetRegionalClassificationStatisticsOrderListAsync(dto.QueryDto);
+            List<JudicialManagementOrders> data;
+            if (dto.IsExportAll)
+            {
+                data = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                data = items;
+            }
+
+            var dataDtos = _mapper.Map<ICollection<EnforcementOrderListDto>>(data);
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+            var dtos = dataDtos
+                .Select(stu => _mapper.Map(stu, typeof(EnforcementOrderListDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+            return ExcelStreamResult(stream, "区域分类统计明细数据");
+
+        }
+
         /// <summary>
         /// 部门满意度统计
         /// </summary>
-        /// <param name="StartTime"></param>
-        /// <param name="EndTime"></param>
-        /// <param name="TypeId">1:办件结果 2:办件态度</param>
+        /// <param name="dto"></param>
         /// <returns></returns>
         [HttpGet("enforcement_visit_org_satisfaction_statistics")]
-        public async Task<object> GetVisitAndOrgSatisfactionStatisticsAsync(DateTime StartTime, DateTime EndTime, int TypeId)
+        public async Task<object> GetVisitAndOrgSatisfactionStatisticsAsync([FromQuery] QueryOrgSatisfactionStatisticsDto dto)
         {
-            EndTime = EndTime.AddDays(1).AddSeconds(-1);
-
-            var list = await _judicialManagementOrdersRepository.Queryable()
-                 .LeftJoin<OrderVisit>((x, o) => x.Id == o.OrderId)
-                 .LeftJoin<OrderVisitDetail>((x, o, p) => o.Id == p.VisitId)
-                .Where((x, o, p) => o.VisitTime >= StartTime && o.VisitTime <= EndTime && p.VisitTarget == EVisitTarget.Org
-                && o.VisitState == EVisitState.Visited && !string.IsNullOrEmpty(p.VisitOrgCode) && x.OrderSoure == EOrderSoure.Hotline)
-                .GroupBy((x, o, p) => new
-                {
-                    VisitOrgCode = p.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6"))
-                })
-                .Select((x, o, p) => new VisitAndOrgSatisfactionStatisticsDto()
-                {
-                    OrgCode = p.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
-                    TotalSumCount = SqlFunc.AggregateCount(p.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6"))),
-                    VerySatisfiedCount = SqlFunc.IIF(TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgProcessingResults, "Key") == "5", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == "5", 1, 0))),//非常满意数
-                    SatisfiedCount = SqlFunc.IIF(TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgProcessingResults, "Key") == "4", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == "4", 1, 0))), //满意数
-                    RegardedAsSatisfiedCount = SqlFunc.IIF(TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgProcessingResults, "Key") == "-1", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == "-1", 1, 0))),//视为满意
-                    DefaultSatisfiedCount = SqlFunc.IIF(TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgProcessingResults, "Key") == "0", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == "0", 1, 0))),//默认满意
-                    NoSatisfiedCount = SqlFunc.IIF(TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgProcessingResults, "Key") == "2", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == "2", 1, 0))),//不满意
-                    NoEvaluateCount = SqlFunc.IIF(TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgProcessingResults, "Key") == "7", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == "7", 1, 0))),//未做评价
-                    NoPutThroughCount = SqlFunc.IIF(TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgProcessingResults, "Key") == "6", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == "6", 1, 0))),//未接通
-                })
-                .MergeTable()
-                .LeftJoin<SystemOrganize>((it, o) => it.OrgCode == o.Id)
-                .Select((it, o) => new VisitAndOrgSatisfactionStatisticsDto()
-                {
-                    OrgName = o.Name,
-                    OrgCode = it.OrgCode,
-                    OrgType = o.OrgType,
-                    TotalSumCount = it.TotalSumCount,
-                    VerySatisfiedCount = it.VerySatisfiedCount,//非常满意数
-                    SatisfiedCount = it.SatisfiedCount, //满意数
-                    RegardedAsSatisfiedCount = it.RegardedAsSatisfiedCount,//视为满意
-                    DefaultSatisfiedCount = it.DefaultSatisfiedCount,//默认满意
-                    NoSatisfiedCount = it.NoSatisfiedCount,//不满意
-                    NoEvaluateCount = it.NoEvaluateCount,//未做评价
-                    NoPutThroughCount = it.NoPutThroughCount,//未接通
-                })
-                .ToListAsync();
-
+            var list = await _enforcementApplication.GetVisitAndOrgSatisfactionStatisticsAsync(dto.StartTime, dto.EndTime, dto.TypeId).ToListAsync();
 
             var sumModel = new VisitAndOrgSatisfactionStatisticsDto()
             {
@@ -674,10 +764,43 @@ namespace Hotline.Api.Controllers
                 NoPutThroughCount = list.Sum(x => x.NoPutThroughCount),
             };
 
-
             return new { DataList = list, SumModel = sumModel };
         }
 
+        /// <summary>
+        /// 部门满意度统计--导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("enforcement_visit_org_satisfaction_statistics_export")]
+        public async Task<object> GetVisitAndOrgSatisfactionStatisticsExportAsync([FromBody] ExportExcelDto<QueryOrgSatisfactionStatisticsDto> dto)
+        {
+            var list = await _enforcementApplication.GetVisitAndOrgSatisfactionStatisticsAsync(dto.QueryDto.StartTime, dto.QueryDto.EndTime, dto.QueryDto.TypeId).ToListAsync();
+
+            list.Add(new VisitAndOrgSatisfactionStatisticsDto()
+            {
+                OrgName = "总计",
+                TotalSumCount = list.Sum(x => x.TotalSumCount),
+                VerySatisfiedCount = list.Sum(x => x.VerySatisfiedCount),
+                SatisfiedCount = list.Sum(x => x.SatisfiedCount),
+                RegardedAsSatisfiedCount = list.Sum(x => x.RegardedAsSatisfiedCount),
+                DefaultSatisfiedCount = list.Sum(x => x.DefaultSatisfiedCount),
+                NoSatisfiedCount = list.Sum(x => x.NoSatisfiedCount),
+                NoEvaluateCount = list.Sum(x => x.NoEvaluateCount),
+                NoPutThroughCount = list.Sum(x => x.NoPutThroughCount),
+            });
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+            var dtos = list
+                .Select(stu => _mapper.Map(stu, typeof(VisitAndOrgSatisfactionStatisticsDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+
+            return ExcelStreamResult(stream, "部门满意度统计数据");
+
+        }
+
         /// <summary>
         /// 部门满意度统计---明细
         /// </summary>
@@ -686,31 +809,39 @@ namespace Hotline.Api.Controllers
         [HttpGet("enforcement_visit_org_satisfaction_statistics_order_list")]
         public async Task<PagedDto<EnforcementOrgSatisfactionOrderListDto>> GetVisitAndOrgSatisfactionStatisticsOrderListAsync([FromQuery] QueryOrgSatisfactionStatisticsDto dto)
         {
-            RefAsync<int> total = 0;
-            var queryData = await _judicialManagementOrdersRepository.Queryable()
-                .LeftJoin<OrderVisit>((x, o) => x.Id == o.OrderId)
-                .LeftJoin<OrderVisitDetail>((x, o, p) => o.Id == p.VisitId)
-                .Where((x, o, p) => o.VisitTime >= dto.StartTime && o.VisitTime <= dto.EndTime && p.VisitTarget == EVisitTarget.Org && x.OrderSoure == EOrderSoure.Hotline)
-                .Where((x, o, p) => o.VisitState == EVisitState.Visited && !string.IsNullOrEmpty(p.VisitOrgCode))
-                .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.OrgCode == "001", (x, o, p) => p.VisitOrgCode == dto.OrgCode)
-                .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.OrgCode != "001", (x, o, p) => p.VisitOrgCode.StartsWith(dto.OrgCode))
-                 .WhereIF(dto.TypeId == 1, (x, o, p) => SqlFunc.JsonField(p.OrgProcessingResults, "Key") == dto.DateValue)
-                .WhereIF(dto.TypeId == 2, (x, o, p) => SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == dto.DateValue)
-                .Select((x, o, p) => new
-                {
-                    x,
-                    p.VisitId
-                })
-               .MergeTable()
-               .ToPageListAsync(dto.PageIndex, dto.PageSize, total, HttpContext.RequestAborted);
+            var (total, items) = await _enforcementApplication.GetVisitAndOrgSatisfactionStatisticsOrderListAsync(dto).ToPagedListAsync(dto, HttpContext.RequestAborted);
+            return new PagedDto<EnforcementOrgSatisfactionOrderListDto>(total, items);
+        }
 
-            var dtos = queryData.Select(d =>
+        /// <summary>
+        /// 部门满意度统计---明细---导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("enforcement_visit_org_satisfaction_statistics_order_list_export")]
+        public async Task<FileStreamResult> GetVisitAndOrgSatisfactionStatisticsOrderListExportAsync([FromBody] ExportExcelDto<QueryOrgSatisfactionStatisticsDto> dto)
+        {
+            var query = _enforcementApplication.GetVisitAndOrgSatisfactionStatisticsOrderListAsync(dto.QueryDto);
+            List<EnforcementOrgSatisfactionOrderListDto> data;
+            if (dto.IsExportAll)
             {
-                var dto = _mapper.Map<EnforcementOrgSatisfactionOrderListDto>(d);
-                return dto;
-            }).ToList();
-            return new PagedDto<EnforcementOrgSatisfactionOrderListDto>(total, dtos);
+                data = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                data = items;
+            }
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+            var dtos = data
+                .Select(stu => _mapper.Map(stu, typeof(EnforcementOrgSatisfactionOrderListDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
 
+            var stream = ExcelHelper.CreateStream(dtos);
+            return ExcelStreamResult(stream, "部门满意度统计明细数据");
         }
 
         ///// <summary>

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

@@ -48,7 +48,7 @@ namespace Hotline.Api.Controllers
         {
             RefAsync<int> total = 0;
             var items = await _orderRepository.Queryable()
-                .Where(p => p.SourceChannelCode == "SZMHD" && p.IsProvince == false && p.Status > EOrderStatus.Filed)
+                .Where(p => p.SourceChannelCode == "SZMHD" && p.IsProvince == false && p.Status >= EOrderStatus.Filed)
                 .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.No == dto.No)
                 .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.ProvinceNo == dto.ProvinceNo)
                 .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Title.StartsWith(dto.Title!))

+ 14 - 8
src/Hotline.Api/Controllers/UserController.cs

@@ -185,10 +185,13 @@ public class UserController : BaseController
     public async Task Update([FromBody] UpdateUserDto dto)
     {
         //工号不能重复
-        var isStaffNoExists = await _userRepository.Queryable()
-            .AnyAsync(d => d.Id != dto.Id && d.StaffNo == dto.StaffNo, HttpContext.RequestAborted);
-        if (isStaffNoExists)
-            throw UserFriendlyException.SameMessage("工号已存在");
+        if (!string.IsNullOrEmpty(dto.StaffNo))
+        {
+            var isStaffNoExists = await _userRepository.Queryable()
+                .AnyAsync(d => d.Id != dto.Id && d.StaffNo == dto.StaffNo, HttpContext.RequestAborted);
+            if (isStaffNoExists)
+                throw UserFriendlyException.SameMessage("工号已存在");
+        }
 
         var user = await _userRepository.Queryable()
             .Includes(d => d.Account)
@@ -217,10 +220,13 @@ public class UserController : BaseController
     public async Task<string> Add([FromBody] AddUserDto dto)
     {
         //工号不能重复
-        var isStaffNoExists = await _userRepository.Queryable()
-            .AnyAsync(d => d.StaffNo == dto.StaffNo, HttpContext.RequestAborted);
-        if (isStaffNoExists)
-            throw UserFriendlyException.SameMessage("工号已存在");
+        if (!string.IsNullOrEmpty(dto.StaffNo))
+        {
+            var isStaffNoExists = await _userRepository.Queryable()
+                .AnyAsync(d => d.StaffNo == dto.StaffNo, HttpContext.RequestAborted);
+            if (isStaffNoExists)
+                throw UserFriendlyException.SameMessage("工号已存在");
+        }
 
         var account = await _accountRepository.GetAsync(d => d.UserName == dto.UserName, HttpContext.RequestAborted);
         if (account is null)

+ 5 - 1
src/Hotline.Api/StartupExtensions.cs

@@ -24,6 +24,7 @@ using Hotline.YbEnterprise.Sdk;
 using Hotline.Share.Dtos.SendSms;
 using Hotline.Wex;
 using Hotline.Application.CallCenter.Calls;
+using Hotline.Application.CallCenter;
 
 namespace Hotline.Api;
 
@@ -112,6 +113,7 @@ internal static class StartupExtensions
                 break;
             case "TianRun":
                 services
+                    .AddScoped<ICallApplication, TianRunCallApplication>()
                     .AddScoped<ITrApplication, TrApplication>()
                     .AddHostedService<CurrentWaitNumService>()
                     .AddHostedService<TelsStatusRefreshService>()
@@ -120,7 +122,9 @@ internal static class StartupExtensions
                         callCenterConfiguration.TianRun.Password);
                 break;
             case "XingTang":
-                services.AddXingTangDb(callCenterConfiguration.XingTang);
+                services.AddXingTangDb(callCenterConfiguration.XingTang)
+                    .AddScoped<ICallApplication, XingTangCallApplication>()
+                    ;
                 break;
             default:
                 break;

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

@@ -1,7 +1,7 @@
 {
   "AllowedHosts": "*",
   "CallCenterConfiguration": {
-    "CallCenterType": "TianRun", //XunShi、WeiErXin、TianRun、XingTang
+    "CallCenterType": "XingTang", //XunShi、WeiErXin、TianRun、XingTang
     "NewRock": {
       "Address": "http://192.168.100.100/xml",
       "Authorize": true,
@@ -28,7 +28,7 @@
     }
   },
   "ConnectionStrings": {
-    "Hotline": "PORT=5432;DATABASE=hotline;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;"
+    "Hotline": "PORT=5432;DATABASE=hotline_dev;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;"
     //"Redis": "110.188.24.182:50179,password=fengwo22@@",
     //"MongoDB": "mongodb://192.168.100.121:27017",
     //"Wex": "server=222.212.82.225;Port=4509;Database=fs_kft;Uid=root;Pwd=Wex@12345;"
@@ -37,7 +37,7 @@
     "Host": "110.188.24.182",
     "Port": 50179,
     "Password": "fengwo123!$!$",
-    "Database": 3
+    "Database": 5
   },
   "Swagger": true,
   "Cors": {

+ 1 - 1
src/Hotline.Application.Contracts/Validators/CallCenter/AddBlacklistDtoValidator.cs

@@ -7,7 +7,7 @@ namespace Hotline.Application.Contracts.Validators.CallCenter
     {
         public AddBlacklistDtoValidator()
         {
-            RuleFor(d => d.PhoneNo).NotEmpty();
+            RuleFor(d => d.Phone).NotEmpty();
             RuleFor(d => d.Duration).NotEmpty();
         }
     }

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

@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Hotline.CallCenter.BlackLists;
+using Hotline.Share.Dtos.CallCenter;
+using Hotline.Share.Dtos.TrCallCenter;
+
+namespace Hotline.Application.CallCenter
+{
+    public interface ICallApplication
+    {
+        /// <summary>
+        /// 查询分机
+        /// </summary>
+        Task<IReadOnlyList<TelDto>> QueryTelsAsync(CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 查询分机组
+        /// </summary>
+        Task<IReadOnlyList<TelGroupDto>> QueryTelGroupsAsync(CancellationToken cancellationToken);
+
+        #region 黑名单
+
+        Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken);
+        Task RemoveBlackListAsync(string id, CancellationToken cancellationToken);
+        Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken);
+
+        #endregion
+
+        /// <summary>
+        /// 签入
+        /// </summary>
+        Task<TrOnDutyResponseDto> SignInAsync(SignInDto dto, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 签出
+        /// </summary>
+        Task SingOutAsync(CancellationToken cancellationToken);
+    }
+}

+ 68 - 0
src/Hotline.Application/CallCenter/TianRunCallApplication.cs

@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Hotline.Application.CallCenter.Calls;
+using Hotline.Application.Tels;
+using Hotline.CallCenter.BlackLists;
+using Hotline.Share.Dtos.CallCenter;
+using Hotline.Share.Dtos.TrCallCenter;
+using Hotline.Share.Enums.CallCenter;
+using Microsoft.AspNetCore.Http;
+using XF.Domain.Authentications;
+
+namespace Hotline.Application.CallCenter
+{
+    public class TianRunCallApplication : ICallApplication
+    {
+        private readonly ISessionContext _sessionContext;
+        private readonly ITrApplication _trApplication;
+        private readonly ITelApplication _telApplication;
+
+        public TianRunCallApplication(
+            ISessionContext sessionContext,
+            ITrApplication trApplication,
+            ITelApplication telApplication)
+        {
+            _sessionContext = sessionContext;
+            _trApplication = trApplication;
+            _telApplication = telApplication;
+        }
+
+        public Task<IReadOnlyList<TelDto>> QueryTelsAsync(CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task<IReadOnlyList<TelGroupDto>> QueryTelGroupsAsync(CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task RemoveBlackListAsync(string id, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public async Task<TrOnDutyResponseDto> SignInAsync(SignInDto dto, CancellationToken cancellationToken)
+        {
+            return await _trApplication.OnSign(_sessionContext.RequiredUserId, dto.TelNo, (ETelModel)dto.TelModelState, cancellationToken);
+        }
+
+        public async Task SingOutAsync(CancellationToken cancellationToken)
+        {
+            await _telApplication.SignOutAsync(_sessionContext.RequiredUserId, cancellationToken);
+        }
+    }
+}

+ 128 - 0
src/Hotline.Application/CallCenter/XingTangCallApplication.cs

@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Hotline.Caching.Interfaces;
+using Hotline.CallCenter.BlackLists;
+using Hotline.CallCenter.Tels;
+using Hotline.Repository.SqlSugar.CallCenter;
+using Hotline.Share.Dtos.CallCenter;
+using Hotline.Share.Dtos.TrCallCenter;
+using Hotline.Users;
+using XF.Domain.Authentications;
+using XF.Domain.Cache;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.CallCenter
+{
+    public class XingTangCallApplication : ICallApplication
+    {
+        private readonly IRepository<Tel> _telRepository;
+        private readonly IRepository<TelGroup> _telGroupRepository;
+        private readonly IWorkRepository _workRepository;
+        private readonly ITelRestRepository _telRestRepository;
+        private readonly ITypedCache<Work> _cacheWork;
+        private readonly IUserCacheManager _userCacheManager;
+        private readonly ISessionContext _sessionContext;
+
+        public XingTangCallApplication(
+            IRepository<Tel> telRepository,
+            IRepository<TelGroup> telGroupRepository,
+            IWorkRepository workRepository,
+            ITelRestRepository telRestRepository,
+            ITypedCache<Work> cacheWork,
+            IUserCacheManager userCacheManager,
+            ISessionContext sessionContext)
+        {
+            _telRepository = telRepository;
+            _telGroupRepository = telGroupRepository;
+            _workRepository = workRepository;
+            _telRestRepository = telRestRepository;
+            _cacheWork = cacheWork;
+            _userCacheManager = userCacheManager;
+            _sessionContext = sessionContext;
+        }
+
+        public async Task<IReadOnlyList<TelDto>> QueryTelsAsync(CancellationToken cancellationToken)
+        {
+            return await _telRepository.Queryable()
+                .Select<TelDto>()
+                .ToListAsync(cancellationToken);
+        }
+
+        public async Task<IReadOnlyList<TelGroupDto>> QueryTelGroupsAsync(CancellationToken cancellationToken)
+        {
+            return await _telGroupRepository.Queryable()
+                .Select<TelGroupDto>()
+                .ToListAsync(cancellationToken);
+        }
+
+        public Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task RemoveBlackListAsync(string id, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public async Task<TrOnDutyResponseDto> SignInAsync(SignInDto dto, CancellationToken cancellationToken)
+        {
+            if (string.IsNullOrEmpty(dto.TelNo))
+                throw UserFriendlyException.SameMessage("无效分机号");
+            var work = _userCacheManager.GetWorkByUserNoExp(_sessionContext.RequiredUserId);
+            if (work is not null)
+            {
+                //if (work.TelNo != dto.TelNo)
+                //{
+                //    throw UserFriendlyException.SameMessage("当前用户已签入其他分机");
+                //}
+                throw UserFriendlyException.SameMessage("当前用户已签入");
+            }
+
+            var telWork = _userCacheManager.GetWorkByTelNoExp(dto.TelNo);
+            if (telWork is not null)
+            {
+                throw UserFriendlyException.SameMessage("当前分机已被占用");
+            }
+
+            work = new Work(_sessionContext.RequiredUserId, _sessionContext.UserName,
+                dto.TelNo, dto.TelNo, null, null,
+                dto.GroupId, _sessionContext.StaffNo, null);
+            await _workRepository.AddAsync(work, cancellationToken);
+
+            return new TrOnDutyResponseDto
+            {
+                TelNo = dto.TelNo,
+                QueueId = dto.GroupId,
+                StartTime = work.StartTime,
+            };
+        }
+
+        public async Task SingOutAsync(CancellationToken cancellationToken)
+        {
+            var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
+            if (work is null) return;
+
+            var telRest = await _telRestRepository.GetAsync(x => x.TelNo == work.TelNo && !x.EndTime.HasValue, cancellationToken);
+            if (telRest is not null)
+            {
+                telRest.EndRest();
+                await _telRestRepository.UpdateAsync(telRest, cancellationToken);
+            }
+
+            work.OffDuty();
+            await _workRepository.UpdateAsync(work, cancellationToken);
+            _cacheWork.Remove(work.GetKey(KeyMode.UserId));
+            _cacheWork.Remove(work.GetKey(KeyMode.TelNo));
+        }
+    }
+}

+ 331 - 8
src/Hotline.Application/JudicialManagement/EnforcementApplication.cs

@@ -1,12 +1,15 @@
-using Consul;
-using Hotline.Caching.Interfaces;
+using Hotline.Caching.Interfaces;
 using Hotline.JudicialManagement;
+using Hotline.Orders;
 using Hotline.Settings;
 using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.JudicialManagement;
+using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.JudicialManagement;
+using Hotline.Share.Enums.Order;
 using MapsterMapper;
 using SqlSugar;
-using XF.Domain.Constants;
+using XF.Domain.Authentications;
 using XF.Domain.Dependency;
 using XF.Domain.Repository;
 
@@ -15,20 +18,19 @@ namespace Hotline.Application.JudicialManagement
     public class EnforcementApplication : IEnforcementApplication, IScopeDependency
     {
         private readonly IRepository<EnforcementOrderHander> _enforcementOrderHanderRepository;
-        private readonly IRepository<EnforcementOrders> _enforcementOrdersRepository;
         private readonly IRepository<EnforcementHotspot> _enforcementHotspotRepository;
         private readonly ISystemDicDataCacheManager _sysDicDataCacheManager;
         private readonly ISystemSettingCacheManager _systemSettingCacheManager;
         private readonly IRepository<JudicialManagementOrders> _judicialManagementOrdersRepository;
         private readonly IRepository<EnforcementOrdersHandler> _enforcementOrdersHandlerRepository;
         private readonly IMapper _mapper;
+        private readonly ISessionContext _sessionContext;
 
 
         /// <summary>
         /// 
         /// </summary>
         /// <param name="enforcementOrderHanderRepository"></param>
-        /// <param name="enforcementOrdersRepository"></param>
         /// <param name="enforcementHotspotRepository"></param>
         /// <param name="sysDicDataCacheManager"></param>
         /// <param name="systemSettingCacheManager"></param>
@@ -36,22 +38,22 @@ namespace Hotline.Application.JudicialManagement
         /// <param name="enforcementOrdersHandlerRepository"></param>
         /// <param name="mapper"></param>
         public EnforcementApplication(IRepository<EnforcementOrderHander> enforcementOrderHanderRepository,
-           IRepository<EnforcementOrders> enforcementOrdersRepository,
            IRepository<EnforcementHotspot> enforcementHotspotRepository,
            ISystemDicDataCacheManager sysDicDataCacheManager,
            ISystemSettingCacheManager systemSettingCacheManager,
            IRepository<JudicialManagementOrders> judicialManagementOrdersRepository,
            IRepository<EnforcementOrdersHandler> enforcementOrdersHandlerRepository,
-           IMapper mapper)
+           IMapper mapper,
+           ISessionContext sessionContext)
         {
             _enforcementOrderHanderRepository = enforcementOrderHanderRepository;
-            _enforcementOrdersRepository = enforcementOrdersRepository;
             _enforcementHotspotRepository = enforcementHotspotRepository;
             _sysDicDataCacheManager = sysDicDataCacheManager;
             _systemSettingCacheManager = systemSettingCacheManager;
             _judicialManagementOrdersRepository = judicialManagementOrdersRepository;
             _enforcementOrdersHandlerRepository = enforcementOrdersHandlerRepository;
             _mapper = mapper;
+            _sessionContext = sessionContext;
         }
 
         /// <summary>
@@ -95,6 +97,7 @@ namespace Hotline.Application.JudicialManagement
                 {
                     //处理工单
                     _mapper.Map(order, orderData);
+                    orderData.Id = order.Id;
                     orderData.IsEnforcementOrder = order.IsEnforcementOrder.HasValue ? order.IsEnforcementOrder.Value : false;
                     orderData.IsTheClueTrue = null;
                     orderData.IsPassTheBuckOrder = false;
@@ -183,6 +186,7 @@ namespace Hotline.Application.JudicialManagement
                     {
                         //处理工单
                         _mapper.Map(order, orderData);
+                        orderData.Id = order.Id;
                         orderData.IsEnforcementOrder = order.IsEnforcementOrder.HasValue ? order.IsEnforcementOrder.Value : false;
                         orderData.IsTheClueTrue = null;
                         orderData.IsPassTheBuckOrder = true;
@@ -217,5 +221,324 @@ namespace Hotline.Application.JudicialManagement
                 }
             }
         }
+
+        /// <summary>
+        /// 受理工单
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<JudicialManagementOrders> GetOwnOrderList(QueryEnforcementOrderNewDto dto)
+        {
+            return _judicialManagementOrdersRepository.Queryable()
+                .Where(d => d.CreatorId == _sessionContext.UserId)
+                  .WhereIF(dto.IsEnforcementOrder.HasValue, d => d.IsEnforcementOrder == dto.IsEnforcementOrder)//是否行政执法类
+                  .WhereIF(dto.IsPassTheBuckOrder.HasValue, d => d.IsPassTheBuckOrder == dto.IsPassTheBuckOrder)//是否推诿
+                   .WhereIF(dto.IsTheClueTrue.HasValue, d => d.IsTheClueTrue == dto.IsTheClueTrue)//线索是否属实
+                   .WhereIF(!string.IsNullOrEmpty(dto.EventTypeId), d => dto.EventTypeId == d.EventTypeId)//事项分类
+                   .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title!)) //标题
+                   .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No)) //工单编码
+                   .WhereIF(!string.IsNullOrEmpty(dto.AcceptTypeCode), d => d.AcceptTypeCode == dto.AcceptTypeCode) //受理类型
+                   .WhereIF(!string.IsNullOrEmpty(dto.ChannelCode), d => d.SourceChannelCode == dto.ChannelCode) //来源渠道
+                    .WhereIF(!string.IsNullOrEmpty(dto.HotspotId), d => d.TransferPhone == dto.HotspotId) //热点类型
+                    .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName.Contains(dto.NameOrNo!) || d.AcceptorStaffNo.Contains(dto.NameOrNo!)) //受理人/坐席
+                    .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
+                   .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
+                     .WhereIF(!string.IsNullOrEmpty(dto.FromName), d => d.FromName == dto.FromName) //来电人姓名
+                     .WhereIF(!string.IsNullOrEmpty(dto.AreaCode), d => d.AreaCode == dto.AreaCode) //区域
+                     .WhereIF(!string.IsNullOrEmpty(dto.OrgCode), d => SqlFunc.JsonListObjectAny(d.EnforcementOrdersHandler, "Value", dto.OrgCode))//执法部门
+                     .OrderByDescending(d => d.CreationTime)
+                    .MergeTable();
+        }
+
+        /// <summary>
+        /// 司法行政监督管理工单查询
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<JudicialManagementOrders> GetOrderList(QueryEnforcementOrderNewDto dto)
+        {
+            var areaCode = _sessionContext.OrgAreaCode ?? "511500";
+
+            return _judicialManagementOrdersRepository.Queryable()
+                    .WhereIF(areaCode != "511500", d => d.AreaCode.StartsWith(areaCode))
+                    .WhereIF(dto.IsEnforcementOrder.HasValue, d => d.IsEnforcementOrder == dto.IsEnforcementOrder)//是否行政执法类
+                    .WhereIF(dto.IsPassTheBuckOrder.HasValue, d => d.IsPassTheBuckOrder == dto.IsPassTheBuckOrder)//是否推诿
+                     .WhereIF(dto.IsTheClueTrue.HasValue, d => d.IsTheClueTrue == dto.IsTheClueTrue)//线索是否属实
+                     .WhereIF(!string.IsNullOrEmpty(dto.EventTypeId), d => dto.EventTypeId == d.EventTypeId)//事项分类
+                     .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title!)) //标题
+                     .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No)) //工单编码
+                     .WhereIF(!string.IsNullOrEmpty(dto.AcceptTypeCode), d => d.AcceptTypeCode == dto.AcceptTypeCode) //受理类型
+                     .WhereIF(!string.IsNullOrEmpty(dto.ChannelCode), d => d.SourceChannelCode == dto.ChannelCode) //来源渠道
+                      .WhereIF(!string.IsNullOrEmpty(dto.HotspotId), d => d.TransferPhone == dto.HotspotId) //热点类型
+                      .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName.Contains(dto.NameOrNo!) || d.AcceptorStaffNo.Contains(dto.NameOrNo!)) //受理人/坐席
+                      .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
+                     .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
+                       .WhereIF(!string.IsNullOrEmpty(dto.FromName), d => d.FromName == dto.FromName) //来电人姓名
+                       .WhereIF(!string.IsNullOrEmpty(dto.AreaCode), d => d.AreaCode == dto.AreaCode) //区域
+                       .WhereIF(!string.IsNullOrEmpty(dto.OrgCode), d => SqlFunc.JsonListObjectAny(d.EnforcementOrdersHandler, "Value", dto.OrgCode))//执法部门
+                       .OrderByDescending(d => d.CreationTime)
+                      .MergeTable();
+
+        }
+
+        /// <summary>
+        /// 事项分类统计--明细
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<JudicialManagementOrders> GetEventClassificationStatisticsOrderListAsync(QueryEventClassificationStatisticsDto dto)
+        {
+            string areCodeText = "";
+            if (string.IsNullOrEmpty(dto.AreaCode))
+            {
+                if (_sessionContext.OrgAreaCode != "511500")
+                    areCodeText = _sessionContext.OrgAreaCode;
+            }
+            else
+                areCodeText = dto.AreaCode;
+
+            return _judicialManagementOrdersRepository.Queryable()
+            .Where(d => d.CreationTime >= dto.StartTime && d.CreationTime <= dto.EndTime && d.EventTypeId != null)
+            .WhereIF(!string.IsNullOrEmpty(dto.EventTypeId), d => d.EventTypeId.StartsWith(dto.EventTypeId))
+            .WhereIF(!string.IsNullOrEmpty(areCodeText), d => d.AreaCode.StartsWith(areCodeText))
+            .OrderByDescending(d => d.CreationTime)
+            .MergeTable();
+        }
+
+        /// <summary>
+        /// 执法部门办件统计
+        /// </summary>
+        /// <param name="StartTime"></param>
+        /// <param name="EndTime"></param>
+        /// <returns></returns>
+        public ISugarQueryable<EmDepartmentalProcessingStatisticsDto> GetDepartmentalProcessingStatisticsAsync(DateTime StartTime, DateTime EndTime)
+        {
+            return _enforcementOrdersHandlerRepository.Queryable()
+                   .LeftJoin<JudicialManagementOrders>((h, o) => h.OrderId == o.Id)
+                   .Where((h, o) => o.CreationTime >= StartTime && o.CreationTime <= EndTime)
+                    .GroupBy((h, o) => new
+                    {
+                        OrgCode = h.OrgCode,
+                        OrgName = h.OrgName
+                    })
+                    .Select((h, o) => new EmDepartmentalProcessingStatisticsDto
+                    {
+                        OrgCode = h.OrgCode,
+                        OrgName = h.OrgName,
+                        CountNum = SqlFunc.AggregateSum(SqlFunc.IIF(h.OrgCode != null, 1, 0)),
+                        TheClueIsTrue = SqlFunc.AggregateSum(SqlFunc.IIF(o.IsTheClueTrue.HasValue && o.IsTheClueTrue.Value == true, 1, 0)),
+                        TheClueIsNotTrue = SqlFunc.AggregateSum(SqlFunc.IIF(o.IsTheClueTrue.HasValue && o.IsTheClueTrue.Value == false, 1, 0)),
+                        EnforcementOrder = SqlFunc.AggregateSum(SqlFunc.IIF(o.IsEnforcementOrder.HasValue && o.IsEnforcementOrder.Value == true, 1, 0))
+                    })
+                      .MergeTable();
+        }
+
+        /// <summary>
+        /// 执法部门办件统计---明细
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<EnforcementOrderListDto> GetDepartmentalProcessingStatisticsOrderListAsync(QueryDepartmentalProcessingStatisticsDto dto)
+        {
+            return _enforcementOrdersHandlerRepository.Queryable()
+                 .LeftJoin<JudicialManagementOrders>((x, o) => x.OrderId == o.Id)
+                 .Where((x, o) => o.CreationTime >= dto.StartTime && o.CreationTime <= dto.EndTime && o.Id != null)
+                 .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.OrgCode == "001", (x, o) => x.OrgCode == dto.OrgCode)
+                 .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.OrgCode != "001", (x, o) => x.OrgCode.StartsWith(dto.OrgCode))
+                 .WhereIF(dto.TheClueIsTrue == true, (x, o) => o.IsTheClueTrue == true)
+                 .WhereIF(dto.TheClueIsNotTrue == true, (x, o) => o.IsTheClueTrue == false)
+                 .WhereIF(dto.EnforcementOrder == true, (x, o) => o.IsEnforcementOrder == true)
+                 .OrderByDescending((x, o) => o.CreationTime)
+                   .Select((x, o) => new EnforcementOrderListDto
+                   {
+                       Id = o.Id,
+                       No = o.No,
+                       SourceChannel = o.SourceChannel,
+                       SourceChannelCode = o.SourceChannelCode,
+                       FromPhone = o.FromPhone,
+                       TransferPhone = o.TransferPhone,
+                       FromName = o.FromName,
+                       Contact = o.Contact,
+                       AcceptType = o.AcceptType,
+                       AcceptTypeCode = o.AcceptTypeCode,
+                       Title = o.Title,
+                       HotspotId = o.HotspotId,
+                       HotspotName = o.HotspotName,
+                       HotspotSpliceName = o.HotspotSpliceName,
+                       CreationTime = o.CreationTime,
+                       Province = o.Province,
+                       City = o.City,
+                       County = o.County,
+                       Town = o.Town,
+                       IsEnforcementOrder = o.IsEnforcementOrder,
+                       IsPassTheBuckOrder = o.IsPassTheBuckOrder,
+                       IsTheClueTrue = o.IsTheClueTrue,
+                       EventTypeId = o.EventTypeId,
+                       EventTypeName = o.EventTypeName,
+                       EventTypeSpliceName = o.EventTypeSpliceName,
+                       AcceptorId = o.AcceptorId,
+                       AcceptorName = o.AcceptorName,
+                       AcceptorStaffNo = o.AcceptorStaffNo,
+                       AcceptorOrgCode = o.AcceptorOrgCode,
+                       AcceptorOrgName = o.AcceptorOrgName,
+                   })
+                .MergeTable();
+        }
+
+        /// <summary>
+        /// 区域分类统计
+        /// </summary>
+        /// <returns></returns>
+        public ISugarQueryable<RegionalClassificationStatisticsDto> GetRegionalClassificationStatisticsAsync(DateTime StartTime, DateTime EndTime)
+        {
+            var areaCode = _sessionContext.OrgAreaCode ?? "511500";
+            return _judicialManagementOrdersRepository.Queryable()
+                .Where(x => x.CreationTime >= StartTime && x.CreationTime <= EndTime)
+                .LeftJoin<SystemArea>((x, o) => x.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) == o.Id)
+                .WhereIF(areaCode != "511500", (x, o) => x.AreaCode.StartsWith(areaCode))
+                .GroupBy((x, o) => new
+                {
+                    AreaCode = x.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
+                    o.AreaName,
+                })
+                .Select((x, o) => new RegionalClassificationStatisticsDto
+                {
+                    AreaCode = x.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
+                    AreaName = o.AreaName,
+                    OrderCountNum = SqlFunc.AggregateCount(x.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6"))),
+                    TheClueIsTrue = SqlFunc.AggregateSum(SqlFunc.IIF(x.IsTheClueTrue.HasValue && x.IsTheClueTrue.Value == true, 1, 0)),
+                    TheClueIsNotTrue = SqlFunc.AggregateSum(SqlFunc.IIF(x.IsTheClueTrue.HasValue && x.IsTheClueTrue.Value == false, 1, 0)),
+                    EnforcementOrder = SqlFunc.AggregateSum(SqlFunc.IIF(x.IsEnforcementOrder.HasValue && x.IsEnforcementOrder.Value == true, 1, 0))
+                }).MergeTable()
+                 .Where(x => x.AreaCode != "519800" && x.AreaCode != "519900")
+                 .OrderByDescending(it => it.OrderCountNum)
+               .MergeTable();
+        }
+
+        /// <summary>
+        /// 区域分类统计---明细
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<JudicialManagementOrders> GetRegionalClassificationStatisticsOrderListAsync(QueryRegionalClassificationStatisticsDto dto)
+        {
+            return _judicialManagementOrdersRepository.Queryable()
+            .Where(d => d.CreationTime >= dto.StartTime && d.CreationTime <= dto.EndTime)
+            .WhereIF(!string.IsNullOrEmpty(dto.AreaCode), d => d.AreaCode.StartsWith(dto.AreaCode))
+            .WhereIF(dto.TheClueIsTrue == true, d => d.IsTheClueTrue == true)
+            .WhereIF(dto.TheClueIsNotTrue == true, d => d.IsTheClueTrue == false)
+            .WhereIF(dto.EnforcementOrder == true, d => d.IsEnforcementOrder == true)
+            .OrderByDescending(d => d.CreationTime)
+            .MergeTable();
+
+        }
+
+        /// <summary>
+        /// 部门满意度统计
+        /// </summary>
+        /// <param name="StartTime"></param>
+        /// <param name="EndTime"></param>
+        /// <param name="TypeId">1:办件结果 2:办件态度</param>
+        /// <returns></returns>
+        public ISugarQueryable<VisitAndOrgSatisfactionStatisticsDto> GetVisitAndOrgSatisfactionStatisticsAsync(DateTime StartTime, DateTime EndTime, int TypeId)
+        {
+            EndTime = EndTime.AddDays(1).AddSeconds(-1);
+
+            return _judicialManagementOrdersRepository.Queryable()
+                 .LeftJoin<OrderVisit>((x, o) => x.Id == o.OrderId)
+                 .LeftJoin<OrderVisitDetail>((x, o, p) => o.Id == p.VisitId)
+                .Where((x, o, p) => o.VisitTime >= StartTime && o.VisitTime <= EndTime && p.VisitTarget == EVisitTarget.Org
+                && o.VisitState == EVisitState.Visited && !string.IsNullOrEmpty(p.VisitOrgCode) && x.OrderSoure == EOrderSoure.Hotline)
+                .GroupBy((x, o, p) => new
+                {
+                    VisitOrgCode = p.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6"))
+                })
+                .Select((x, o, p) => new VisitAndOrgSatisfactionStatisticsDto()
+                {
+                    OrgCode = p.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
+                    TotalSumCount = SqlFunc.AggregateCount(p.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6"))),
+                    VerySatisfiedCount = SqlFunc.IIF(TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgProcessingResults, "Key") == "5", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == "5", 1, 0))),//非常满意数
+                    SatisfiedCount = SqlFunc.IIF(TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgProcessingResults, "Key") == "4", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == "4", 1, 0))), //满意数
+                    RegardedAsSatisfiedCount = SqlFunc.IIF(TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgProcessingResults, "Key") == "-1", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == "-1", 1, 0))),//视为满意
+                    DefaultSatisfiedCount = SqlFunc.IIF(TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgProcessingResults, "Key") == "0", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == "0", 1, 0))),//默认满意
+                    NoSatisfiedCount = SqlFunc.IIF(TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgProcessingResults, "Key") == "2", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == "2", 1, 0))),//不满意
+                    NoEvaluateCount = SqlFunc.IIF(TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgProcessingResults, "Key") == "7", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == "7", 1, 0))),//未做评价
+                    NoPutThroughCount = SqlFunc.IIF(TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgProcessingResults, "Key") == "6", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == "6", 1, 0))),//未接通
+                })
+                .MergeTable()
+                .LeftJoin<SystemOrganize>((it, o) => it.OrgCode == o.Id)
+                .Select((it, o) => new VisitAndOrgSatisfactionStatisticsDto()
+                {
+                    OrgName = o.Name,
+                    OrgCode = it.OrgCode,
+                    OrgType = o.OrgType,
+                    TotalSumCount = it.TotalSumCount,
+                    VerySatisfiedCount = it.VerySatisfiedCount,//非常满意数
+                    SatisfiedCount = it.SatisfiedCount, //满意数
+                    RegardedAsSatisfiedCount = it.RegardedAsSatisfiedCount,//视为满意
+                    DefaultSatisfiedCount = it.DefaultSatisfiedCount,//默认满意
+                    NoSatisfiedCount = it.NoSatisfiedCount,//不满意
+                    NoEvaluateCount = it.NoEvaluateCount,//未做评价
+                    NoPutThroughCount = it.NoPutThroughCount,//未接通
+                })
+                .MergeTable();
+
+        }
+
+        /// <summary>
+        /// 部门满意度统计---明细
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<EnforcementOrgSatisfactionOrderListDto> GetVisitAndOrgSatisfactionStatisticsOrderListAsync(QueryOrgSatisfactionStatisticsDto dto)
+        {
+            return _judicialManagementOrdersRepository.Queryable()
+                .LeftJoin<OrderVisit>((x, o) => x.Id == o.OrderId)
+                .LeftJoin<OrderVisitDetail>((x, o, p) => o.Id == p.VisitId)
+                .Where((x, o, p) => o.VisitTime >= dto.StartTime && o.VisitTime <= dto.EndTime && p.VisitTarget == EVisitTarget.Org && x.OrderSoure == EOrderSoure.Hotline)
+                .Where((x, o, p) => o.VisitState == EVisitState.Visited && !string.IsNullOrEmpty(p.VisitOrgCode))
+                .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.OrgCode == "001", (x, o, p) => p.VisitOrgCode == dto.OrgCode)
+                .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.OrgCode != "001", (x, o, p) => p.VisitOrgCode.StartsWith(dto.OrgCode))
+                 .WhereIF(dto.TypeId == 1, (x, o, p) => SqlFunc.JsonField(p.OrgProcessingResults, "Key") == dto.DateValue)
+                .WhereIF(dto.TypeId == 2, (x, o, p) => SqlFunc.JsonField(p.OrgHandledAttitude, "Key") == dto.DateValue)
+                .Select((x, o, p) => new EnforcementOrgSatisfactionOrderListDto
+                {
+                    Id = x.Id,
+                    No = x.No,
+                    SourceChannel = x.SourceChannel,
+                    SourceChannelCode = x.SourceChannelCode,
+                    FromPhone = x.FromPhone,
+                    TransferPhone = x.TransferPhone,
+                    FromName = x.FromName,
+                    Contact = x.Contact,
+                    AcceptType = x.AcceptType,
+                    AcceptTypeCode = x.AcceptTypeCode,
+                    Title = x.Title,
+                    HotspotId = x.HotspotId,
+                    HotspotName = x.HotspotName,
+                    HotspotSpliceName = x.HotspotSpliceName,
+                    CreationTime = x.CreationTime,
+                    Province = x.Province,
+                    City = x.City,
+                    County = x.County,
+                    Town = x.Town,
+                    IsEnforcementOrder = x.IsEnforcementOrder,
+                    IsPassTheBuckOrder = x.IsPassTheBuckOrder,
+                    IsTheClueTrue = x.IsTheClueTrue,
+                    EventTypeId = x.EventTypeId,
+                    EventTypeName = x.EventTypeName,
+                    EventTypeSpliceName = x.EventTypeSpliceName,
+                    AcceptorId = x.AcceptorId,
+                    AcceptorName = x.AcceptorName,
+                    AcceptorStaffNo = x.AcceptorStaffNo,
+                    AcceptorOrgCode = x.AcceptorOrgCode,
+                    AcceptorOrgName = x.AcceptorOrgName,
+                    VisitId = p.VisitId
+                })
+               .MergeTable();
+
+
+        }
+
     }
 }

+ 72 - 1
src/Hotline.Application/JudicialManagement/IEnforcementApplication.cs

@@ -1,4 +1,9 @@
-namespace Hotline.Application.JudicialManagement
+using Hotline.JudicialManagement;
+using Hotline.Share.Dtos.JudicialManagement;
+using Hotline.Share.Dtos.Order;
+using SqlSugar;
+
+namespace Hotline.Application.JudicialManagement
 {
     public interface IEnforcementApplication
     {
@@ -19,5 +24,71 @@
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         Task AddPassTheBuckOrderAsync(Hotline.Orders.Order order, string orgCode, string orgName, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 受理工单
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<JudicialManagementOrders> GetOwnOrderList(QueryEnforcementOrderNewDto dto);
+
+        /// <summary>
+        /// 司法行政监督管理工单查询
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<JudicialManagementOrders> GetOrderList(QueryEnforcementOrderNewDto dto);
+
+        /// <summary>
+        /// 事项分类统计--明细
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<JudicialManagementOrders> GetEventClassificationStatisticsOrderListAsync(QueryEventClassificationStatisticsDto dto);
+
+        /// <summary>
+        /// 执法部门办件统计
+        /// </summary>
+        /// <param name="StartTime"></param>
+        /// <param name="EndTime"></param>
+        /// <returns></returns>
+        ISugarQueryable<EmDepartmentalProcessingStatisticsDto> GetDepartmentalProcessingStatisticsAsync(DateTime StartTime, DateTime EndTime);
+
+        /// <summary>
+        /// 执法部门办件统计---明细
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<EnforcementOrderListDto> GetDepartmentalProcessingStatisticsOrderListAsync(QueryDepartmentalProcessingStatisticsDto dto);
+
+        /// <summary>
+        /// 区域分类统计
+        /// </summary>
+        /// <returns></returns>
+        ISugarQueryable<RegionalClassificationStatisticsDto> GetRegionalClassificationStatisticsAsync(DateTime StartTime, DateTime EndTime);
+
+        /// <summary>
+        /// 区域分类统计---明细
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<JudicialManagementOrders> GetRegionalClassificationStatisticsOrderListAsync(QueryRegionalClassificationStatisticsDto dto);
+
+        /// <summary>
+        /// 部门满意度统计
+        /// </summary>
+        /// <param name="StartTime"></param>
+        /// <param name="EndTime"></param>
+        /// <param name="TypeId">1:办件结果 2:办件态度</param>
+        /// <returns></returns>
+        ISugarQueryable<VisitAndOrgSatisfactionStatisticsDto> GetVisitAndOrgSatisfactionStatisticsAsync(DateTime StartTime, DateTime EndTime, int TypeId);
+
+        /// <summary>
+        /// 部门满意度统计---明细
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<EnforcementOrgSatisfactionOrderListDto> GetVisitAndOrgSatisfactionStatisticsOrderListAsync(QueryOrgSatisfactionStatisticsDto dto);
+
     }
 }

+ 3 - 1
src/Hotline.Repository.SqlSugar/Extensions/XingTangDbExtensions.cs

@@ -7,7 +7,7 @@ namespace Hotline.Repository.SqlSugar.Extensions;
 
 public static class XingTangDbExtensions
 {
-    public static void AddXingTangDb(this IServiceCollection services, XingTangConfiguration xingTangConfiguration)
+    public static IServiceCollection AddXingTangDb(this IServiceCollection services, XingTangConfiguration xingTangConfiguration)
     {
         SqlSugarScope sqlSugar = new SqlSugarScope(new ConnectionConfig()
         {
@@ -20,5 +20,7 @@ public static class XingTangDbExtensions
 
         ISugarUnitOfWork<XingTangDbContext> context = new SugarUnitOfWork<XingTangDbContext>(sqlSugar);
         services.AddSingleton(context);
+
+        return services;
     }
 }

+ 1 - 1
src/Hotline.Share/Dtos/CallCenter/AddBlacklistDto.cs

@@ -1,4 +1,4 @@
 namespace Hotline.Share.Dtos.CallCenter
 {
-    public record AddBlacklistDto(string PhoneNo, double Duration);
+    public record AddBlacklistDto(string Phone, double Duration, int? SpecialFlag);
 }

+ 29 - 0
src/Hotline.Share/Dtos/CallCenter/SignInDto.cs

@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.CallCenter
+{
+    /// <summary>
+    /// 签入
+    /// </summary>
+    public class SignInDto
+    {
+        /// <summary>
+        /// 分机号
+        /// </summary>
+        public string? TelNo { get; set; }
+
+        /// <summary>
+        /// 分机组id
+        /// </summary>
+        public string? GroupId { get; set; }
+
+        /// <summary>
+        /// 兼容添润签入参数
+        /// </summary>
+        public int TelModelState { get; set; }
+    }
+}

+ 17 - 0
src/Hotline.Share/Dtos/CallCenter/TelDto.cs

@@ -63,6 +63,23 @@ namespace Hotline.Share.Dtos.CallCenter
         public string GroupNames => string.Join(",", Groups?.Select(x => x.Name) ?? new List<string>());
 
         public List<TelGroupDto> Groups { get; set; }
+
+        #region 兼容添润字段
+        
+        public string Name { get; set; }
+
+        public string TelNo { get; set; }
+
+        public string Description { get; set; }
+
+        public string QueueId { get; set; }
+
+        /// <summary>
+        /// 外呼分机组(由内部系统提供)
+        /// </summary>
+        public string? CallOutQueue { get; set; }
+
+        #endregion
     }
 
    

+ 22 - 0
src/Hotline.Share/Dtos/JudicialManagement/EmDepartmentalProcessingStatisticsDto.cs

@@ -0,0 +1,22 @@
+namespace Hotline.Share.Dtos.JudicialManagement
+{
+    public class EmDepartmentalProcessingStatisticsDto
+    {
+        public string OrgCode { get; set; }
+        public string OrgName { get; set; }
+        public int CountNum { get; set; }
+        public int TheClueIsTrue { get; set; }
+        public int TheClueIsNotTrue { get; set; }
+        public int EnforcementOrder { get; set; }
+    }
+
+    public class RegionalClassificationStatisticsDto
+    {
+        public string AreaCode { get; set; }
+        public string AreaName { get; set; }
+        public int OrderCountNum { get; set; }
+        public int TheClueIsTrue { get; set; }
+        public int TheClueIsNotTrue { get; set; }
+        public int EnforcementOrder { get; set; }
+    }
+}

+ 58 - 6
src/Hotline.Share/Dtos/JudicialManagement/EnforcementOrderListDto.cs

@@ -1,4 +1,5 @@
 using Hotline.Share.Enums.Order;
+using System.Diagnostics.Metrics;
 
 namespace Hotline.Share.Dtos.JudicialManagement
 {
@@ -48,11 +49,6 @@ namespace Hotline.Share.Dtos.JudicialManagement
         public string? AcceptType { get; set; }
         public string? AcceptTypeCode { get; set; }
 
-        /// <summary>
-        /// 紧急程度
-        /// </summary>
-        public EEmergencyLevel EmergencyLevel { get; set; }
-
         /// <summary>
         /// 标题
         /// </summary>
@@ -78,7 +74,7 @@ namespace Hotline.Share.Dtos.JudicialManagement
         public string? City { get; set; }
 
         /// <summary>
-        /// 区/县
+        /// 区/县  
         /// </summary>
         public string? County { get; set; }
 
@@ -87,20 +83,28 @@ namespace Hotline.Share.Dtos.JudicialManagement
         /// </summary>
         public string? Town { get; set; }
 
+        /// <summary>
+        /// 省市区
+        /// </summary>
+        public string IncidentAddressText => IncidentAddress();
+
         /// <summary>
         /// 是否行政执法类
         /// </summary>
         public bool? IsEnforcementOrder { get; set; }
+        public string? IsEnforcementOrderText  => CalcRate(IsEnforcementOrder);
 
         /// <summary>
         /// 是否推诿
         /// </summary>
         public bool? IsPassTheBuckOrder { get; set; }
+        public string? IsPassTheBuckOrderText => CalcRate(IsPassTheBuckOrder);
 
         /// <summary>
         /// 线索是否属实
         /// </summary>
         public bool? IsTheClueTrue { get; set; }
+        public string? IsTheClueTrueText => CalcRate(IsTheClueTrue);
 
         /// <summary>
         /// 诉事项类型Id
@@ -122,6 +126,54 @@ namespace Hotline.Share.Dtos.JudicialManagement
         /// </summary>
         public bool IsShowUpdateButton { get; set; }
 
+        /// <summary>
+        /// 受理人id
+        /// </summary>
+        public string? AcceptorId { get; set; }
+
+        /// <summary>
+        /// 受理人名称
+        /// </summary>
+        public string? AcceptorName { get; set; }
+
+        /// <summary>
+        /// 受理人工号
+        /// </summary>
+        public string? AcceptorStaffNo { get; set; }
+
+        /// <summary>
+        /// 受理人部门编码
+        /// </summary>
+        public string? AcceptorOrgCode { get; set; }
+
+        /// <summary>
+        /// 受理人部门名称
+        /// </summary>
+        public string? AcceptorOrgName { get; set; }
+
+        /// <summary>
+        /// 转换是否文本
+        /// </summary>
+        /// <returns></returns>
+        public string CalcRate(bool? isRight)
+        {
+            if (isRight.HasValue && isRight.Value == true)
+                return "是";
+            else if (isRight.HasValue && isRight.Value == false)
+                return "否";
+            else
+                return "";
+        }
+
+        /// <summary>
+        /// 组装省市区
+        /// </summary>
+        /// <returns></returns>
+        public string IncidentAddress()
+        {
+            return $"{Province}{City}{County}";
+        }
+
     }
 
     public class EnforcementOrgSatisfactionOrderListDto : EnforcementOrderListDto

+ 4 - 1
src/Hotline.Share/Dtos/JudicialManagement/EventClassificationOrderCountDto.cs

@@ -21,7 +21,10 @@
         /// </summary>
         public int PassTheBuckOrder { get; set; }
 
-
+        /// <summary>
+        /// 待核实
+        /// </summary>
+        public int ToBeVerified { get; set; }
 
     }
 }

+ 6 - 0
src/Hotline.Share/Dtos/JudicialManagement/JudicialManagementAddOrderDto.cs

@@ -107,6 +107,11 @@ namespace Hotline.Share.Dtos.JudicialManagement
 
     public class JudicialManagementOrderDto : JudicialManagementUpdateOrderDto
     {
+        /// <summary>
+        /// 工单编码(20220101000001)
+        /// </summary>
+        public string No { get; set; }
+
         /// <summary>
         /// 是否推诿
         /// </summary>
@@ -141,6 +146,7 @@ namespace Hotline.Share.Dtos.JudicialManagement
         /// 同步省工单编号和省上传下来的工单都用这个字段
         /// </summary>
         public string? ProvinceNo { get; set; }
+
         /// <summary>
         /// 市民查询密码
         /// </summary>

+ 2 - 1
src/Hotline.Share/Dtos/JudicialManagement/QueryEventClassificationStatisticsDto.cs

@@ -4,6 +4,7 @@ namespace Hotline.Share.Dtos.JudicialManagement
 {
     public record QueryEventClassificationStatisticsDto : PagedRequest
     {
+        public string Id { get; set; }
         public DateTime StartTime { get; set; }
         public DateTime EndTime { get; set; }
         public string EventTypeId { get; set; }
@@ -11,7 +12,7 @@ namespace Hotline.Share.Dtos.JudicialManagement
         public string AreaCode { get; set; }
     }
 
-    public record QueryDepartmentalProcessingStatisticsDto: PagedRequest
+    public record QueryDepartmentalProcessingStatisticsDto : PagedRequest
     {
         public DateTime StartTime { get; set; }
         public DateTime EndTime { get; set; }

+ 6 - 6
src/Hotline.Share/Enums/CallCenter/ETelStatus.cs

@@ -16,31 +16,31 @@ public enum ETelStatus
     /// 振铃、回铃或通话中(外部对接无效)
     /// </summary>
     [Description("繁忙")]
-    Active = 1,
+    Active = 10,
     /// <summary>
     /// 模拟分机摘机后等待拨号以及拨号过程中
     /// </summary>
-    Progress = 2,
+    Progress = 20,
     /// <summary>
     /// 分机离线
     /// </summary>
     [Description("离线")]
-    Offline = 3,
+    Offline = 30,
     /// <summary>
     /// 模拟分机听催挂音时的状态
     /// </summary>
-    Offhook = 4,
+    Offhook = 40,
 
     /// <summary>
     /// 通话进行中
     /// </summary>
     [Description("通话进行中")]
-    Talk = 5,
+    Talk = 50,
 
     /// <summary>
     /// 呼叫等待中
     /// </summary>
     [Description("呼叫等待中")]
-    Wait = 6,
+    Wait = 60,
 
 }

+ 14 - 0
src/Hotline.XingTang/Hotline.XingTang.csproj

@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Hotline\Hotline.csproj" />
+    <ProjectReference Include="..\XingTang.Sdk\XingTang.Sdk.csproj" />
+  </ItemGroup>
+
+</Project>

+ 2 - 2
src/Hotline/CallCenter/BlackLists/BlacklistDomainService.cs

@@ -32,8 +32,8 @@ public class BlacklistDomainService : IBlacklistDomainService, IScopeDependency
     public async Task AddAsync(AddBlacklistDto dto, CancellationToken cancellationToken = default)
     {
         var cache = await _blackCache.GetOrSetAsync(
-            Blacklist.GetKey(dto.PhoneNo),
-            k => _blacklistRepository.Queryable().FirstAsync(d => d.PhoneNo == dto.PhoneNo).GetAwaiter().GetResult(),
+            Blacklist.GetKey(dto.Phone),
+            k => _blacklistRepository.Queryable().FirstAsync(d => d.PhoneNo == dto.Phone).GetAwaiter().GetResult(),
             TimeSpan.FromSeconds(dto.Duration),
             cancellationToken);
         if (cache != null) return;

+ 111 - 0
src/Hotline/CallCenter/Calls/CallNative.cs

@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Hotline.Share.Enums.CallCenter;
+using XF.Domain.Repository;
+
+namespace Hotline.CallCenter.Calls
+{
+    /// <summary>
+    /// 本地通话记录
+    /// </summary>
+    public class CallNative : CreationEntity
+    {
+        /// <summary>
+        /// 通话id
+        /// </summary>
+        public string CallId { get; set; }
+
+        public ECallDirection Direction { get; set; }
+
+        /// <summary>
+        /// 主叫
+        /// </summary>
+        public string FromNo { get; set; }
+
+        /// <summary>
+        /// 被叫
+        /// </summary>
+        public string ToNo { get; set; }
+
+        /// <summary>
+        /// 响应分机号
+        /// </summary>
+        public string Ext { get; set; }
+
+        /// <summary>
+        /// IVR开始时间
+        /// </summary>
+        public DateTime? BeginIvrTime { get; set; }
+        /// <summary>
+        /// IVR结束时间
+        /// </summary>
+        public DateTime? EndIvrTime { get; set; }
+        /// <summary>
+        /// 开始等待时间
+        /// </summary>
+        public DateTime? BeginQueueTime { get; set; }
+        /// <summary>
+        /// 结束等待时间
+        /// </summary>
+        public DateTime? EndQueueTime { get; set; }
+        /// <summary>
+        /// 开始振铃时间
+        /// </summary>
+        public DateTime? BeginRingTime { get; set; }
+        /// <summary>
+        /// 结束振铃时间
+        /// </summary>
+        public DateTime? EndRingTime { get; set; }
+        /// <summary>
+        /// 接听时间
+        /// </summary>
+        public DateTime? AnsweredTime { get; set; }
+        /// <summary>
+        /// 挂机时间
+        /// </summary>
+        public DateTime EndTime { get; set; }
+
+        /// <summary>
+        /// 分机组id(技能组Id)
+        /// </summary>
+        public string? GroupId { get; set; }
+
+        /// <summary>
+        /// 工号
+        /// </summary>
+        public string? StaffNo { get; set; }
+
+        /// <summary>
+        /// 挂断方
+        /// </summary>
+        public EEndBy EndBy { get; set; }
+
+        /// <summary>
+        /// 评分
+        /// </summary>
+        public int Score { get; set; }
+
+        /// <summary>
+        /// 通话时长(秒)
+        /// </summary>
+        public int Duration { get; set; }
+
+        /// <summary>
+        /// 响铃时长(秒)
+        /// </summary>
+        public int RingDuration { get; set; }
+
+        /// <summary>
+        /// 等待时长
+        /// </summary>
+        public int WaitDuration { get; set; }
+
+        /// <summary>
+        /// 通话录音
+        /// </summary>
+        public string AudioFile { get; set; }
+    }
+}

+ 0 - 1
src/Hotline/CallCenter/Calls/ICallDomainService.cs

@@ -96,7 +96,6 @@ namespace Hotline.CallCenter.Calls
         Task MonitorExtToListen(MonitorExtToListenRequest request, CancellationToken cancellationToken);
         #endregion
 
-
         #region 强插
 
         /// <summary>

+ 3 - 1
src/Hotline/JudicialManagement/JudicialManagementOrders.cs

@@ -186,11 +186,13 @@ namespace Hotline.JudicialManagement
                 ContactMask = Contact.MaskPhoneNumber();
         }
 
-        public void AutoAccept(string userId, string? userName, string? staffNo)
+        public void AutoAccept(string userId, string? userName, string? staffNo, string? acceptorOrgCode, string? acceptorOrgName)
         {
             AcceptorId = userId;
             AcceptorName = userName;
             AcceptorStaffNo = staffNo;
+            AcceptorOrgCode = acceptorOrgCode;
+            AcceptorOrgName = acceptorOrgName;
         }
 
     }

+ 5 - 4
src/Hotline/JudicialManagement/JudicialManagementOrdersService.cs

@@ -41,12 +41,13 @@ namespace Hotline.JudicialManagement
         {
             if (autoAccept)
             {
-                order.AutoAccept(_sessionContext.RequiredUserId, _sessionContext.UserName, _sessionContext.StaffNo);
+                order.AutoAccept(_sessionContext.RequiredUserId, _sessionContext.UserName, _sessionContext.StaffNo, _sessionContext.RequiredOrgId, _sessionContext.OrgName);
             }
             order.Init();
-            order.No = GenerateNewOrderNoSF();
+            var no = GenerateNewOrderNoSF();
+            order.No = no + "SF";
             order.Password = Random.Shared.Next(100000, 1000000).ToString();
-            order.ProvinceNo ??= GenerateNewProvinceNoSF(order.No, order.SourceChannelCode);
+            order.ProvinceNo ??= GenerateNewProvinceNoSF(no, order.SourceChannelCode);
             return await _judicialManagementOrdersRepository.AddAsync(order, cancellationToken);
         }
 
@@ -91,7 +92,7 @@ namespace Hotline.JudicialManagement
 
         private string GenerateOrderNo(DateTime today, int count)
         {
-            return $"{today:yyyyMMdd}{count:000000}SF";
+            return $"{today:yyyyMMdd}{count:000000}";
         }
 
     }

+ 1 - 1
src/Hotline/Users/Work.cs

@@ -63,7 +63,7 @@ public class Work : CreationModificationEntity
 
     }
 
-    public Work(string userId, string name, string telId, string telNo, string? telPwd, string? description, string? queueId,string? staffNo, ETelModel telModel)
+    public Work(string userId, string name, string telId, string telNo, string? telPwd, string? description, string? queueId,string? staffNo, ETelModel? telModel)
     {
         StartTime = DateTime.Now;
         UserId = userId;

+ 6 - 1
src/XingTang.Sdk/XingtangCall.cs

@@ -160,4 +160,9 @@ public class XingtangCall
     public long Ver { get; set; }
 
     #endregion
-}
+}
+
+/*
+开始响铃时间: 振铃时间
+结束响铃时间: 接听时间
+ */