xf vor 10 Monaten
Ursprung
Commit
091a653088

+ 4 - 4
src/Hotline.Api/Controllers/AiController.cs

@@ -355,8 +355,8 @@ namespace Hotline.Api.Controllers
                         .FirstAsync(x => x.Id == request.Id,HttpContext.RequestAborted);
                     if (aiVisit!=null && !string.IsNullOrEmpty(aiVisit.BatchUid))
                     {
-                        if (aiVisit.TaskState != EAiOrderVisitTaskState.NoStarted && aiVisit.TaskState != EAiOrderVisitTaskState.InProgress)
-                            throw UserFriendlyException.SameMessage("当前状态不能终止");
+                        if (aiVisit.TaskState !=  EAiOrderVisitTaskState.Pause)
+                            throw UserFriendlyException.SameMessage("请先暂停任务,再进行终止;");
 
                         bool isOk = await _aiVisitService.ChangeStatusAsync(aiVisit.BatchUid, "cancel", HttpContext.RequestAborted);
 
@@ -384,8 +384,8 @@ namespace Hotline.Api.Controllers
                        .FirstAsync(x => x.Id == request.Id);
                     if (callOut != null && !string.IsNullOrEmpty(callOut.BatchUid))
                     {
-                        if (callOut.AiCallOutTaskState != EAiCallOutTaskState.NoStarted && callOut.AiCallOutTaskState != EAiCallOutTaskState.InProgress)
-                            throw UserFriendlyException.SameMessage("当前状态不能终止");
+                        if (callOut.AiCallOutTaskState !=  EAiCallOutTaskState.Pause)
+                            throw UserFriendlyException.SameMessage("请先暂停任务,再进行终止;");
 
                         bool isOk = await _aiVisitService.ChangeStatusAsync(callOut.BatchUid, "cancel", HttpContext.RequestAborted);
 

+ 23 - 0
src/Hotline.Api/Controllers/OrderController.cs

@@ -2300,6 +2300,29 @@ public class OrderController : BaseController
         return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
     }
 
+    /// <summary>
+    /// 查询工单(固定数据量)
+    /// </summary>
+    [HttpGet("constant")]
+    public async Task<IReadOnlyList<OrderDto>> QueryConstant([FromQuery] QueryOrderConstantDto dto)
+    {
+        var count = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.ConstantQueryCount)
+            .SettingValue[0]);
+        var query = _orderApplication.QueryOrders(dto);
+        var orders = await query.Skip(dto.QueryIndex * count).Take(count).ToListAsync(HttpContext.RequestAborted);
+        return _mapper.Map<IReadOnlyList<OrderDto>>(orders);
+    }
+
+    /// <summary>
+    /// 查询总数
+    /// </summary>
+    [HttpGet("count")]
+    public async Task<int> Count([FromQuery] QueryOrderConstantDto dto)
+    {
+        var query = _orderApplication.QueryOrders(dto);
+        return await query.CountAsync(HttpContext.RequestAborted);
+    }
+
     [HttpPost("order/export")]
     public async Task<FileStreamResult> ExportOrders([FromBody] ExportExcelDto<QueryOrderDto> dto)
     {

+ 162 - 62
src/Hotline.Api/Controllers/SysController.cs

@@ -19,6 +19,7 @@ using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc.Rendering;
 using System.Diagnostics.CodeAnalysis;
+using System.Text.RegularExpressions;
 using XF.Domain.Authentications;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
@@ -43,6 +44,7 @@ namespace Hotline.Api.Controllers
         private readonly ISessionContext _sessionContext;
         private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
         private readonly IRepository<SystemLog> _systemLogRepository;
+        private readonly IRepository<SystemMobilArea> _systemMobilAreaRepository;
 
         /// <summary>
         /// 系统管理相关接口
@@ -50,13 +52,16 @@ namespace Hotline.Api.Controllers
         /// <param name="mapper"></param>
         /// <param name="systemSettingsRepository"></param>
         /// <param name="systemMenuRepository"></param>
-        /// <param name="sysDicDataRepository"></param>
         /// <param name="sysDicTypeRepository"></param>
+        /// <param name="sysDicDataRepository"></param>
+        /// <param name="systemAreaDomainService"></param>
+        /// <param name="systemAreaRepository"></param>
         /// <param name="commonOpinionDomainService"></param>
         /// <param name="commonOpinionRepository"></param>
         /// <param name="sessionContext"></param>
-        /// <param name="systemAreaDomainService"></param>
-        /// <param name="systemAreaRepository"></param>
+        /// <param name="systemDicDataCacheManager"></param>
+        /// <param name="systemLogRepository"></param>
+        /// <param name="systemMobilAreaRepository"></param>
         public SysController(
             IMapper mapper,
             IRepository<SystemSetting> systemSettingsRepository,
@@ -69,8 +74,9 @@ namespace Hotline.Api.Controllers
             IRepository<SystemCommonOpinion> commonOpinionRepository,
             ISessionContext sessionContext,
             ISystemDicDataCacheManager systemDicDataCacheManager,
-            IRepository<SystemLog> systemLogRepository
-			)
+            IRepository<SystemLog> systemLogRepository,
+            IRepository<SystemMobilArea> systemMobilAreaRepository
+            )
         {
             _mapper = mapper;
             _systemSettingsRepository = systemSettingsRepository;
@@ -84,8 +90,8 @@ namespace Hotline.Api.Controllers
             _sessionContext = sessionContext;
             _systemDicDataCacheManager = systemDicDataCacheManager;
             _systemLogRepository = systemLogRepository;
-
-		}
+            _systemMobilAreaRepository = systemMobilAreaRepository;
+        }
 
         #region 菜单管理
         /// <summary>
@@ -111,7 +117,7 @@ namespace Hotline.Api.Controllers
         public async Task AddMenu([FromBody] AddMenuDto dto)
         {
             var menu = _mapper.Map<SystemMenu>(dto);
-            await _systemMenuRepository.AddAsync(menu,HttpContext.RequestAborted);
+            await _systemMenuRepository.AddAsync(menu, HttpContext.RequestAborted);
         }
 
         /// <summary>
@@ -268,7 +274,7 @@ namespace Hotline.Api.Controllers
         [HttpGet("dictdata-type")]
         public async Task<List<SystemDicData>> GetSysDicData([FromQuery] GetSysDicDataDto dto)
         {
-            return await _sysDicDataRepository.Queryable().Where(x => x.DicTypeId == dto.typeid).OrderBy(x=>x.Sort)/*.WhereIF(!string.IsNullOrEmpty(dto.datavalue),x=>x.DicDataValue.Contains(dto.datavalue))*/.ToTreeAsync(x=>x.Children,x=>x.ParentId,"");
+            return await _sysDicDataRepository.Queryable().Where(x => x.DicTypeId == dto.typeid).OrderBy(x => x.Sort)/*.WhereIF(!string.IsNullOrEmpty(dto.datavalue),x=>x.DicDataValue.Contains(dto.datavalue))*/.ToTreeAsync(x => x.Children, x => x.ParentId, "");
             //return await _sysDicDataRepository.Queryable().Where(x => x.DicTypeId == dto.typeid).WhereIF(!string.IsNullOrEmpty(dto.datavalue), x => x.DicDataValue.Contains(dto.datavalue)).WhereIF(!string.IsNullOrEmpty(dto.ParentId), x => x.ParentId == dto.ParentId).ToListAsync();
         }
 
@@ -280,9 +286,9 @@ namespace Hotline.Api.Controllers
         [HttpGet("dictdata-code/{code}")]
         public async Task<List<SystemDicData>> GetSysDicDataByCode(string code)
         {
-            return await _sysDicDataRepository.Queryable().Where(x => x.DicTypeCode == code).OrderBy(x=>x.Sort).ToListAsync();
+            return await _sysDicDataRepository.Queryable().Where(x => x.DicTypeCode == code).OrderBy(x => x.Sort).ToListAsync();
         }
-         
+
         /// <summary>
         /// 获取字典对象
         /// </summary>
@@ -303,7 +309,7 @@ namespace Hotline.Api.Controllers
         /// </summary>
         /// <param name="dto"></param>
         /// <returns></returns>
-        [Permission(EPermission.AddDicData)] 
+        [Permission(EPermission.AddDicData)]
         [HttpPost("add-dicdata")]
         public async Task AddDicData([FromBody] AddDicDataDto dto)
         {
@@ -323,7 +329,7 @@ namespace Hotline.Api.Controllers
         /// <returns></returns>
         [Permission(EPermission.UpdateDicData)]
         [HttpPost("update-dicdata")]
-        public async Task UpdateDicData([FromBody]UpdateDicDataDto dto)
+        public async Task UpdateDicData([FromBody] UpdateDicDataDto dto)
         {
             var dicData = await _sysDicDataRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
             if (dicData is null)
@@ -334,7 +340,7 @@ namespace Hotline.Api.Controllers
             _mapper.Map(dto, dicData);
             dicData.DicTypeCode = dicType.DicTypeCode;
             _systemDicDataCacheManager.RemoveSysDicDataCache(dicType.DicTypeCode);
-            await _sysDicDataRepository.UpdateAsync(dicData,HttpContext.RequestAborted);
+            await _sysDicDataRepository.UpdateAsync(dicData, HttpContext.RequestAborted);
         }
 
         #endregion
@@ -365,13 +371,13 @@ namespace Hotline.Api.Controllers
             {
                 throw UserFriendlyException.SameMessage("只允许添加乡镇、街道数据,请选择区县");
             }
-            if(model.ParentId.Substring(6,2) == "00")
+            if (model.ParentId.Substring(6, 2) == "00")
             {
                 throw UserFriendlyException.SameMessage("只允许添加乡镇、街道数据,请选择区县");
             }
             //验证重复
-            var area = await _systemAreaRepository.Queryable(includeDeleted:true).FirstAsync(x => x.ParentId == dto.ParentId && x.AreaName == dto.AreaName);
-            if (area!=null)
+            var area = await _systemAreaRepository.Queryable(includeDeleted: true).FirstAsync(x => x.ParentId == dto.ParentId && x.AreaName == dto.AreaName);
+            if (area != null)
             {
                 if (area.IsDeleted)
                 {
@@ -405,13 +411,13 @@ namespace Hotline.Api.Controllers
             if (!model.IsCanModify)
                 throw UserFriendlyException.SameMessage("系统数据,不能修改");
 
-            _mapper.Map(dto,model); //_mapper.Map<SystemArea>(dto);
+            _mapper.Map(dto, model); //_mapper.Map<SystemArea>(dto);
 
             //验证重复
             var area = await _systemAreaRepository.Queryable(includeDeleted: true).Where(x => x.ParentId == dto.ParentId && x.AreaName == dto.AreaName).ToListAsync();
             if (area.Count > 1)
             {
-               throw UserFriendlyException.SameMessage("同目录下已存在相同数据,不能修改");
+                throw UserFriendlyException.SameMessage("同目录下已存在相同数据,不能修改");
             }
 
             await _systemAreaDomainService.ModifyArea(model, HttpContext.RequestAborted);
@@ -459,10 +465,10 @@ namespace Hotline.Api.Controllers
         /// </summary>
         /// <returns></returns>
         [HttpGet("common-list")]
-        public async Task<IReadOnlyList<SystemCommonOpinion>> GetCommon([FromQuery]ECommonType commonType,bool isOpen)
+        public async Task<IReadOnlyList<SystemCommonOpinion>> GetCommon([FromQuery] ECommonType commonType, bool isOpen)
         {
             return await _commonOpinionRepository.Queryable().Where(x => x.CommonType == commonType && x.IsOpen == isOpen)
-                .WhereIF(isOpen== false,x=> x.CreatorId == _sessionContext.RequiredUserId).ToListAsync();
+                .WhereIF(isOpen == false, x => x.CreatorId == _sessionContext.RequiredUserId).ToListAsync();
         }
 
         /// <summary>
@@ -471,7 +477,7 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("add-common")]
-        public async Task AddCommon([FromBody]AddCommonDto dto)
+        public async Task AddCommon([FromBody] AddCommonDto dto)
         {
             var entity = _mapper.Map<SystemCommonOpinion>(dto);
             await _commonOpinionDomainService.AddCommonOpinion(entity, HttpContext.RequestAborted);
@@ -483,7 +489,7 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("del-common")]
-        public async Task DelCommon([FromBody]DelCommonDto dto)
+        public async Task DelCommon([FromBody] DelCommonDto dto)
         {
             await _commonOpinionDomainService.DelCommonOpinion(dto.Ids, HttpContext.RequestAborted);
         }
@@ -512,12 +518,12 @@ namespace Hotline.Api.Controllers
         /// <returns></returns>
         [Permission(EPermission.QueryOpenCommonOpinionList)]
         [HttpGet("open-common")]
-        public async Task<PagedDto<SystemCommonOpinion>> QueryOpenCommonOpinionList([FromQuery]QueryCommonDto dto)
+        public async Task<PagedDto<SystemCommonOpinion>> QueryOpenCommonOpinionList([FromQuery] QueryCommonDto dto)
         {
-            var (total,items) = await _commonOpinionRepository.Queryable()
-                .WhereIF(dto.IsOpen != null,x=>x.IsOpen == dto.IsOpen)
-                .WhereIF(!string.IsNullOrEmpty(dto.UserName),x=>x.CreatorName.Contains(dto.UserName))
-                .WhereIF(dto.CommonType!=null, x => x.CommonType == dto.CommonType)
+            var (total, items) = await _commonOpinionRepository.Queryable()
+                .WhereIF(dto.IsOpen != null, x => x.IsOpen == dto.IsOpen)
+                .WhereIF(!string.IsNullOrEmpty(dto.UserName), x => x.CreatorName.Contains(dto.UserName))
+                .WhereIF(dto.CommonType != null, x => x.CommonType == dto.CommonType)
                 .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
             return new PagedDto<SystemCommonOpinion>(total, items);
         }
@@ -530,7 +536,7 @@ namespace Hotline.Api.Controllers
         /// <returns></returns>
         [Permission(EPermission.CommonModify)]
         [HttpPost("common-modify")]
-        public async Task CommonModify([FromBody]CommonModifyDto dto)
+        public async Task CommonModify([FromBody] CommonModifyDto dto)
         {
             var model = await _commonOpinionRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
             if (model is null)
@@ -541,42 +547,42 @@ namespace Hotline.Api.Controllers
             await _commonOpinionRepository.UpdateAsync(model, HttpContext.RequestAborted);
         }
 
-		#endregion
-
-		#endregion
-
-		#region 日志
-		/// <summary>
-		/// 获取日志列表
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpGet("log_list")]
-		public async Task<PagedDto<SystemLogDto>> List([FromQuery] PagedKeywordRequest dto)
-		{
-			var (total, items) = await _systemLogRepository.Queryable()
-                .Where(x=> !string.IsNullOrEmpty(x.Name))
-				.WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Name.Contains(dto.Keyword!) || x.CreatorName.Contains(dto.Keyword!))
-				.OrderByDescending(x => x.CreationTime)
-				.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
-			return new PagedDto<SystemLogDto>(total, _mapper.Map<IReadOnlyList<SystemLogDto>>(items));
-		}
-
-		/// <summary>
-		/// 获取日志实体
-		/// </summary>
-		/// <param name="id"></param>
-		/// <returns></returns>
-		[HttpGet("log/{id}")]
-		public async Task<SystemLogDto> ItemEntity(string id)
-		{
-			var log = await _systemLogRepository.Queryable()
-				.FirstAsync(x => x.Id == id);
+        #endregion
+
+        #endregion
+
+        #region 日志
+        /// <summary>
+        /// 获取日志列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("log_list")]
+        public async Task<PagedDto<SystemLogDto>> List([FromQuery] PagedKeywordRequest dto)
+        {
+            var (total, items) = await _systemLogRepository.Queryable()
+                .Where(x => !string.IsNullOrEmpty(x.Name))
+                .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Name.Contains(dto.Keyword!) || x.CreatorName.Contains(dto.Keyword!))
+                .OrderByDescending(x => x.CreationTime)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<SystemLogDto>(total, _mapper.Map<IReadOnlyList<SystemLogDto>>(items));
+        }
+
+        /// <summary>
+        /// 获取日志实体
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpGet("log/{id}")]
+        public async Task<SystemLogDto> ItemEntity(string id)
+        {
+            var log = await _systemLogRepository.Queryable()
+                .FirstAsync(x => x.Id == id);
             return _mapper.Map<SystemLogDto>(log);
-		}
+        }
 
         [HttpPost("log")]
-        public async Task<string> LogAdd([FromBody]SystemLogDto dto)
+        public async Task<string> LogAdd([FromBody] SystemLogDto dto)
         {
             var log = _mapper.Map<SystemLog>(dto);
             return await _systemLogRepository.AddAsync(log, HttpContext.RequestAborted);
@@ -584,5 +590,99 @@ namespace Hotline.Api.Controllers
 
         #endregion
 
+        /// <summary>
+        ///  获取电话号码归属地和手机号码卡类型
+        /// </summary>
+        /// <param name="PhoneNum"></param>
+        /// <returns></returns>
+        [HttpGet("getphonecardarea")]
+        public async Task<SystemMobilAreaDto> GetPhoneCardArea(string PhoneNum)
+        {
+            SystemMobilAreaDto areaDto = new SystemMobilAreaDto();
+            if (true == string.IsNullOrEmpty(PhoneNum) || PhoneNum.Length < 6)
+            {
+                return areaDto;
+            }
+
+            // 验证电话号码是否是手机号码
+            bool bCheckMobile = e_VerificationMobile(PhoneNum);
+            // 电话归属编码
+            string strPhoneCode = "";
+            if (bCheckMobile)
+            {
+                // 手机号码第一位是否是0
+                if (PhoneNum.Substring(0, 1) == "0")
+                    strPhoneCode = PhoneNum.Substring(1, 7);
+                else
+                    strPhoneCode = PhoneNum.Substring(0, 7);
+
+                var data = await _systemMobilAreaRepository.GetAsync(p => p.MobileCode.Trim() == strPhoneCode, HttpContext.RequestAborted);
+                if (data != null)
+                {
+                    areaDto.OFlag = data.OFlag == "1" ? "电信" : data.OFlag == "2" ? "移动" : "联通";
+                    areaDto.MobileAreaName = data.MobileAreaName;
+                    areaDto.OperatorName = data.OperatorName;
+                }
+            }
+            else
+            {
+                // 验证电话号码是否是座机号码
+                bCheckMobile = e_VerificationTel(PhoneNum);
+                if (true == bCheckMobile)
+                {
+                    strPhoneCode = PhoneNum.Substring(0, 3);
+
+                    SystemMobilArea data = await _systemMobilAreaRepository.GetAsync(p => p.TelCode.Trim() == strPhoneCode, HttpContext.RequestAborted);
+                    if (data == null)
+                    {
+                        strPhoneCode = PhoneNum.Substring(0, 4);
+                        data = await _systemMobilAreaRepository.GetAsync(p => p.TelCode.Trim() == strPhoneCode, HttpContext.RequestAborted);
+                    }
+                    
+                    if (data != null)
+                    {
+                        areaDto.MobileAreaName = data.MobileAreaName;
+                    }
+                }
+            }
+            return areaDto;
+        }
+
+        #region 验证手机号码
+        /// <summary>
+        /// 验证手机号码
+        /// </summary>
+        /// <param name="strPhoneNum">电话号码</param>
+        /// <returns></returns>
+        public static bool e_VerificationMobile(string strPhoneNum)
+        {
+            // 手机号码正则表达式
+            string strVer = @"^(0)?(13\d|15\d|18\d|17\d|14\d|19\d|16\d)\d{5}(\d{3}|\*{3})$";
+            Regex regex = new Regex(strVer);
+            if (true == regex.IsMatch(strPhoneNum))
+                return true;
+            else
+                return false;
+        }
+        #endregion
+
+        #region 验证座机号码
+        /// <summary>
+        /// 验证座机号码
+        /// </summary>
+        /// <param name="strPhoneNum">电话号码</param>
+        /// <returns></returns>
+        public static bool e_VerificationTel(string strPhoneNum)
+        {
+            // 座机号码正则表达式
+            string strVer = @"^((0\d{2,3})(-)?)?(\d{7,8})(-(\d{3,}))?$";
+            Regex regex = new Regex(strVer);
+            if (true == regex.IsMatch(strPhoneNum))
+                return true;
+            else
+                return false;
+        }
+        #endregion
+
     }
 }

+ 1 - 1
src/Hotline.Api/StartupHelper.cs

@@ -245,7 +245,7 @@ namespace Hotline.Api
         {
             services.AddQuartz(d =>
             {
-                d.SchedulerId = "scheduler1";
+                d.SchedulerId = "default_scheduler";
                 d.InterruptJobsOnShutdown = true;
                 d.InterruptJobsOnShutdownWithWait = true;
                 d.MaxBatchSize = 3;

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

@@ -16,7 +16,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",
     "MongoDB": "mongodb://192.168.100.121:27017",
     "Wex": "server=222.212.82.225;Port=4509;Database=fs_kft;Uid=root;Pwd=Wex@12345;"

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

@@ -16,7 +16,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;"
@@ -25,7 +25,7 @@
     "Host": "110.188.24.182",
     "Port": 50179,
     "Password": "fengwo22@@",
-    "Database": 3
+    "Database": 5
   },
   "Swagger": true,
   "Cors": {

+ 6 - 2
src/Hotline.Application/Handlers/FlowEngine/WorkflowNextHandler.cs

@@ -157,7 +157,9 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
                         {
                             case EFlowAssignType.Org:
                                 var orgCodes = notification.FlowAssignInfo.HandlerObjects.Select(x => x.Key);
-                                var orgList = await _userRepository.Queryable().Where(x => orgCodes.Contains(x.OrgId) && x.Roles.Any(d => d.Id == "08dae71e-0eca-4bc4-89fe-7eaefae8a98e")).ToListAsync();
+                                var orgList = await _userRepository.Queryable()
+                                    .Where(x => orgCodes.Contains(x.OrgId) && x.Roles.Any(d => d.Id == "08dae71e-0eca-4bc4-89fe-7eaefae8a98e"))
+                                    .ToListAsync(cancellationToken);
                                 foreach (var item in orgList)
                                 {
                                     if (!string.IsNullOrEmpty(item.PhoneNo))
@@ -181,7 +183,9 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
                                 break;
                             case EFlowAssignType.User:
                                 var userCodes = notification.FlowAssignInfo.HandlerObjects.Select(x => x.Key);
-                                var userList = await _userRepository.Queryable().Where(x => userCodes.Contains(x.Id) && x.Roles.Any(d => d.Id == "08dae71e-0eca-4bc4-89fe-7eaefae8a98e")).ToListAsync();
+                                var userList = await _userRepository.Queryable()
+                                    .Where(x => userCodes.Contains(x.Id) && x.Roles.Any(d => d.Id == "08dae71e-0eca-4bc4-89fe-7eaefae8a98e"))
+                                    .ToListAsync(cancellationToken);
                                 foreach (var item in userList)
                                 {
                                     var messageDto = new Share.Dtos.Push.MessageDto

+ 35 - 0
src/Hotline.Application/Jobs/ReloadTotalsJob.cs

@@ -0,0 +1,35 @@
+using Quartz;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Cache;
+
+namespace Hotline.Application.Jobs
+{
+    /// <summary>
+    /// 刷新总数
+    /// </summary>
+    public class ReloadTotalsJob : IJob, IDisposable
+    {
+        private const string totalCachePrefix = "TotalsCache:";
+        private readonly ITypedCache<int> _totalsCache;
+
+        public ReloadTotalsJob(ITypedCache<int> totalsCache)
+        {
+            _totalsCache = totalsCache;
+        }
+
+        public async Task Execute(IJobExecutionContext context)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
+        public void Dispose()
+        {
+            throw new NotImplementedException();
+        }
+    }
+}

+ 73 - 71
src/Hotline.Application/Orders/OrderApplication.cs

@@ -178,13 +178,13 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         DateTime stTime = DateTime.Now.AddDays(int.Parse(value));
         stTime = _timeLimitDomainService.WorkDay(stTime);
         DateTime stTime2 = _timeLimitDomainService.WorkDay(DateTime.Now);
-        return  _orderRepository.Queryable(canView: true).Includes(d=>d.OrderDelays)
+        return _orderRepository.Queryable(canView: true).Includes(d => d.OrderDelays)
             .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
             .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No!))
             .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title!))
-            .WhereIF(dto.Delay.HasValue && dto.Delay == 1,d=>d.OrderDelays.Any() == true)
+            .WhereIF(dto.Delay.HasValue && dto.Delay == 1, d => d.OrderDelays.Any() == true)
             .WhereIF(dto.Delay.HasValue && dto.Delay == 2, d => d.OrderDelays.Any() == false)
-			.Where(d => d.ExpiredTime != null &&
+            .Where(d => d.ExpiredTime != null &&
             d.Status != EOrderStatus.Filed && d.Status != EOrderStatus.Published && d.Status != EOrderStatus.Visited && stTime >= d.ExpiredTime.Value && stTime2 <= d.ExpiredTime.Value)
             .OrderByDescending(d => d.CreationTime);
     }
@@ -227,13 +227,13 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         DateTime stTime = _timeLimitDomainService.WorkDay(DateTime.Now);
 
         return _orderRepository.Queryable(canView: true).Includes(d => d.OrderDelays)
-			.WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
-              //.WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
+            .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
+            //.WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
             .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No.Contains(dto.No))
             .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title.Contains(dto.Title!))
-		    .WhereIF(dto.Delay.HasValue && dto.Delay == 1, d => d.OrderDelays.Any() == true)
+            .WhereIF(dto.Delay.HasValue && dto.Delay == 1, d => d.OrderDelays.Any() == true)
             .WhereIF(dto.Delay.HasValue && dto.Delay == 2, d => d.OrderDelays.Any() == false)
-			.Where(d => d.ExpiredTime != null &&
+            .Where(d => d.ExpiredTime != null &&
             (((d.Status == EOrderStatus.Filed || d.Status == EOrderStatus.Published || d.Status == EOrderStatus.Visited) && d.FiledTime >= d.ExpiredTime) ||
             ((d.Status != EOrderStatus.Filed && d.Status != EOrderStatus.Published && d.Status != EOrderStatus.Visited) && stTime >= d.ExpiredTime.Value)))
             .OrderByDescending(x => x.CreationTime);
@@ -415,30 +415,30 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     {
         var isCenter = _sessionContext.OrgIsCenter;
 
-        return _orderRepository.Queryable(canView: isCenter ? false : true)
+        return _orderRepository.Queryable(canView: !isCenter)
             .Includes(x => x.OrderScreens)
-            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!)) //标题
-            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), d => d.ProvinceNo.Contains(dto.ProvinceNo)) //省本地编号
-            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No)) //工单编码
-                                                                                //.WhereIF(!string.IsNullOrEmpty(dto.Content), d => d.Content.Contains(dto.Content!))
+            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword!)) //标题
+            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), d => d.ProvinceNo == dto.ProvinceNo) //省本地编号
+            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No) //工单编码
+                                                                         //.WhereIF(!string.IsNullOrEmpty(dto.Content), d => d.Content.Contains(dto.Content!))
             .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型
             .WhereIF(dto.Channels.Any(), d => dto.Channels.Contains(d.SourceChannelCode)) //来源渠道
             .WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.HotspotId)) //热点类型
-            .WhereIF(!string.IsNullOrEmpty(dto.TransferPhone), d => d.TransferPhone.Contains(dto.TransferPhone!)) //转接号码
-                                                                                                                  //.WhereIF(dto.OrgCodes.Any(), d => d.Workflow.Assigns.Any(s => dto.OrgCodes.Contains(s.OrgCode)))
+            .WhereIF(!string.IsNullOrEmpty(dto.TransferPhone), d => d.TransferPhone == dto.TransferPhone!) //转接号码
+                                                                                                           //.WhereIF(dto.OrgCodes.Any(), d => d.Workflow.Assigns.Any(s => dto.OrgCodes.Contains(s.OrgCode)))
             .WhereIF(dto.OrgCodes.Any(), d => dto.OrgCodes.Contains(d.ActualHandleOrgCode)) //接办部门
-            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName.Contains(dto.NameOrNo!) || d.AcceptorStaffNo.Contains(dto.NameOrNo!)) //受理人/坐席
+            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName == dto.NameOrNo! || d.AcceptorStaffNo == dto.NameOrNo!) //受理人/坐席
             .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
             .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
             .WhereIF(dto.EmergencyLevels.Any(), d => dto.EmergencyLevels.Contains(d.EmergencyLevel))  //紧急程度
-            .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.FromPhone.Contains(dto.FromPhone)) //来电号码
-            .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.Contact.Contains(dto.PhoneNo!)) //联系电话
+            .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.FromPhone == dto.FromPhone) //来电号码
+            .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.Contact == dto.PhoneNo!) //联系电话
             .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.PushTypeCode == dto.PushTypeCode) //推送分类
             .WhereIF(dto.ExpiredTimeStart.HasValue, d => d.ExpiredTime >= dto.ExpiredTimeStart) //超期时间开始
             .WhereIF(dto.ExpiredTimeEnd.HasValue, d => d.ExpiredTime <= dto.ExpiredTimeEnd) //超期时间结束
             .WhereIF(dto.Statuses.Any(), d => dto.Statuses.Contains(d.Status))  //工单状态
             .WhereIF(dto.Statuses.Any(d => d == EOrderStatus.SpecialToUnAccept), d => d.Status <= EOrderStatus.SpecialToUnAccept)
-            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandlerName), d => d.ActualHandlerName.Contains(dto.ActualHandlerName)) //接办人
+            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandlerName), d => d.ActualHandlerName == dto.ActualHandlerName) //接办人
             .WhereIF(dto.IsScreen == true, d => d.OrderScreens.Any(x => x.Status != EScreenStatus.Refuse)) //有甄别
             .WhereIF(dto.IsScreen == false, d => !d.OrderScreens.Any(x => x.Status != EScreenStatus.Refuse)) //无甄别
             .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepCode), d => d.ActualHandleStepCode == dto.CurrentStepCode) //当前办理节点
@@ -447,7 +447,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .WhereIF(dto.IsOverTime == true, d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //是 超期
             .WhereIF(dto.IsOverTime == false, d => (d.ExpiredTime > DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime > d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //否 超期
             .WhereIF(dto.IdentityType != null, d => d.IdentityType == dto.IdentityType) //来电主体
-            .WhereIF(!string.IsNullOrEmpty(dto.FromName), d => d.FromName.Contains(dto.FromName)) //来电人姓名
+            .WhereIF(!string.IsNullOrEmpty(dto.FromName), d => d.FromName == dto.FromName) //来电人姓名
             .WhereIF(dto.AreaCodes.Any(), d => dto.AreaCodes.Contains(d.AreaCode)) //区域
             .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true, x => x.IsProvince == true)
             .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == false, x => x.IsProvince == false)
@@ -461,22 +461,23 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// </summary>
     /// <param name="dto"></param>
     /// <returns></returns>
-    public ISugarQueryable<Order,WorkflowStep> QueryUnsignedOrders(QueryUnsignedOrdersRequest dto) {
-		if (dto.EndTime.HasValue)
-			dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-		var IsCenter = _sessionContext.OrgIsCenter;
-		return _orderRepository.Queryable()
-            .LeftJoin<WorkflowStep>((x,ws)=>x.Id == ws.ExternalId)
-            .WhereIF(dto.StartTime.HasValue, (x,ws) => ws.CreationTime >= dto.StartTime)
+    public ISugarQueryable<Order, WorkflowStep> QueryUnsignedOrders(QueryUnsignedOrdersRequest dto)
+    {
+        if (dto.EndTime.HasValue)
+            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+        var IsCenter = _sessionContext.OrgIsCenter;
+        return _orderRepository.Queryable()
+            .LeftJoin<WorkflowStep>((x, ws) => x.Id == ws.ExternalId)
+            .WhereIF(dto.StartTime.HasValue, (x, ws) => ws.CreationTime >= dto.StartTime)
             .WhereIF(dto.EndTime.HasValue, (x, ws) => ws.CreationTime <= dto.EndTime)
             .WhereIF(dto.Level == 0 && IsCenter == false, (x, ws) => ws.AcceptorOrgId.StartsWith(_sessionContext.OrgId))
-			.WhereIF(dto.Level == 1,(x,ws)=> ws.AcceptorOrgId == _sessionContext.OrgId)
+            .WhereIF(dto.Level == 1, (x, ws) => ws.AcceptorOrgId == _sessionContext.OrgId)
             .WhereIF(dto.Level == 2, (x, ws) => ws.AcceptorOrgId.StartsWith(_sessionContext.OrgId))
-            .WhereIF(dto.Signed == 0 ,(x,ws)=>ws.Status == Share.Enums.FlowEngine.EWorkflowStepStatus.WaitForAccept)
+            .WhereIF(dto.Signed == 0, (x, ws) => ws.Status == Share.Enums.FlowEngine.EWorkflowStepStatus.WaitForAccept)
             .WhereIF(dto.Signed == 1, (x, ws) => ws.Status == Share.Enums.FlowEngine.EWorkflowStepStatus.WaitForHandle)
-            .Where((x,ws)=>ws.CountersignPosition ==  Share.Enums.FlowEngine.ECountersignPosition.None && x.Status > EOrderStatus.WaitForAccept)
-			.OrderByDescending((x,ws) => ws.CreationTime);
-	}
+            .Where((x, ws) => ws.CountersignPosition == Share.Enums.FlowEngine.ECountersignPosition.None && x.Status > EOrderStatus.WaitForAccept)
+            .OrderByDescending((x, ws) => ws.CreationTime);
+    }
 
     /// <summary>
     /// 信件来源统计
@@ -485,24 +486,24 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public ISugarQueryable<Order> QueryOrderSource(QueryOrderSourceRequest dto)
     {
-	    if (dto.EndTime.HasValue)
-		    dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-	    return _orderRepository.Queryable()
-		    .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
-		    .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
-            .WhereIF(dto.IdentityType.HasValue , d=>d.IdentityType == dto.IdentityType)
-            .Where(d=> d.SourceChannel != null &&  d.SourceChannel !="");
-	}
-
-	/// <summary>
-	/// 信件来源统计列表
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <returns></returns>
-	public async Task<List<OrderSourceHeaderVo>> QueryOrderSourceList(QueryOrderSourceRequest dto)
+        if (dto.EndTime.HasValue)
+            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+        return _orderRepository.Queryable()
+            .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
+            .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
+            .WhereIF(dto.IdentityType.HasValue, d => d.IdentityType == dto.IdentityType)
+            .Where(d => d.SourceChannel != null && d.SourceChannel != "");
+    }
+
+    /// <summary>
+    /// 信件来源统计列表
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public async Task<List<OrderSourceHeaderVo>> QueryOrderSourceList(QueryOrderSourceRequest dto)
     {
-	    if (dto.EndTime.HasValue)
-		    dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+        if (dto.EndTime.HasValue)
+            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
         var data = await _orderRepository.Queryable()
             .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
             .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
@@ -510,7 +511,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .Where(d => d.SourceChannel != null && d.SourceChannel != "")
             .GroupBy(d => new { Time = d.CreationTime.ToString("yyyy-MM-dd"), d.SourceChannel })
             .Select(d => new OrderSourceHeaderVo
-			{
+            {
                 Time = d.CreationTime.ToString("yyyy-MM-dd"),
                 Phone = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "RGDH", 1, 0)),
                 Web = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "YTW", 1, 0)),
@@ -530,7 +531,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 Platform110 = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "YB110", 1, 0)),
                 NoService = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "SMZXBNCS", 1, 0)),
                 Iyb = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "IYB", 1, 0))
-			}).ToListAsync() ;
+            }).ToListAsync();
         var totalVo = new OrderSourceHeaderVo()
         {
             Time = "合计",
@@ -554,27 +555,28 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             Iyb = data.Sum(x => x.Iyb)
         };
         data.Add(totalVo);
-		return data;
-	}
-
-    public ISugarQueryable<Order> QueryOrderSourceDetail(QueryOrderSourceDetailRequest dto) {
-		
-		return _orderRepository.Queryable()
-            .WhereIF(string.IsNullOrEmpty(dto.SourceChannel),d=>d.SourceChannel == dto.SourceChannel)
-            .WhereIF(dto.Time.HasValue,d=>d.CreationTime.ToString("yyyy-MM-dd") == dto.Time.Value.ToString("yyyy-MM-dd"))
-			.WhereIF(dto.IdentityType.HasValue, d => d.IdentityType == dto.IdentityType)
-			.Where(d => d.SourceChannel != null && d.SourceChannel != "");
-	}
-
-	#region private
-
-	/// <summary>
-	/// 接受外部工单(除省平台)
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <param name="cancellationToken"></param>
-	/// <returns></returns>
-	private async Task<AddOrderResponse> ReceiveOrderFromOtherPlatformAsync(AddOrderDto dto, List<FileDto> files,
+        return data;
+    }
+
+    public ISugarQueryable<Order> QueryOrderSourceDetail(QueryOrderSourceDetailRequest dto)
+    {
+
+        return _orderRepository.Queryable()
+            .WhereIF(string.IsNullOrEmpty(dto.SourceChannel), d => d.SourceChannel == dto.SourceChannel)
+            .WhereIF(dto.Time.HasValue, d => d.CreationTime.ToString("yyyy-MM-dd") == dto.Time.Value.ToString("yyyy-MM-dd"))
+            .WhereIF(dto.IdentityType.HasValue, d => d.IdentityType == dto.IdentityType)
+            .Where(d => d.SourceChannel != null && d.SourceChannel != "");
+    }
+
+    #region private
+
+    /// <summary>
+    /// 接受外部工单(除省平台)
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <param name="cancellationToken"></param>
+    /// <returns></returns>
+    private async Task<AddOrderResponse> ReceiveOrderFromOtherPlatformAsync(AddOrderDto dto, List<FileDto> files,
         ISessionContext current, CancellationToken cancellationToken)
     {
         if (string.IsNullOrEmpty(dto.ExternalId))

+ 12 - 0
src/Hotline.Share/Dtos/Order/QueryOrderConstantDto.cs

@@ -0,0 +1,12 @@
+namespace Hotline.Share.Dtos.Order;
+
+/// <summary>
+/// 定量查询工单
+/// </summary>
+public record QueryOrderConstantDto : QueryOrderDto
+{
+    /// <summary>
+    /// 查询批次
+    /// </summary>
+    public int QueryIndex { get; set; }
+}

+ 1 - 7
src/Hotline.Share/Dtos/Order/QueryOrderDto.cs

@@ -1,11 +1,5 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using System.ComponentModel;
 using Hotline.Share.Dtos.File;
-using Hotline.Share.Dtos.Users;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Settings;

+ 20 - 0
src/Hotline.Share/Dtos/Settings/SystemMobilAreaDto.cs

@@ -0,0 +1,20 @@
+namespace Hotline.Share.Dtos.Settings
+{
+    public class SystemMobilAreaDto
+    {
+        /// <summary>
+        /// 归属地
+        /// </summary>
+        public string MobileAreaName { get; set; }
+
+        /// <summary>
+        /// 运营商
+        /// </summary>
+        public string OFlag { get; set; }
+
+        /// <summary>
+        /// 卡类型
+        /// </summary>
+        public string OperatorName { get; set; }
+    }
+}

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

@@ -342,5 +342,10 @@
         /// 更新工单派单员信息
         /// </summary>
         public const string CanUpdateOrderSender = "CanUpdateOrderSender";
+
+        /// <summary>
+        /// 定量查询数据条数上限
+        /// </summary>
+        public const string ConstantQueryCount = "ConstantQueryCount";
 	}
 }

+ 39 - 0
src/Hotline/Settings/SystemMobilArea.cs

@@ -0,0 +1,39 @@
+using System.ComponentModel;
+using XF.Domain.Repository;
+
+namespace Hotline.Settings
+{
+    [Description("号码归属地")]
+    public class SystemMobilArea : CreationEntity
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        public string StaId { get; set; }
+
+        /// <summary>
+        /// 座机编号
+        /// </summary>
+        public string TelCode { get; set; }
+
+        /// <summary>
+        /// 手机编号
+        /// </summary>
+        public string MobileCode { get; set; }
+
+        /// <summary>
+        /// 归属地
+        /// </summary>
+        public string MobileAreaName { get; set; }
+
+        /// <summary>
+        /// 运营商
+        /// </summary>
+        public string OFlag { get; set; }
+
+        /// <summary>
+        /// 卡类型
+        /// </summary>
+        public string OperatorName { get; set; }
+    }
+}