Browse Source

Merge branch 'test' into release

xf 3 ngày trước cách đây
mục cha
commit
a7dbe00e45

+ 2 - 4
src/Hotline.Api/Controllers/IdentityController.cs

@@ -125,12 +125,9 @@ jxrWXHbT1FB6DqkdOnBbQqS1Azqz5HxLlSyEK3F60e3SgB5iZsDZ
     /// <summary>
     /// 第三方登录
     /// </summary>
-    /// <param name=""></param>
-    /// <param name="_identityAppService"></param>
-    /// <param name=""></param>
-    /// <param name=""></param>
     /// <returns></returns>
     [AllowAnonymous]
+    [LogFilterAlpha("老系统微信用户登录")]
     [HttpPost("third/login")]
     public async Task<Dictionary<string, object>> GetThirdLoginAsync([FromBody] ThirdOpenIdInDto dto)
             => await _identityAppService.GetThredTokenAsync(dto, HttpContext.RequestAborted);
@@ -141,6 +138,7 @@ jxrWXHbT1FB6DqkdOnBbQqS1Azqz5HxLlSyEK3F60e3SgB5iZsDZ
     /// <param name="openId"></param>
     /// <returns></returns>
     [HttpGet("third/refresh")]
+    [LogFilterAlpha("微信用户刷新Token")]
     [AllowAnonymous]
     public async Task<Dictionary<string, object>> RefreshTokenAsync(string openId)
         => await _identityAppService.RefreshTokenAsync(openId, HttpContext.RequestAborted);

+ 172 - 0
src/Hotline.Api/Controllers/ObservationPieceController.cs

@@ -0,0 +1,172 @@
+using Hotline.Application.ObservationPiece;
+using Hotline.Orders;
+using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.ObservationPiece;
+using Hotline.Share.Dtos.Order;
+using Hotline.Tools;
+using MapsterMapper;
+using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
+using XF.Domain.Authentications;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+
+namespace Hotline.Api.Controllers
+{
+    public class ObservationPieceController : BaseController
+    {
+        private readonly ISessionContext _sessionContext;
+        private readonly IMapper _mapper;
+        private readonly IRepository<ObservationPiece> _observationPieceRepository;
+        private readonly IObservationPieceApplication _observationPieceApplication;
+
+        public ObservationPieceController(
+            ISessionContext sessionContext,
+            IMapper mapper,
+            IRepository<ObservationPiece> observationPieceRepository,
+             IObservationPieceApplication observationPieceApplication
+            )
+        {
+            _sessionContext = sessionContext;
+            _mapper = mapper;
+            _observationPieceRepository = observationPieceRepository;
+            _observationPieceApplication = observationPieceApplication;
+        }
+
+        /// <summary>
+        /// 回复
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("add-observation-piece-reply")]
+        public async Task AddObservationPieceReply([FromBody] AddObservationPieceReply dto)
+        {
+            if (dto.ReplyContent == null)
+                throw UserFriendlyException.SameMessage("回复内容不能为空!");
+
+            if (dto.CompletionTime.HasValue == false)
+                throw UserFriendlyException.SameMessage("完成时间不能为空!");
+            var data = await _observationPieceRepository.GetAsync(p => p.Id == dto.Id, HttpContext.RequestAborted);
+            if (data == null)
+                throw UserFriendlyException.SameMessage("数据查询失败!");
+
+            data.ReplyContent = dto.ReplyContent;
+            data.CompletionTime = dto.CompletionTime;
+            data.ReplyTime = DateTime.Now;
+            data.IsReply = true;
+            data.ReplyUserId = _sessionContext.UserId;
+            data.ReplyUserName = _sessionContext.UserName;
+            data.ReplyOrgId = _sessionContext.OrgId;
+            data.ReplyOrgName = _sessionContext.OrgName;
+            await _observationPieceRepository.UpdateAsync(data, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 获取详情
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpGet("get-observation-piece-detail/{id}")]
+        public async Task<ObservationPiece> GetObservationPieceDetail(string id)
+        {
+            var data = await _observationPieceRepository.GetAsync(p => p.Id == id, HttpContext.RequestAborted);
+
+            return data;
+        }
+
+
+        /// <summary>
+        /// 观察件回复
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("get-observation-piece-reply-list")]
+        public async Task<PagedDto<ObservationPieceListDto>> GetObservationPieceReplyList([FromQuery] ObservationPieceRequestDto dto)
+        {
+            var (total, items) = await _observationPieceApplication.GetObservationPieceReplyList(dto)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<ObservationPieceListDto>(total, _mapper.Map<IReadOnlyList<ObservationPieceListDto>>(items));
+        }
+
+        /// <summary>
+        /// 观察件回复导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+
+        [HttpPost("get-observation-piece-reply-list-export")]
+        public async Task<FileStreamResult> GetObservationPieceReplyListExport([FromBody] ExportExcelDto<ObservationPieceRequestDto> dto)
+        {
+            var query = _observationPieceApplication.GetObservationPieceReplyList(dto.QueryDto);
+            List<ObservationPieceListDto> data;
+            if (dto.IsExportAll)
+            {
+                data = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                data = items;
+            }
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<ObservationPieceListDto>(dto.ColumnInfos);
+
+            var dtos = data
+                .Select(stu => _mapper.Map(stu, typeof(ObservationPieceListDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+
+            return ExcelStreamResult(stream, "观察件回复");
+        }
+
+        /// <summary>
+        /// 观察件列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("get-observation-piece-list")]
+        public async Task<PagedDto<ObservationPieceListDto>> GetObservationPieceList([FromQuery] ObservationPieceRequestDto dto)
+        {
+            var (total, items) = await _observationPieceApplication.GetObservationPieceList(dto)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<ObservationPieceListDto>(total, _mapper.Map<IReadOnlyList<ObservationPieceListDto>>(items));
+        }
+
+        /// <summary>
+        /// 观察件列表导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+
+        [HttpPost("get-observation-piece-list-export")]
+        public async Task<FileStreamResult> GetObservationPieceListExport([FromBody] ExportExcelDto<ObservationPieceRequestDto> dto)
+        {
+            var query = _observationPieceApplication.GetObservationPieceList(dto.QueryDto);
+            List<ObservationPieceListDto> data;
+            if (dto.IsExportAll)
+            {
+                data = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                data = items;
+            }
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<ObservationPieceListDto>(dto.ColumnInfos);
+
+            var dtos = data
+                .Select(stu => _mapper.Map(stu, typeof(ObservationPieceListDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+
+            return ExcelStreamResult(stream, "观察件列表");
+        }
+
+    }
+}

+ 16 - 19
src/Hotline.Api/Controllers/OrderController.cs

@@ -3843,31 +3843,28 @@ public class OrderController : BaseController
                     {
                         #region 旅游督办短信内容
 
-                        var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
+                        //var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
                         //查询部门所有账号
-                        var userlist = await _userRepository.Queryable().Where(x =>
-                            x.OrgId == model.OrgId && x.PhoneNo == dto.PhoneNo &&
-                            x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
+                        //var userlist = await _userRepository.Queryable().Where(x =>
+                        //    x.OrgId == model.OrgId && x.PhoneNo == dto.PhoneNo &&
+                        //    x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
 
                         var Contact = !string.IsNullOrEmpty(order.FromPhone) ? order.FromPhone : order.Contact;
 
                         //发送短信
-                        if (userlist != null && userlist.Count > 0)
+                        var messageDto = new Share.Dtos.Push.MessageDto
                         {
-                            var messageDto = new Share.Dtos.Push.MessageDto
-                            {
-                                PushBusiness = EPushBusiness.OrderSupervise,
-                                ExternalId = order.Id,
-                                OrderId = order.Id,
-                                PushPlatform = EPushPlatform.Sms,
-                                Remark = order.Title,
-                                Name = userlist[0].Name,
-                                TemplateCode = "1022",
-                                Params = new List<string>() { dto.ApplyContent, order.No, Contact, order.Content },
-                                TelNumber = userlist[0].PhoneNo,
-                            };
-                            await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
-                        }
+                            PushBusiness = EPushBusiness.OrderSupervise,
+                            ExternalId = order.Id,
+                            OrderId = order.Id,
+                            PushPlatform = EPushPlatform.Sms,
+                            Remark = order.Title,
+                            Name = dto.PhoneNo,//userlist[0].Name,
+                            TemplateCode = "1022",
+                            Params = new List<string>() { dto.ApplyContent, order.No, Contact, order.Content },
+                            TelNumber = dto.PhoneNo,
+                        };
+                        await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
 
                         #endregion
                     }

+ 16 - 25
src/Hotline.Api/Controllers/OrderTerminateController.cs

@@ -1,35 +1,26 @@
-using Hotline.Orders;
-using Hotline.Permissions;
-using Hotline.Quality;
-using Hotline.Share.Dtos.Quality;
-using Hotline.Share.Dtos;
-using Microsoft.AspNetCore.Mvc;
-using XF.Domain.Authentications;
-using XF.Domain.Exceptions;
-using XF.Domain.Repository;
-using Hotline.Api.Filter;
-using Hotline.Caching.Services;
-using Hotline.FlowEngine.WorkflowModules;
-using Hotline.Repository.SqlSugar.Orders;
-using Hotline.Settings;
-using Hotline.Share.Dtos.FlowEngine;
-using Hotline.Share.Dtos.Order;
-using Hotline.Share.Enums.FlowEngine;
-using Hotline.Share.Enums.Order;
-using Hotline.Share.Enums.Settings;
-using SqlSugar;
-using XF.Utility.EnumExtensions;
-using MapsterMapper;
-using Hotline.File;
+using Hotline.Api.Filter;
 using Hotline.Application.FlowEngine;
 using Hotline.Application.OrderApp;
+using Hotline.Configurations;
+using Hotline.File;
+using Hotline.FlowEngine.WorkflowModules;
 using Hotline.FlowEngine.Workflows;
+using Hotline.Orders;
 using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
-using Hotline.Share.Requests;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Enums.Order;
 using Hotline.Tools;
-using Hotline.Configurations;
+using MapsterMapper;
+using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Options;
+using SqlSugar;
+using XF.Domain.Authentications;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+using XF.Utility.EnumExtensions;
 
 namespace Hotline.Api.Controllers
 {

+ 474 - 410
src/Hotline.Api/Controllers/SchedulingController.cs

@@ -1,422 +1,486 @@
 using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Schedulings;
-using Hotline.Share.Dtos.File;
 using Hotline.Share.Dtos;
-using Microsoft.AspNetCore.Mvc;
-using XF.Domain.Authentications;
-using XF.Domain.Exceptions;
-using XF.Domain.Repository;
+using Hotline.Share.Dtos.Order;
 using Hotline.Share.Dtos.Schedulings;
-using MapsterMapper;
+using Hotline.Share.Dtos.Settings;
+using Hotline.Share.Requests;
+using Hotline.Tools;
 using Hotline.Users;
+using MapsterMapper;
+using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
 using System.Data;
-using Hotline.Repository.SqlSugar.TextSearch;
-using Microsoft.AspNetCore.Components;
 using System.Dynamic;
-using Microsoft.EntityFrameworkCore.Query.Internal;
-using NetTaste;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
 
 namespace Hotline.Api.Controllers
 {
-	public class SchedulingController : BaseController
-	{
-		private readonly IRepository<Scheduling> _schedulingRepository;
-		private readonly IRepository<SchedulingShift> _schedulingShiftRepository;
-		private readonly IRepository<SchedulingUser> _schedulingUserRepository;
-		private readonly IRepository<User> _userRepository;
-		private readonly IMapper _mapper;
-
-		public SchedulingController(
-			IRepository<Scheduling> schedulingRepository,
-			IRepository<SchedulingShift> schedulingShiftRepository,
-			IRepository<SchedulingUser> schedulingUserRepository,
-			IRepository<User> userRepository,
-			IMapper mapper
-			) {
-			_schedulingRepository = schedulingRepository;
-			_schedulingShiftRepository = schedulingShiftRepository;
-			_schedulingUserRepository = schedulingUserRepository;
-			_mapper= mapper;
-			_userRepository = userRepository;
-		}
-		#region 排班人员
-
-		/// <summary>
-		/// 新增排班人员
-		/// </summary>
-		/// <param name="dtos"></param>
-		/// <returns></returns>
-		[HttpPost("user")]
-		public async Task Add([FromBody] List<UserAddDto> dtos)
-		{
-			List<SchedulingUser> user = new List<SchedulingUser>();
-			foreach (var dto in dtos)
-			{
-				if (string.IsNullOrEmpty(dto.UserId))
-					throw UserFriendlyException.SameMessage("请带上用户信息");
-				var schedulingUser = await _schedulingUserRepository.Queryable().Where(x => x.UserId == dto.UserId).AnyAsync();
-				if (!schedulingUser)
-				{
-					var model = _mapper.Map<SchedulingUser>(dto);
-					var sysUser = await _userRepository.Queryable().Includes(u => u.Organization).Where(x => x.Id == dto.UserId).FirstAsync(HttpContext.RequestAborted);
-					model.OrgId = sysUser.Organization.Id;
-					model.OrgIdName = sysUser.Organization.Name;
-					user.Add(model);
-				}
-			}
-
-			if (user.Any())
-				await _schedulingUserRepository.AddRangeAsync(user, HttpContext.RequestAborted);
-		}
-
-		/// <summary>
-		/// 删除排班人员
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpDelete("user")]
-		public async Task Delete([FromBody] UserDeleteDto dto)
-		{
-			foreach (var Id in dto.Ids)
-			{
-				await _schedulingUserRepository.RemoveAsync(x => x.Id == Id);
-			}
-		}
-
-		/// <summary>
-		/// 更新排班人员
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpPut("user")]
-		public async Task Update([FromBody] UserUpdateDto dto)
-		{
-			var user = await _schedulingUserRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
-			if (user is null)
-				throw UserFriendlyException.SameMessage("无效排班人员");
-			_mapper.Map(dto, user);
-			var sysUser = await _userRepository.Queryable().Includes(u => u.Organization).Where(x => x.Id == dto.UserId).FirstAsync(HttpContext.RequestAborted);
-			user.OrgId = sysUser.Organization.Id;
-			user.OrgIdName = sysUser.Organization.Name;
-			await _schedulingUserRepository.UpdateAsync(user, HttpContext.RequestAborted);
-		}
-
-		/// <summary>
-		/// 批量更新排班人员
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpPut("batch_user")]
-		public async Task Update([FromBody] List<UserUpdateDto> dto)
-		{
-			List<SchedulingUser> users = new List<SchedulingUser>();
-			foreach (var item in dto)
-			{
-				var user = await _schedulingUserRepository.GetAsync(item.Id, HttpContext.RequestAborted);
-				if (user is null)
-					throw UserFriendlyException.SameMessage("无效排班人员");
-				_mapper.Map(dto, user);
-				var sysUser = await _userRepository.Queryable().Includes(u => u.Organization).Where(x => x.Id == item.UserId).FirstAsync(HttpContext.RequestAborted);
-				user.OrgId = sysUser.Organization.Id;
-				user.OrgIdName = sysUser.Organization.Name;
-				users.Add(user);
-			}
-			await _schedulingUserRepository.UpdateRangeAsync(users, HttpContext.RequestAborted);
-		}
-
-
-		/// <summary>
-		/// 获取排班人员列表
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpGet("user_list")]
-		public async Task<PagedDto<SchedulingUser>> List([FromQuery] UserListDto dto)
-		{
-			var (total, items) = await _schedulingUserRepository.Queryable()
-				.WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.UserName.Contains(dto.Keyword!))
-				.OrderByDescending(x => x.CreationTime)
-				.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
-			return new PagedDto<SchedulingUser>(total, items);
-		}
-
-		/// <summary>
-		/// 获取排班人员实体
-		/// </summary>
-		/// <param name="id"></param>
-		/// <returns></returns>
-		[HttpGet("user/{id}")]
-		public async Task<SchedulingUser> UserEntity(string id)
-		{
-			return await _schedulingUserRepository.Queryable()
-				.FirstAsync(x => x.Id == id);
-		}
-
-		#endregion
-
-		#region 班次管理
-
-		/// <summary>
-		/// 新增班次管理
-		/// </summary>
-		/// <param name="dtos"></param>
-		/// <returns></returns>
-		[HttpPost("shift")]
-		public async Task Add([FromBody] ShiftAddDto dto)
-		{
-			var model = _mapper.Map<SchedulingShift>(dto);
-			await _schedulingShiftRepository.AddAsync(model, HttpContext.RequestAborted);
-		}
-
-		/// <summary>
-		/// 删除班次管理
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpDelete("shift")]
-		public async Task Delete([FromBody] ShiftDeleteDto dto)
-		{
-			foreach (var Id in dto.Ids)
-			{
-				await _schedulingShiftRepository.RemoveAsync(x => x.Id == Id);
-			}
-		}
-
-		/// <summary>
-		/// 更新班次管理
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpPut("shift")]
-		public async Task Update([FromBody] ShiftUpdateDto dto)
-		{
-			var shift = await _schedulingShiftRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
-			if (shift is null)
-				throw UserFriendlyException.SameMessage("无效班次信息");
-			_mapper.Map(dto, shift);
-			await _schedulingShiftRepository.UpdateAsync(shift, HttpContext.RequestAborted);
-		}
-
-
-		/// <summary>
-		/// 获取班次管理列表
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpGet("shift_list")]
-		public async Task<PagedDto<SchedulingShift>> List([FromQuery] ShiftListDto dto)
-		{
-			var (total, items) = await _schedulingShiftRepository.Queryable()
-				.WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Name.Contains(dto.Keyword!))
-				.OrderByDescending(x => x.CreationTime)
-				.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
-			return new PagedDto<SchedulingShift>(total, items);
-		}
-
-		/// <summary>
-		/// 获取班次管理实体
-		/// </summary>
-		/// <param name="id"></param>
-		/// <returns></returns>
-		[HttpGet("shift/{id}")]
-		public async Task<SchedulingShift> ShiftEntity(string id)
-		{
-			return await _schedulingShiftRepository.Queryable()
-				.FirstAsync(x => x.Id == id);
-		}
-		#endregion
-
-		#region 排班管理
-		/// <summary>
-		/// 新增排班管理
-		/// </summary>
-		/// <param name="dtos"></param>
-		/// <returns></returns>
-		[HttpPost]
-		public async Task Add([FromBody] AddDto dtos)
-		{
-			List<Scheduling> schedulings = new List<Scheduling>();
-			
-			if (string.IsNullOrEmpty(dtos.ShiftId))
-				throw UserFriendlyException.SameMessage("请传入排班班次信息");
-			var shift = await _schedulingShiftRepository.GetAsync(dtos.ShiftId, HttpContext.RequestAborted);
-			if (shift  == null)
-				throw UserFriendlyException.SameMessage("传入排班班次信息错误");
-			foreach (var Id in dtos.UserIds)
-			{
-				if (string.IsNullOrEmpty(Id))
-					throw UserFriendlyException.SameMessage("请传入排班用户信息");
-				var user = await _schedulingUserRepository.GetAsync(Id, HttpContext.RequestAborted);
-				if (user == null)
-					throw UserFriendlyException.SameMessage("传入排班用户信息错误");
-
-				if (dtos.SchedulingStartTime.HasValue  && dtos.SchedulingEndTime.HasValue)
-				{
-					for (int i = 0; dtos.SchedulingStartTime.Value.AddDays(i) <= dtos.SchedulingEndTime.Value; i++)
-					{
-						var schedulingTime = dtos.SchedulingStartTime.Value.AddDays(i);
-						var oldScheduling = await _schedulingRepository.Queryable().Where(x => x.SchedulingUserId == user.Id && x.ShiftId == dtos.ShiftId && x.SchedulingTime == schedulingTime).AnyAsync();
-						if (!oldScheduling)
-						{
-							var scheduling = new Scheduling
-							{
-								SchedulingUserId = user.Id,
-								SchedulingUserName = user.UserName,
-								ShiftId = dtos.ShiftId,
-								ShiftName = shift.Name,
-								SchedulingTime = schedulingTime,
-								WorkingTime = shift.WorkingTime,
-								OffDutyTime = shift.OffDutyTime,
-								SendOrderNum = 0
-							};
-							schedulings.Add(scheduling);
-						}
-					}
+    public class SchedulingController : BaseController
+    {
+        private readonly IRepository<Scheduling> _schedulingRepository;
+        private readonly IRepository<SchedulingShift> _schedulingShiftRepository;
+        private readonly IRepository<SchedulingUser> _schedulingUserRepository;
+        private readonly IRepository<User> _userRepository;
+        private readonly IMapper _mapper;
+
+        public SchedulingController(
+            IRepository<Scheduling> schedulingRepository,
+            IRepository<SchedulingShift> schedulingShiftRepository,
+            IRepository<SchedulingUser> schedulingUserRepository,
+            IRepository<User> userRepository,
+            IMapper mapper
+            )
+        {
+            _schedulingRepository = schedulingRepository;
+            _schedulingShiftRepository = schedulingShiftRepository;
+            _schedulingUserRepository = schedulingUserRepository;
+            _mapper = mapper;
+            _userRepository = userRepository;
+        }
+        #region 排班人员
+
+        /// <summary>
+        /// 新增排班人员
+        /// </summary>
+        /// <param name="dtos"></param>
+        /// <returns></returns>
+        [HttpPost("user")]
+        public async Task Add([FromBody] List<UserAddDto> dtos)
+        {
+            List<SchedulingUser> user = new List<SchedulingUser>();
+            foreach (var dto in dtos)
+            {
+                if (string.IsNullOrEmpty(dto.UserId))
+                    throw UserFriendlyException.SameMessage("请带上用户信息");
+                var schedulingUser = await _schedulingUserRepository.Queryable().Where(x => x.UserId == dto.UserId).AnyAsync();
+                if (!schedulingUser)
+                {
+                    var model = _mapper.Map<SchedulingUser>(dto);
+                    var sysUser = await _userRepository.Queryable().Includes(u => u.Organization).Where(x => x.Id == dto.UserId).FirstAsync(HttpContext.RequestAborted);
+                    model.OrgId = sysUser.Organization.Id;
+                    model.OrgIdName = sysUser.Organization.Name;
+                    user.Add(model);
+                }
+            }
+
+            if (user.Any())
+                await _schedulingUserRepository.AddRangeAsync(user, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 删除排班人员
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpDelete("user")]
+        public async Task Delete([FromBody] UserDeleteDto dto)
+        {
+            foreach (var Id in dto.Ids)
+            {
+                await _schedulingUserRepository.RemoveAsync(x => x.Id == Id);
+            }
+        }
+
+        /// <summary>
+        /// 更新排班人员
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPut("user")]
+        public async Task Update([FromBody] UserUpdateDto dto)
+        {
+            var user = await _schedulingUserRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
+            if (user is null)
+                throw UserFriendlyException.SameMessage("无效排班人员");
+            _mapper.Map(dto, user);
+            var sysUser = await _userRepository.Queryable().Includes(u => u.Organization).Where(x => x.Id == dto.UserId).FirstAsync(HttpContext.RequestAborted);
+            user.OrgId = sysUser.Organization.Id;
+            user.OrgIdName = sysUser.Organization.Name;
+            await _schedulingUserRepository.UpdateAsync(user, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 批量更新排班人员
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPut("batch_user")]
+        public async Task Update([FromBody] List<UserUpdateDto> dto)
+        {
+            List<SchedulingUser> users = new List<SchedulingUser>();
+            foreach (var item in dto)
+            {
+                var user = await _schedulingUserRepository.GetAsync(item.Id, HttpContext.RequestAborted);
+                if (user is null)
+                    throw UserFriendlyException.SameMessage("无效排班人员");
+                _mapper.Map(dto, user);
+                var sysUser = await _userRepository.Queryable().Includes(u => u.Organization).Where(x => x.Id == item.UserId).FirstAsync(HttpContext.RequestAborted);
+                user.OrgId = sysUser.Organization.Id;
+                user.OrgIdName = sysUser.Organization.Name;
+                users.Add(user);
+            }
+            await _schedulingUserRepository.UpdateRangeAsync(users, HttpContext.RequestAborted);
+        }
+
+
+        /// <summary>
+        /// 获取排班人员列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("user_list")]
+        public async Task<PagedDto<SchedulingUser>> List([FromQuery] UserListDto dto)
+        {
+            var (total, items) = await _schedulingUserRepository.Queryable()
+                .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.UserName.Contains(dto.Keyword!))
+                .OrderByDescending(x => x.CreationTime)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<SchedulingUser>(total, items);
+        }
+
+        /// <summary>
+        /// 获取排班人员实体
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpGet("user/{id}")]
+        public async Task<SchedulingUser> UserEntity(string id)
+        {
+            return await _schedulingUserRepository.Queryable()
+                .FirstAsync(x => x.Id == id);
+        }
+
+        #endregion
+
+        #region 班次管理
+
+        /// <summary>
+        /// 新增班次管理
+        /// </summary>
+        /// <param name="dtos"></param>
+        /// <returns></returns>
+        [HttpPost("shift")]
+        public async Task Add([FromBody] ShiftAddDto dto)
+        {
+            var model = _mapper.Map<SchedulingShift>(dto);
+            await _schedulingShiftRepository.AddAsync(model, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 删除班次管理
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpDelete("shift")]
+        public async Task Delete([FromBody] ShiftDeleteDto dto)
+        {
+            foreach (var Id in dto.Ids)
+            {
+                await _schedulingShiftRepository.RemoveAsync(x => x.Id == Id);
+            }
+        }
+
+        /// <summary>
+        /// 更新班次管理
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPut("shift")]
+        public async Task Update([FromBody] ShiftUpdateDto dto)
+        {
+            var shift = await _schedulingShiftRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
+            if (shift is null)
+                throw UserFriendlyException.SameMessage("无效班次信息");
+            _mapper.Map(dto, shift);
+            await _schedulingShiftRepository.UpdateAsync(shift, HttpContext.RequestAborted);
+        }
+
+
+        /// <summary>
+        /// 获取班次管理列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("shift_list")]
+        public async Task<PagedDto<SchedulingShift>> List([FromQuery] ShiftListDto dto)
+        {
+            var (total, items) = await _schedulingShiftRepository.Queryable()
+                .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Name.Contains(dto.Keyword!))
+                .OrderByDescending(x => x.CreationTime)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<SchedulingShift>(total, items);
+        }
+
+        /// <summary>
+        /// 获取班次管理实体
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpGet("shift/{id}")]
+        public async Task<SchedulingShift> ShiftEntity(string id)
+        {
+            return await _schedulingShiftRepository.Queryable()
+                .FirstAsync(x => x.Id == id);
+        }
+        #endregion
+
+        #region 排班管理
+        /// <summary>
+        /// 新增排班管理
+        /// </summary>
+        /// <param name="dtos"></param>
+        /// <returns></returns>
+        [HttpPost]
+        public async Task Add([FromBody] AddDto dtos)
+        {
+            List<Scheduling> schedulings = new List<Scheduling>();
+
+            if (string.IsNullOrEmpty(dtos.ShiftId))
+                throw UserFriendlyException.SameMessage("请传入排班班次信息");
+            var shift = await _schedulingShiftRepository.GetAsync(dtos.ShiftId, HttpContext.RequestAborted);
+            if (shift == null)
+                throw UserFriendlyException.SameMessage("传入排班班次信息错误");
+            foreach (var Id in dtos.UserIds)
+            {
+                if (string.IsNullOrEmpty(Id))
+                    throw UserFriendlyException.SameMessage("请传入排班用户信息");
+                var user = await _schedulingUserRepository.GetAsync(Id, HttpContext.RequestAborted);
+                if (user == null)
+                    throw UserFriendlyException.SameMessage("传入排班用户信息错误");
+
+                if (dtos.SchedulingStartTime.HasValue && dtos.SchedulingEndTime.HasValue)
+                {
+                    for (int i = 0; dtos.SchedulingStartTime.Value.AddDays(i) <= dtos.SchedulingEndTime.Value; i++)
+                    {
+                        var schedulingTime = dtos.SchedulingStartTime.Value.AddDays(i);
+                        var oldScheduling = await _schedulingRepository.Queryable().Where(x => x.SchedulingUserId == user.Id && x.ShiftId == dtos.ShiftId && x.SchedulingTime == schedulingTime).AnyAsync();
+                        if (!oldScheduling)
+                        {
+                            var scheduling = new Scheduling
+                            {
+                                SchedulingUserId = user.Id,
+                                SchedulingUserName = user.UserName,
+                                ShiftId = dtos.ShiftId,
+                                ShiftName = shift.Name,
+                                SchedulingTime = schedulingTime,
+                                WorkingTime = shift.WorkingTime,
+                                OffDutyTime = shift.OffDutyTime,
+                                SendOrderNum = 0
+                            };
+                            schedulings.Add(scheduling);
+                        }
+                    }
                 }
-				else {
-					var oldScheduling = await _schedulingRepository.Queryable().Where(x => x.SchedulingUserId == user.Id && x.ShiftId == dtos.ShiftId && x.SchedulingTime == dtos.SchedulingTime).AnyAsync();
-					if (!oldScheduling)
-					{
-						var scheduling = new Scheduling
-						{
-							SchedulingUserId = user.Id,
-							SchedulingUserName = user.UserName,
-							ShiftId = dtos.ShiftId,
-							ShiftName = shift.Name,
-							SchedulingTime = dtos.SchedulingTime,
-							WorkingTime = shift.WorkingTime,
-							OffDutyTime = shift.OffDutyTime,
-							SendOrderNum = 0
-						};
-						schedulings.Add(scheduling);
-					}
-				}
-			}
-			await _schedulingRepository.AddRangeAsync(schedulings, HttpContext.RequestAborted);
-		}
-
-		/// <summary>
-		/// 删除排班管理
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpDelete]
-		public async Task Delete([FromBody] DeleteDto dto)
-		{
-			foreach (var Id in dto.Ids)
-			{
-				await _schedulingRepository.RemoveAsync(x => x.Id == Id);
-			}
-		}
-
-		/// <summary>
-		/// 更新排班管理
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpPut]
-		public async Task Update([FromBody] UpdateDto dto)
-		{
-			var scheduling = await _schedulingRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
-			if (scheduling is null)
-				throw UserFriendlyException.SameMessage("无效排班信息");
-			var shift = await _schedulingShiftRepository.GetAsync(dto.ShiftId, HttpContext.RequestAborted);
-			if (shift == null)
-				throw UserFriendlyException.SameMessage("传入排班班次信息错误");
-			_mapper.Map(dto, scheduling);
-			scheduling.ShiftName = shift.Name;
-			scheduling.WorkingTime = shift.WorkingTime;
-			scheduling.OffDutyTime = shift.OffDutyTime;
-			await _schedulingRepository.UpdateAsync(scheduling, HttpContext.RequestAborted);
-		}
-
-		///// <summary>
-		///// 批量更新排班管理
-		///// </summary>
-		///// <param name="dto"></param>
-		///// <returns></returns>
-		//[HttpPut("batch")]
-		//public async Task Update([FromBody] List<UpdateDto> dto)
-		//{
-		//	List<Scheduling> schedulings = new List<Scheduling>();
-		//	foreach (var item in dto)
-		//	{
-		//		var scheduling = await _schedulingRepository.GetAsync(item.Id, HttpContext.RequestAborted);
-		//		if (scheduling is null)
-		//			throw UserFriendlyException.SameMessage("无效排班信息");
-		//		_mapper.Map(dto, scheduling);
-		//		schedulings.Add(scheduling);
-		//	}
-		//	await _schedulingRepository.UpdateRangeAsync(schedulings, HttpContext.RequestAborted);
-		//}
-
-
-		/// <summary>
-		/// 获取排班管理列表
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpGet("list")]
-		public async Task<PagedDto<Scheduling>> List([FromQuery] ListDto dto)
-		{
-			var (total, items) = await _schedulingRepository.Queryable()
-				.Includes(x => x.SchedulingUser)
-				.Includes(x => x.SchedulingShift)
-				.WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.ShiftName.Contains(dto.Keyword!))
-				.WhereIF(dto.StartTime.HasValue, x => x.SchedulingTime >= dto.StartTime)
-				.WhereIF(dto.EndTime.HasValue, x => x.SchedulingTime <= dto.EndTime)
-				.OrderByDescending(x => x.CreationTime)
-				.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
-			return new PagedDto<Scheduling>(total, items);
-		}
-
-		/// <summary>
-		/// 排班数据查询
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpGet("data")]
-		public async Task<List<IDictionary<string, object>>> Data([FromQuery] DataDto dto) 
-		{
-			List<IDictionary<string, object>> res = new List<IDictionary<string, object>>();
-			var startTime = DateTime.Parse(dto.Time.ToString("yyyy-MM") + "-01");
-			var endTime =startTime.AddMonths(1).AddDays(-1);
-			DataTable data = await _schedulingRepository.Queryable().Where(x=>x.SchedulingTime >= startTime && x.SchedulingTime <= endTime).ToDataTableAsync();
-			if (data == null || data.Rows.Count <= 0) return res;
-			var names = data.AsEnumerable().Select(x=>new { SchedulingUserName = x.Field<string>("SchedulingUserName") , SchedulingUserId  = x.Field<string>("SchedulingUserId") }).Distinct().OrderBy(x=>x.SchedulingUserName).ToList();
-		
-			foreach (var item in names)
-			{
-				dynamic dynamicObj = new ExpandoObject();
-				var dict = (IDictionary<string, object>)dynamicObj;
-				var userName = "SchedulingUserName";
-				dict[userName] = item.SchedulingUserName!;
-				var scheduling = data.AsEnumerable().Where(x => x.Field<string>("SchedulingUserName") == item.SchedulingUserName).OrderBy(x => x.Field<DateTime>("SchedulingTime")).ToList();
-				var userId = "UserId";
-				dict[userId] =item.SchedulingUserId!;
-				foreach (DataRow row in scheduling)
-				{
-					var obj = new { Name = row.Field<string>("ShiftName"), Id = row.Field<string>("Id") };
-					var tiem = row.Field<DateTime>("SchedulingTime").ToString("yyyy-MM-dd");
-					dict[tiem] = obj;
-				}
-				res.Add(dict);
-			}
-			return res;
-		}
-
-		/// <summary>
-		/// 获取排班管理实体
-		/// </summary>
-		/// <param name="id"></param>
-		/// <returns></returns>
-		[HttpGet("{id}")]
-		public async Task<Scheduling> Entity(string id)
-		{
-			return await _schedulingRepository.Queryable()
-				.FirstAsync(x => x.Id == id);
-		}
-		#endregion
-
-	}
+                else
+                {
+                    var oldScheduling = await _schedulingRepository.Queryable().Where(x => x.SchedulingUserId == user.Id && x.ShiftId == dtos.ShiftId && x.SchedulingTime == dtos.SchedulingTime).AnyAsync();
+                    if (!oldScheduling)
+                    {
+                        var scheduling = new Scheduling
+                        {
+                            SchedulingUserId = user.Id,
+                            SchedulingUserName = user.UserName,
+                            ShiftId = dtos.ShiftId,
+                            ShiftName = shift.Name,
+                            SchedulingTime = dtos.SchedulingTime,
+                            WorkingTime = shift.WorkingTime,
+                            OffDutyTime = shift.OffDutyTime,
+                            SendOrderNum = 0
+                        };
+                        schedulings.Add(scheduling);
+                    }
+                }
+            }
+            await _schedulingRepository.AddRangeAsync(schedulings, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 删除排班管理
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpDelete]
+        public async Task Delete([FromBody] DeleteDto dto)
+        {
+            foreach (var Id in dto.Ids)
+            {
+                await _schedulingRepository.RemoveAsync(x => x.Id == Id);
+            }
+        }
+
+        /// <summary>
+        /// 更新排班管理
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPut]
+        public async Task Update([FromBody] UpdateDto dto)
+        {
+            var scheduling = await _schedulingRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
+            if (scheduling is null)
+                throw UserFriendlyException.SameMessage("无效排班信息");
+            var shift = await _schedulingShiftRepository.GetAsync(dto.ShiftId, HttpContext.RequestAborted);
+            if (shift == null)
+                throw UserFriendlyException.SameMessage("传入排班班次信息错误");
+            _mapper.Map(dto, scheduling);
+            scheduling.ShiftName = shift.Name;
+            scheduling.WorkingTime = shift.WorkingTime;
+            scheduling.OffDutyTime = shift.OffDutyTime;
+            await _schedulingRepository.UpdateAsync(scheduling, HttpContext.RequestAborted);
+        }
+
+        ///// <summary>
+        ///// 批量更新排班管理
+        ///// </summary>
+        ///// <param name="dto"></param>
+        ///// <returns></returns>
+        //[HttpPut("batch")]
+        //public async Task Update([FromBody] List<UpdateDto> dto)
+        //{
+        //	List<Scheduling> schedulings = new List<Scheduling>();
+        //	foreach (var item in dto)
+        //	{
+        //		var scheduling = await _schedulingRepository.GetAsync(item.Id, HttpContext.RequestAborted);
+        //		if (scheduling is null)
+        //			throw UserFriendlyException.SameMessage("无效排班信息");
+        //		_mapper.Map(dto, scheduling);
+        //		schedulings.Add(scheduling);
+        //	}
+        //	await _schedulingRepository.UpdateRangeAsync(schedulings, HttpContext.RequestAborted);
+        //}
+
+
+        /// <summary>
+        /// 获取排班管理列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("list")]
+        public async Task<PagedDto<Scheduling>> List([FromQuery] ListDto dto)
+        {
+            var (total, items) = await _schedulingRepository.Queryable()
+                .Includes(x => x.SchedulingUser)
+                .Includes(x => x.SchedulingShift)
+                .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.ShiftName.Contains(dto.Keyword!))
+                .WhereIF(dto.StartTime.HasValue, x => x.SchedulingTime >= dto.StartTime)
+                .WhereIF(dto.EndTime.HasValue, x => x.SchedulingTime <= dto.EndTime)
+                .OrderByDescending(x => x.CreationTime)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<Scheduling>(total, items);
+        }
+
+        /// <summary>
+        /// 排班数据查询
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("data")]
+        public async Task<List<IDictionary<string, object>>> Data([FromQuery] DataDto dto)
+        {
+            List<IDictionary<string, object>> res = new List<IDictionary<string, object>>();
+            var startTime = DateTime.Parse(dto.Time.ToString("yyyy-MM") + "-01");
+            var endTime = startTime.AddMonths(1).AddDays(-1);
+            DataTable data = await _schedulingRepository.Queryable().Where(x => x.SchedulingTime >= startTime && x.SchedulingTime <= endTime).ToDataTableAsync();
+            if (data == null || data.Rows.Count <= 0) return res;
+            var names = data.AsEnumerable().Select(x => new { SchedulingUserName = x.Field<string>("SchedulingUserName"), SchedulingUserId = x.Field<string>("SchedulingUserId") }).Distinct().OrderBy(x => x.SchedulingUserName).ToList();
+
+            foreach (var item in names)
+            {
+                dynamic dynamicObj = new ExpandoObject();
+                var dict = (IDictionary<string, object>)dynamicObj;
+                var userName = "SchedulingUserName";
+                dict[userName] = item.SchedulingUserName!;
+                var scheduling = data.AsEnumerable().Where(x => x.Field<string>("SchedulingUserName") == item.SchedulingUserName).OrderBy(x => x.Field<DateTime>("SchedulingTime")).ToList();
+                var userId = "UserId";
+                dict[userId] = item.SchedulingUserId!;
+                foreach (DataRow row in scheduling)
+                {
+                    var obj = new { Name = row.Field<string>("ShiftName"), Id = row.Field<string>("Id") };
+                    var tiem = row.Field<DateTime>("SchedulingTime").ToString("yyyy-MM-dd");
+                    dict[tiem] = obj;
+                }
+                res.Add(dict);
+            }
+            return res;
+        }
+
+        /// <summary>
+        /// 获取排班管理实体
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpGet("{id}")]
+        public async Task<Scheduling> Entity(string id)
+        {
+            return await _schedulingRepository.Queryable()
+                .FirstAsync(x => x.Id == id);
+        }
+        #endregion
+
+        #region 值班管理列表
+        /// <summary>
+        /// 值班管理列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("get-scheduling-statistics-list")]
+        public async Task<PagedDto<SchedulingStatisticsDto>> GetSchedulingStatisticsList([FromQuery] PagedKeywordRequest dto)
+        {
+            var (total, items) = await GetList(dto)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<SchedulingStatisticsDto>(total, items);
+        }
+
+        /// <summary>
+        /// 值班管理列表导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("get-scheduling-statistics-list-export")]
+        public async Task<FileStreamResult> GetSystemMobilAreaListExport([FromBody] ExportExcelDto<SystemMobilAreaRequestDto> dto)
+        {
+            var query = GetList(dto.QueryDto);
+            List<SchedulingStatisticsDto> data;
+            if (dto.IsExportAll)
+            {
+                data = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                data = items;
+            }
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<SchedulingStatisticsDto>(dto.ColumnInfos);
+
+            var dtos = data
+                .Select(stu => _mapper.Map(stu, typeof(SchedulingStatisticsDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+
+            return ExcelStreamResult(stream, "值班管理列表");
+        }
+
+        private ISugarQueryable<SchedulingStatisticsDto> GetList(PagedKeywordRequest dto)
+        {
+            return _schedulingRepository.Queryable()
+                     .Where(p => p.WorkingTime.ToString() != "00:00:00")
+                    .WhereIF(dto.StartTime.HasValue, p => p.SchedulingTime >= dto.StartTime)
+                    .WhereIF(dto.EndTime.HasValue, p => p.SchedulingTime <= dto.EndTime)
+                    .WhereIF(!string.IsNullOrEmpty(dto.Keyword), p => p.SchedulingUserName == dto.Keyword)
+                    .GroupBy(p => p.SchedulingTime.Value.ToString("yyyy-MM"))
+                    .Select(p => new SchedulingStatisticsDto
+                    {
+                        Date = p.SchedulingTime.Value.ToString("yyyy-MM"),
+                        UserName = p.SchedulingUserName,
+                        Count = SqlFunc.AggregateCount(p.SchedulingUserName)
+                    })
+                    .OrderBy(p => p.Date);
+        }
+        #endregion
+    }
 }

+ 213 - 0
src/Hotline.Api/Controllers/SystemMobilAreaController.cs

@@ -0,0 +1,213 @@
+using Hotline.Application.Systems;
+using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Settings;
+using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Dtos.Settings;
+using Hotline.Tools;
+using MapsterMapper;
+using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
+using XF.Domain.Authentications;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+
+namespace Hotline.Api.Controllers
+{
+    public class SystemMobilAreaController : BaseController
+    {
+        private readonly IMapper _mapper;
+        private readonly ISessionContext _sessionContext;
+        private readonly IRepository<SystemMobilArea> _systemMobilAreaRepository;
+        private readonly ISystemMobilAreaApplication _systemMobilAreaApplication;
+
+        public SystemMobilAreaController(
+            IMapper mapper,
+            ISessionContext sessionContext,
+            IRepository<SystemMobilArea> systemMobilAreaRepository,
+           ISystemMobilAreaApplication systemMobilAreaApplication)
+        {
+            _mapper = mapper;
+            _sessionContext = sessionContext;
+            _systemMobilAreaRepository = systemMobilAreaRepository;
+            _systemMobilAreaApplication = systemMobilAreaApplication;
+        }
+
+        /// <summary>
+        /// 基础信息
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("get-base-data")]
+        public async Task<List<Kv>> GetBaseData()
+        {
+            var data = new List<Kv>
+            {
+                new Kv() { Key = "1", Value = "中国电信" },
+                new Kv() { Key = "2", Value = "中国移动" },
+                new Kv() { Key = "3", Value = "中国联通" }
+            };
+            return data;
+        }
+
+        /// <summary>
+        /// 新增
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("add-system-mobil-area")]
+        public async Task AddSystemMobilArea([FromBody] AddSystemMobilAreaDto dto)
+        {
+            if (!string.IsNullOrEmpty(dto.TelCode))
+                throw UserFriendlyException.SameMessage("座机编号不能为空!");
+            if (!string.IsNullOrEmpty(dto.MobileCode))
+                throw UserFriendlyException.SameMessage("手机编号不能为空!");
+            if (!string.IsNullOrEmpty(dto.MobileAreaName))
+                throw UserFriendlyException.SameMessage("归属地不能为空!");
+            if (!string.IsNullOrEmpty(dto.OFlag))
+                throw UserFriendlyException.SameMessage("运营商不能为空!");
+            if (!string.IsNullOrEmpty(dto.OperatorName))
+                throw UserFriendlyException.SameMessage("卡类型不能为空!");
+
+            var data = await _systemMobilAreaRepository.AnyAsync(p => p.TelCode == dto.TelCode && p.MobileCode == dto.MobileCode && p.OFlag == p.OFlag, HttpContext.RequestAborted);
+            if (data)
+                throw UserFriendlyException.SameMessage("存在相同数据!");
+
+            SystemMobilArea systemMobilArea = new SystemMobilArea
+            {
+                TelCode = dto.TelCode,
+                MobileCode = dto.MobileCode,
+                MobileAreaName = dto.MobileAreaName,
+                OFlag = dto.OFlag,
+                OperatorName = dto.OperatorName,
+                StaId = "0"
+            };
+            await _systemMobilAreaRepository.AddAsync(systemMobilArea, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 查询详情
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpGet("get-system-mobil-area-detail/{id}")]
+        public async Task<SystemMobilArea> GetSystemMobilAreaDetail(string id)
+        {
+            var data = await _systemMobilAreaRepository.GetAsync(p => p.Id == id, HttpContext.RequestAborted);
+            if (data == null)
+                return new SystemMobilArea();
+            return data;
+        }
+
+        /// <summary>
+        /// 修改
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("update-system-mobil-area")]
+        public async Task UpdateSystemMobilAreaDetail([FromBody] UpdateSystemMobilAreaDto dto)
+        {
+            if (!string.IsNullOrEmpty(dto.TelCode))
+                throw UserFriendlyException.SameMessage("座机编号不能为空!");
+            if (!string.IsNullOrEmpty(dto.MobileCode))
+                throw UserFriendlyException.SameMessage("手机编号不能为空!");
+            if (!string.IsNullOrEmpty(dto.MobileAreaName))
+                throw UserFriendlyException.SameMessage("归属地不能为空!");
+            if (!string.IsNullOrEmpty(dto.OFlag))
+                throw UserFriendlyException.SameMessage("运营商不能为空!");
+            if (!string.IsNullOrEmpty(dto.OperatorName))
+                throw UserFriendlyException.SameMessage("卡类型不能为空!");
+            var isCheack = await _systemMobilAreaRepository.AnyAsync(p => p.Id != dto.Id && p.TelCode == dto.TelCode
+            && p.MobileCode == dto.MobileCode && p.OFlag == p.OFlag, HttpContext.RequestAborted);
+            if (isCheack)
+                throw UserFriendlyException.SameMessage("存在相同数据!");
+
+            var data = await _systemMobilAreaRepository.GetAsync(p => p.Id == dto.Id, HttpContext.RequestAborted);
+            if (data == null)
+                throw UserFriendlyException.SameMessage("修改失败!");
+
+            data.TelCode = dto.TelCode;
+            data.MobileCode = dto.MobileCode;
+            data.OFlag = dto.OFlag;
+            data.OperatorName = dto.OperatorName;
+            data.MobileAreaName = dto.MobileAreaName;
+            await _systemMobilAreaRepository.UpdateAsync(data, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 删除
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpDelete("delete-system-mobil-area-detail/{id}")]
+        public async Task DeleteSystemMobilAreaDetail(string id)
+        {
+            await _systemMobilAreaRepository.RemoveAsync(id, cancellationToken: HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 根据号码查询归属地等信息
+        /// </summary>
+        /// <param name="phonenum"></param>
+        /// <returns></returns>
+        [HttpGet("get-phone-card-area/{phonenum}")]
+        public async Task<SystemMobilAreaDto> GetPhoneCardArea(string phonenum)
+        {
+            var data = await _systemMobilAreaApplication.GetPhoneCardArea(phonenum, cancellationToken: HttpContext.RequestAborted);
+            if (data != null)
+            {
+                if (data.OFlag == "1")
+                    data.OFlag = "中国电信";
+                else if (data.OFlag == "2")
+                    data.OFlag = "中国移动";
+                else if (data.OFlag == "3")
+                    data.OFlag = "中国联通";
+            }
+            return data;
+        }
+
+        /// <summary>
+        /// 号码归属地列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("get-system-mobil-area-list")]
+        public async Task<PagedDto<SystemMobilAreaListDto>> GetSystemMobilAreaList([FromQuery] SystemMobilAreaRequestDto dto)
+        {
+            var (total, items) = await _systemMobilAreaApplication.GetList(dto)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<SystemMobilAreaListDto>(total, _mapper.Map<IReadOnlyList<SystemMobilAreaListDto>>(items));
+        }
+
+        /// <summary>
+        /// 号码归属地列表导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("get-system-mobil-area-list-export")]
+        public async Task<FileStreamResult> GetSystemMobilAreaListExport([FromBody] ExportExcelDto<SystemMobilAreaRequestDto> dto)
+        {
+            var query = _systemMobilAreaApplication.GetList(dto.QueryDto);
+            List<SystemMobilArea> 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<SystemMobilAreaListDto>>(data);
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<SystemMobilAreaListDto>(dto.ColumnInfos);
+
+            var dtos = dataDtos
+                .Select(stu => _mapper.Map(stu, typeof(SystemMobilAreaListDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+
+            return ExcelStreamResult(stream, "号码归属地列表");
+        }
+    }
+}

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

@@ -181,7 +181,8 @@ public class WorkflowController : BaseController
     /// </summary>
     /// <param name="dto"></param>
     /// <returns></returns>
-    [HttpGet("definition/export")]
+    [HttpPost("definition/export")]
+    [LogFilterAlpha("导出日志")]
     public async Task<FileStreamResult> QueryDefinitionsExport([FromBody] ExportExcelDto<QueryDefinitionDto> dto)
     {
         var query = _definitionRepository.Queryable()
@@ -328,7 +329,8 @@ public class WorkflowController : BaseController
     /// 查询所有工作流模块导出
     /// </summary>
     /// <returns></returns>
-    [HttpGet("wfmodules/export")]
+    [HttpPost("wfmodules/export")]
+    [LogFilterAlpha("导出日志")]
     public async Task<FileStreamResult> QueryWfModulesExport([FromBody] ExportExcelDto<QueryCommonDto> dto)
     {
         var items = await _wfModuleRepository.Queryable().Includes(d => d.Definition).ToListAsync(HttpContext.RequestAborted);

+ 22 - 0
src/Hotline.Application/ObservationPiece/IObservationPieceApplication.cs

@@ -0,0 +1,22 @@
+using Hotline.Share.Dtos.ObservationPiece;
+using SqlSugar;
+
+namespace Hotline.Application.ObservationPiece
+{
+    public interface IObservationPieceApplication
+    {
+        /// <summary>
+        /// 观察件回复
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<ObservationPieceListDto> GetObservationPieceReplyList(ObservationPieceRequestDto dto);
+
+        /// <summary>
+        /// 观察件列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<ObservationPieceListDto> GetObservationPieceList(ObservationPieceRequestDto dto);
+    }
+}

+ 153 - 0
src/Hotline.Application/ObservationPiece/ObservationPieceApplication.cs

@@ -0,0 +1,153 @@
+using Hotline.Share.Dtos.ObservationPiece;
+using SqlSugar;
+using XF.Domain.Authentications;
+using XF.Domain.Dependency;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.ObservationPiece
+{
+    public class ObservationPieceApplication : IObservationPieceApplication, IScopeDependency
+    {
+        private readonly ISessionContext _sessionContext;
+        private readonly IRepository<Hotline.Orders.ObservationPiece> _observationPieceRepository;
+
+        public ObservationPieceApplication(
+            ISessionContext sessionContext,
+            IRepository<Hotline.Orders.ObservationPiece> observationPieceRepository
+            )
+        {
+            _sessionContext = sessionContext;
+            _observationPieceRepository = observationPieceRepository;
+        }
+
+        /// <summary>
+        /// 观察件回复
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<ObservationPieceListDto> GetObservationPieceReplyList(ObservationPieceRequestDto dto)
+        {
+            var query = _observationPieceRepository.Queryable()
+                .Includes(p => p.Order)
+                .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.No.Contains(dto.No))
+                .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Order.Title.Contains(dto.Title))
+                .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), p => p.Order.AcceptTypeCode == dto.AcceptType) //受理类型
+                .WhereIF(dto.AcceptanceStartTime.HasValue, p => p.Order.CreationTime >= dto.AcceptanceStartTime)
+                .WhereIF(dto.AcceptanceEndTime.HasValue, p => p.Order.CreationTime <= dto.AcceptanceEndTime)
+                .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), p => p.Order.HotspotSpliceName != null && p.Order.HotspotSpliceName.Contains(dto.Hotspot))
+                .WhereIF(dto.ExpiredStartTime.HasValue, p => p.Order.ExpiredTime >= dto.ExpiredStartTime) //期满时间开始
+                .WhereIF(dto.ExpiredEndTime.HasValue, p => p.Order.ExpiredTime <= dto.ExpiredEndTime) //期满时间结束
+                .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), p => p.Order.ActualHandleOrgName.Contains(dto.ActualHandleOrgName)) //接办部门(综合查询模糊)
+
+                .WhereIF(dto.FiledStartTime.HasValue, p => p.Order.FiledTime >= dto.FiledStartTime) //办结时间开始
+                .WhereIF(dto.FiledEndTime.HasValue, p => p.Order.FiledTime <= dto.FiledEndTime) //办结时间结束
+
+                 .WhereIF(dto.ReplyStartTime.HasValue, p => p.ReplyTime >= dto.ReplyStartTime) //回复时间开始
+                .WhereIF(dto.ReplyEndTime.HasValue, p => p.ReplyTime <= dto.ReplyEndTime) //回复时间结束
+                .WhereIF(!string.IsNullOrEmpty(dto.ReplyUserName), p => p.ReplyUserName.Contains(dto.ReplyUserName))
+                 .WhereIF(dto.CreationStartTime.HasValue, p => p.CreationTime >= dto.CreationStartTime) //设置时间开始
+                .WhereIF(dto.CreationEndTime.HasValue, p => p.CreationTime <= dto.CreationEndTime) //设置时间结束
+                .WhereIF(!string.IsNullOrEmpty(dto.CreatorName), p => p.CreatorName.Contains(dto.CreatorName))
+                .WhereIF(dto.IsReply.HasValue && dto.IsReply == true, p => p.IsReply == true) //是否设置
+                 .WhereIF(dto.IsReply.HasValue && dto.IsReply == false, p => p.IsReply == false)
+                 .WhereIF(!string.IsNullOrEmpty(dto.Type) && dto.Type == "0", p => p.IsReply == false)//查询类型  待回复或者已回复
+                 .WhereIF(!string.IsNullOrEmpty(dto.Type) && dto.Type == "1", p => p.IsReply == true)
+
+                .WhereIF(_sessionContext.OrgIsCenter == false && dto.Type == "0" && dto.DataSoure == "0", p => p.ObserveOrgId.StartsWith(_sessionContext.RequiredOrgId))
+                .WhereIF(dto.Type == "0" && dto.DataSoure == "1", p => p.ObserveOrgId == _sessionContext.RequiredOrgId)
+
+                .WhereIF(_sessionContext.OrgIsCenter == false && dto.Type == "1" && dto.DataSoure == "0", p => p.ReplyOrgId.StartsWith(_sessionContext.RequiredOrgId))
+                .WhereIF(dto.Type == "1" && dto.DataSoure == "1", p => p.ObserveOrgId == _sessionContext.RequiredOrgId)
+                .Select(p => new ObservationPieceListDto
+                {
+                    Id = p.Id,
+                    OrderId = p.OrderId,
+                    No = p.No,
+                    Title = p.Order.Title,
+                    AcceptType = p.Order.AcceptType,
+                    HotspotName = p.Order.HotspotName,
+                    HotspotSpliceName = p.Order.HotspotSpliceName,
+                    AcceptanceTime = p.Order.CreationTime,
+                    ExpiredTime = p.Order.ExpiredTime,
+                    ActualHandleOrgName = p.Order.ActualHandleOrgName,
+                    CurrentStepAcceptTime = p.Order.CurrentStepAcceptTime,
+                    FiledTime = p.Order.FiledTime,
+                    CreationTime = p.CreationTime,
+                    CreatorName = p.CreatorName,
+                    ReplyTime = p.ReplyTime,
+                    ReplyUserId = p.ReplyUserId,
+                    ReplyUserName = p.ReplyUserName,
+                    ReplyOrgId = p.ReplyOrgId,
+                    ReplyOrgName = p.ReplyOrgName,
+                    IsReply = p.IsReply
+                })
+                .OrderByIF(dto.Type == "1", p => p.ReplyTime, OrderByType.Desc)
+                .OrderByIF(dto.Type == "0", p => p.CreationTime, OrderByType.Desc);
+            return query;
+        }
+
+        /// <summary>
+        /// 观察件列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<ObservationPieceListDto> GetObservationPieceList(ObservationPieceRequestDto dto)
+        {
+            var query = _observationPieceRepository.Queryable()
+                .Includes(p => p.Order)
+                .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.No.Contains(dto.No))
+                .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Order.Title.Contains(dto.Title))
+                .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), p => p.Order.AcceptTypeCode == dto.AcceptType) //受理类型
+                .WhereIF(dto.AcceptanceStartTime.HasValue, p => p.Order.CreationTime >= dto.AcceptanceStartTime)
+                .WhereIF(dto.AcceptanceEndTime.HasValue, p => p.Order.CreationTime <= dto.AcceptanceEndTime)
+                .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), p => p.Order.HotspotSpliceName != null && p.Order.HotspotSpliceName.Contains(dto.Hotspot))
+                .WhereIF(dto.ExpiredStartTime.HasValue, p => p.Order.ExpiredTime >= dto.ExpiredStartTime) //期满时间开始
+                .WhereIF(dto.ExpiredEndTime.HasValue, p => p.Order.ExpiredTime <= dto.ExpiredEndTime) //期满时间结束
+                .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), p => p.Order.ActualHandleOrgName.Contains(dto.ActualHandleOrgName)) //接办部门(综合查询模糊)
+
+                .WhereIF(dto.FiledStartTime.HasValue, p => p.Order.FiledTime >= dto.FiledStartTime) //办结时间开始
+                .WhereIF(dto.FiledEndTime.HasValue, p => p.Order.FiledTime <= dto.FiledEndTime) //办结时间结束
+
+                 .WhereIF(dto.ReplyStartTime.HasValue, p => p.ReplyTime >= dto.ReplyStartTime) //回复时间开始
+                .WhereIF(dto.ReplyEndTime.HasValue, p => p.ReplyTime <= dto.ReplyEndTime) //回复时间结束
+                .WhereIF(!string.IsNullOrEmpty(dto.ReplyUserName), p => p.ReplyUserName.Contains(dto.ReplyUserName))
+                 .WhereIF(dto.CreationStartTime.HasValue, p => p.CreationTime >= dto.CreationStartTime) //设置时间开始
+                .WhereIF(dto.CreationEndTime.HasValue, p => p.CreationTime <= dto.CreationEndTime) //设置时间结束
+                .WhereIF(!string.IsNullOrEmpty(dto.CreatorName), p => p.CreatorName.Contains(dto.CreatorName))
+                .WhereIF(dto.IsReply.HasValue && dto.IsReply == true, p => p.IsReply == true) //是否设置
+                 .WhereIF(dto.IsReply.HasValue && dto.IsReply == false, p => p.IsReply == false)
+                 .WhereIF(!string.IsNullOrEmpty(dto.Type) && dto.Type == "0", p => p.IsReply == false)//查询类型  待回复或者已回复
+                 .WhereIF(!string.IsNullOrEmpty(dto.Type) && dto.Type == "1", p => p.IsReply == true)
+
+                .WhereIF(_sessionContext.OrgIsCenter == false, p => p.ObserveOrgId.StartsWith(_sessionContext.RequiredOrgId))
+
+                .Select(p => new ObservationPieceListDto
+                {
+                    Id = p.Id,
+                    OrderId = p.OrderId,
+                    No = p.No,
+                    Title = p.Order.Title,
+                    AcceptType = p.Order.AcceptType,
+                    HotspotName = p.Order.HotspotName,
+                    HotspotSpliceName = p.Order.HotspotSpliceName,
+                    AcceptanceTime = p.Order.CreationTime,
+                    ExpiredTime = p.Order.ExpiredTime,
+                    ActualHandleOrgName = p.Order.ActualHandleOrgName,
+                    CurrentStepAcceptTime = p.Order.CurrentStepAcceptTime,
+                    FiledTime = p.Order.FiledTime,
+                    CreationTime = p.CreationTime,
+                    CreatorName = p.CreatorName,
+                    ReplyTime = p.ReplyTime,
+                    ReplyUserId = p.ReplyUserId,
+                    ReplyUserName = p.ReplyUserName,
+                    ReplyOrgId = p.ReplyOrgId,
+                    ReplyOrgName = p.ReplyOrgName,
+                    IsReply = p.IsReply
+                })
+              .OrderByDescending(p => p.CreationTime);
+
+            return query;
+        }
+
+    }
+}

+ 31 - 13
src/Hotline.Application/OrderApp/OrderApplication.cs

@@ -122,6 +122,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     private readonly IOrderVisitApplication _orderVisitApplication;
     private readonly IRepository<OrderVisitDetailCopy> _orderVisitDetailCopyRepository;
     private readonly IRepository<OrderDelayAutomatic> _orderDelayAutomaticRepository;
+    private readonly IRepository<Hotline.Orders.ObservationPiece> _observationPieceRepository;
 
     public OrderApplication(
         IOrderDomainService orderDomainService,
@@ -175,7 +176,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         IOrderVisitApplication orderVisitApplication,
         IRepository<Role> roleRepository,
         IRepository<OrderVisitDetailCopy> orderVisitDetailCopyRepository,
-        IRepository<OrderDelayAutomatic> orderDelayAutomaticRepository
+        IRepository<OrderDelayAutomatic> orderDelayAutomaticRepository,
+        IRepository<Hotline.Orders.ObservationPiece> observationPieceRepository
         )
     {
         _orderDomainService = orderDomainService;
@@ -229,6 +231,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         _roleRepository = roleRepository;
         _orderVisitDetailCopyRepository = orderVisitDetailCopyRepository;
         _orderDelayAutomaticRepository = orderDelayAutomaticRepository;
+        _observationPieceRepository = observationPieceRepository;
     }
 
     /// <summary>
@@ -1426,6 +1429,20 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         bool exisNoSatisfiedSeat = false;
         bool exisNoSatisfiedOrg = false;
 
+
+        //是否观察件
+        if (dto.IsObservationPiece.HasValue && dto.IsObservationPiece.Value == true)
+        {
+            Hotline.Orders.ObservationPiece observationPiece = new Hotline.Orders.ObservationPiece
+            {
+                No = visit.No,
+                OrderId = visit.OrderId,
+                ObserveOrgId = visit.Order.ActualHandleOrgCode,
+                State = EDelayState.Examining
+            };
+            await _observationPieceRepository.AddAsync(observationPiece, cancellationToken);
+        }
+
         //记录修改历史
         try
         {
@@ -3631,6 +3648,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         var query = _orderRepository.UnionAll(query1, query2, query3, query4)
                                     .LeftJoin<User>((x, y) => x.UserId == y.Id)
                                     .GroupBy((x, y) => new { x.UserId, y.Name })
+                                    .Where((x, y) => y.OrgId == OrgSeedData.CenterId)
                                     .Select((x, y) => new OrderVolumeDataListVo
                                     {
                                         UserId = x.UserId,
@@ -5608,17 +5626,17 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public async Task<List<SendOrderReportOutDto>> SendOrderReportAsync_LZ(QuerySendOrderRequest dto)
     {
-		var itemsHandled = _workflowTraceRepository.Queryable()
-			   .LeftJoin<Workflow>((x, w) => x.WorkflowId == w.Id)
-			   .Where((x, w) => w.ModuleCode == WorkflowModuleConsts.OrderHandle && x.Status == EWorkflowStepStatus.Handled && !SqlFunc.JsonListObjectAny(x.NextHandlers, "OrgId", OrgSeedData.CenterId) && (x.Name =="派单组" || x.Name == "班长审批"))
-			   .Where((x, w) => x.HandleTime >= dto.StartTime.Value)
-			   .Where((x, w) => x.HandleTime <= dto.EndTime.Value)
-			   .WhereIF(!string.IsNullOrEmpty(dto.UserName), (x, w) => x.HandlerName == dto.UserName)
-			   .GroupBy((x, w) => new { x.HandlerId,x.HandlerName,x.Name})
-			   .Select((x, w) => new BiOrderSendVo
-			   {
-				   UserId = x.HandlerId,
-				   UserName = x.HandlerName,
+        var itemsHandled = _workflowTraceRepository.Queryable()
+               .LeftJoin<Workflow>((x, w) => x.WorkflowId == w.Id)
+               .Where((x, w) => w.ModuleCode == WorkflowModuleConsts.OrderHandle && x.Status == EWorkflowStepStatus.Handled && !SqlFunc.JsonListObjectAny(x.NextHandlers, "OrgId", OrgSeedData.CenterId) && (x.Name == "派单组" || x.Name == "班长审批"))
+               .Where((x, w) => x.HandleTime >= dto.StartTime.Value)
+               .Where((x, w) => x.HandleTime <= dto.EndTime.Value)
+               .WhereIF(!string.IsNullOrEmpty(dto.UserName), (x, w) => x.HandlerName == dto.UserName)
+               .GroupBy((x, w) => new { x.HandlerId, x.HandlerName, x.Name })
+               .Select((x, w) => new BiOrderSendVo
+               {
+                   UserId = x.HandlerId,
+                   UserName = x.HandlerName,
                    StepName = x.Name,
                    SendOrderNum = SqlFunc.AggregateDistinctCount(w.ExternalId),
                    NoSendOrderNum = 0,
@@ -5726,7 +5744,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 .Where((x, su) => x.ModuleCode == WorkflowModuleConsts.OrderHandle && x.BusinessType == EBusinessType.Send)
                 .Where((x, su) => x.CreationTime >= dto.StartTime.Value && x.CreationTime <= dto.EndTime.Value && su.UserId == dto.UserId)
                 .WhereIF(dto.TitleCode.ToUpper() == "NOSENDORDERNUM", (x, su) => x.Status != EWorkflowStepStatus.Handled)
-                .WhereIF(dto.TitleCode.ToUpper() == "SENDORDERNUM", (x, su) => x.Status == EWorkflowStepStatus.Handled )
+                .WhereIF(dto.TitleCode.ToUpper() == "SENDORDERNUM", (x, su) => x.Status == EWorkflowStepStatus.Handled)
                 .GroupBy((x, su) => x.ExternalId)
                 .Select((x, su) => new { Id = x.ExternalId })
                 .MergeTable()

+ 10 - 1
src/Hotline.Application/Systems/ISystemMobilAreaApplication.cs

@@ -1,9 +1,18 @@
-using Hotline.Share.Dtos.Settings;
+using Hotline.Settings;
+using Hotline.Share.Dtos.Settings;
+using SqlSugar;
 
 namespace Hotline.Application.Systems
 {
     public interface ISystemMobilAreaApplication
     {
+        /// <summary>
+        /// 查询列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<SystemMobilArea> GetList(SystemMobilAreaRequestDto dto);
+
         /// <summary>
         /// 
         /// </summary>

+ 19 - 0
src/Hotline.Application/Systems/SystemMobilAreaApplication.cs

@@ -2,6 +2,7 @@
 using Hotline.Settings;
 using Hotline.Share.Dtos.Settings;
 using Microsoft.Extensions.Options;
+using SqlSugar;
 using System.Text.RegularExpressions;
 using XF.Domain.Dependency;
 using XF.Domain.Repository;
@@ -25,6 +26,24 @@ namespace Hotline.Application.Systems
             _appOptions = appOptions;
         }
 
+        /// <summary>
+        /// 查询列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<SystemMobilArea> GetList(SystemMobilAreaRequestDto dto)
+        {
+            return _systemMobilAreaRepository.Queryable()
+                   .WhereIF(!string.IsNullOrEmpty(dto.TelCode), p => p.TelCode == dto.TelCode)
+                   .WhereIF(!string.IsNullOrEmpty(dto.MobileCode), p => p.MobileCode.Contains(dto.MobileCode))
+                   .WhereIF(!string.IsNullOrEmpty(dto.MobileAreaName), p => p.MobileAreaName.Contains(dto.MobileAreaName))
+                   .WhereIF(!string.IsNullOrEmpty(dto.OFlag), p => p.OFlag == dto.OFlag)
+                   .WhereIF(!string.IsNullOrEmpty(dto.OperatorName), p => p.OperatorName.Contains(dto.OperatorName))
+                   .WhereIF(dto.StartTime.HasValue, p => p.CreationTime >= dto.StartTime)
+                    .WhereIF(dto.EndTime.HasValue, p => p.CreationTime <= dto.EndTime)
+                    .OrderByDescending(p => p.CreationTime);
+        }
+
         /// <summary>
         /// 
         /// </summary>

+ 44 - 44
src/Hotline.Repository.SqlSugar/Extensions/SqlSugarStartupExtensions.cs

@@ -331,52 +331,52 @@ namespace Hotline.Repository.SqlSugar.Extensions
                 }
             };
 
-            //SetDeletedEntityFilter(db);
+            SetDeletedEntityFilter(db);
         }
 
-        //private static void SetDeletedEntityFilter(SqlSugarClient db)
-        //{
-        //    var cacheKey = $"DbFilter:{db.CurrentConnectionConfig.ConfigId}:IsDeleted";
-        //    var tableFilterItemList = db.DataCache.Get<List<TableFilterItem<object>>>(cacheKey);
-        //    if (tableFilterItemList == null)
-        //    {
-        //        // 获取基类实体数据表
-        //        var entityTypes = AppDomain.CurrentDomain.GetAssemblies()
-        //            .SelectMany(d => d.GetTypes())
-        //            .Where(d => !d.IsInterface
-        //                        && !d.IsAbstract
-        //                        && d.IsClass
-        //                        && d.GetInterfaces().Any(x => x == typeof(ISoftDelete)));
-        //        if (!entityTypes.Any()) return;
-
-        //        var tableFilterItems = new List<TableFilterItem<object>>();
-        //        foreach (var entityType in entityTypes)
-        //        {
-        //            if (entityType.GetProperty("IsDeleted") is null) continue;
-        //            //// 排除非当前数据库实体
-        //            //var tAtt = entityType.GetCustomAttribute<TenantAttribute>();
-        //            //if ((tAtt != null && (string)db.CurrentConnectionConfig.ConfigId != tAtt.configId.ToString()) ||
-        //            //    (tAtt == null && (string)db.CurrentConnectionConfig.ConfigId != SqlSugarConst.ConfigId))
-        //            //    continue;
-
-        //            var lambda = DynamicExpressionParser.ParseLambda(new[] {
-        //                Expression.Parameter(entityType, "d") },
-        //            typeof(bool),
-        //            $"{nameof(SoftDeleteEntity.IsDeleted)} == @0", false);
-        //            var tableFilterItem = new TableFilterItem<object>(entityType, lambda);
-        //            tableFilterItems.Add(tableFilterItem);
-        //            db.QueryFilter.Add(tableFilterItem);
-        //        }
-        //        db.DataCache.Add(cacheKey, tableFilterItems);
-        //    }
-        //    else
-        //    {
-        //        tableFilterItemList.ForEach(u =>
-        //        {
-        //            db.QueryFilter.Add(u);
-        //        });
-        //    }
-        //}
+        private static void SetDeletedEntityFilter(SqlSugarClient db)
+        {
+            var cacheKey = $"DbFilter:{db.CurrentConnectionConfig.ConfigId}:IsDeleted";
+            var tableFilterItemList = db.DataCache.Get<List<TableFilterItem<object>>>(cacheKey);
+            if (tableFilterItemList == null)
+            {
+                // 获取基类实体数据表
+                var entityTypes = AppDomain.CurrentDomain.GetAssemblies()
+                    .SelectMany(d => d.GetTypes())
+                    .Where(d => !d.IsInterface
+                                && !d.IsAbstract
+                                && d.IsClass
+                                && d.GetInterfaces().Any(x => x == typeof(ISoftDelete)));
+                if (!entityTypes.Any()) return;
+
+                var tableFilterItems = new List<TableFilterItem<object>>();
+                foreach (var entityType in entityTypes)
+                {
+                    if (entityType.GetProperty("IsDeleted") is null) continue;
+                    //// 排除非当前数据库实体
+                    //var tAtt = entityType.GetCustomAttribute<TenantAttribute>();
+                    //if ((tAtt != null && (string)db.CurrentConnectionConfig.ConfigId != tAtt.configId.ToString()) ||
+                    //    (tAtt == null && (string)db.CurrentConnectionConfig.ConfigId != SqlSugarConst.ConfigId))
+                    //    continue;
+
+                    var lambda = DynamicExpressionParser.ParseLambda(new[] {
+                        Expression.Parameter(entityType, "d") },
+                    typeof(bool),
+                    $"{nameof(SoftDeleteEntity.IsDeleted)} == @0", false);
+                    var tableFilterItem = new TableFilterItem<object>(entityType, lambda);
+                    tableFilterItems.Add(tableFilterItem);
+                    db.QueryFilter.Add(tableFilterItem);
+                }
+                db.DataCache.Add(cacheKey, tableFilterItems);
+            }
+            else
+            {
+                tableFilterItemList.ForEach(u =>
+                {
+                    db.QueryFilter.Add(u);
+                });
+            }
+        }
 
         #endregion
     }

+ 23 - 0
src/Hotline.Share/Dtos/ObservationPiece/AddObservationPieceReply.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.ObservationPiece
+{
+    public class AddObservationPieceReply
+    {
+        public string Id {  get; set; }
+
+        /// <summary>
+        /// 回复内容
+        /// </summary>
+        public string? ReplyContent { get; set; }
+
+        /// <summary>
+        /// 完成时间
+        /// </summary>
+        public DateTime? CompletionTime { get; set; }
+    }
+}

+ 86 - 0
src/Hotline.Share/Dtos/ObservationPiece/ObservationPieceListDto.cs

@@ -0,0 +1,86 @@
+namespace Hotline.Share.Dtos.ObservationPiece
+{
+    public class ObservationPieceListDto
+    {
+        public string Id { get; set; }
+
+        public string OrderId { get; set; }
+
+        public string? No { get; set; }
+
+        public string? Title { get; set; }
+
+        /// <summary>
+        /// 受理类型
+        /// </summary>
+        public string? AcceptType { get; set; }
+
+        /// <summary>
+        /// 热点分类类目名称
+        /// </summary>
+        public string? HotspotName { get; set; }
+
+        /// <summary>
+        /// 热点分类类目名称
+        /// </summary>
+        public string? HotspotSpliceName { get; set; }
+
+        /// <summary>
+        /// 受理时间
+        /// </summary>
+        public DateTime? AcceptanceTime { get; set; }
+
+        /// <summary>
+        /// 超期时间(期满时间)
+        /// </summary>
+        public DateTime? ExpiredTime { get; set; }
+
+        /// <summary>
+        /// 接办部门
+        /// </summary>
+        public string? ActualHandleOrgName { get; set; }
+
+        /// <summary>
+        /// 接办时间
+        /// </summary>
+        public DateTime? CurrentStepAcceptTime { get; set; }
+
+        /// <summary>
+        /// 归档时间
+        /// </summary>
+        public DateTime? FiledTime { get; set; }
+
+        /// <summary>
+        /// 设置时间
+        /// </summary>
+        public DateTime? CreationTime { get; set; }
+
+        /// <summary>
+        /// 设置人
+        /// </summary>
+        public string? CreatorName { get; set; }
+
+        /// <summary>
+        /// 回复时间
+        /// </summary>
+        public DateTime? ReplyTime { get; set; }
+
+        /// <summary>
+        /// 回复人
+        /// </summary>
+        public string? ReplyUserId { get; set; }
+        public string? ReplyUserName { get; set; }
+
+        /// <summary>
+        /// 回复部门
+        /// </summary>
+        public string? ReplyOrgId { get; set; }
+        public string? ReplyOrgName { get; set; }
+
+        /// <summary>
+        /// 是否回复
+        /// </summary>
+        public bool IsReply { get; set; }
+        public string? IsReplyText => IsReply ? "已回复" : "未回复";
+    }
+}

+ 87 - 0
src/Hotline.Share/Dtos/ObservationPiece/ObservationPieceRequestDto.cs

@@ -0,0 +1,87 @@
+using Hotline.Share.Requests;
+
+namespace Hotline.Share.Dtos.ObservationPiece
+{
+    public record ObservationPieceRequestDto : PagedKeywordRequest
+    {
+        /// <summary>
+        /// 本地编号(√)
+        /// </summary>
+        public string No { get; set; }
+
+        /// <summary>
+        /// 标题
+        /// </summary>
+        public string? Title { get; set; }
+
+        /// <summary>
+        /// 受理类型(√)
+        /// </summary>
+        public string? AcceptType { get; set; }
+
+        /// <summary>
+        /// 受理时间
+        /// </summary>
+        public DateTime? AcceptanceStartTime { get; set; }
+        public DateTime? AcceptanceEndTime { get; set; }
+
+        /// <summary>
+        /// 热点分类关键词
+        /// </summary>
+        public string? Hotspot { get; set; }
+
+        /// <summary>
+        /// 超期时间(期满时间)
+        /// </summary>
+        public DateTime? ExpiredStartTime { get; set; }
+        public DateTime? ExpiredEndTime { get; set; }
+
+        /// <summary>
+        /// 接办部门
+        /// </summary>
+        public string? ActualHandleOrgName { get; set; }
+
+        /// <summary>
+        /// 归档时间
+        /// </summary>
+        public DateTime? FiledStartTime { get; set; }
+        public DateTime? FiledEndTime { get; set; }
+
+        /// <summary>
+        /// 回复时间
+        /// </summary>
+        public DateTime? ReplyStartTime { get; set; }
+        public DateTime? ReplyEndTime { get; set; }
+
+        /// <summary>
+        /// 回复人
+        /// </summary>
+        public string? ReplyUserName { get; set; }
+
+        /// <summary>
+        /// 设置时间
+        /// </summary>
+        public DateTime? CreationStartTime { get; set; }
+        public DateTime? CreationEndTime { get; set; }
+
+        /// <summary>
+        /// 设置人
+        /// </summary>
+        public string? CreatorName { get; set; }
+
+        /// <summary>
+        /// 是否回复
+        /// </summary>
+        public bool? IsReply { get; set; }
+
+        /// <summary>
+        /// 类型  0:待回复,1:已回复
+        /// </summary>
+        public string? Type { get; set; }
+
+        /// <summary>
+        /// 数据范围 0:全部 ,1:本级
+        /// </summary>
+        public string? DataSoure { get; set; }
+    }
+}

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

@@ -492,7 +492,13 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public OrderReTransactDto? OrderReTransact { get; set; }
 
-	}
+        /// <summary>
+        /// 是否观察件
+        /// </summary>
+        public bool? IsObservationPiece {  get; set; }
+
+
+    }
 
     public record VisitDetailDto
     {

+ 88 - 76
src/Hotline.Share/Dtos/Schedulings/SchedulingUserDto.cs

@@ -4,80 +4,92 @@ using Hotline.Share.Requests;
 
 namespace Hotline.Share.Dtos.Schedulings
 {
-	public class SchedulingUserDto : UserBaseDto
-	{
-		/// <summary>
-		/// 用户ID
-		/// </summary>
-		public string UserId { get; set; }
-
-		/// <summary>
-		/// 用户名称
-		/// </summary>
-		public string? UserName { get; set; }
-
-		/// <summary>
-		/// 
-		/// </summary>
-		public UserDto User { get; set; }
-	}
-	public class UserAddDto
-	{
-		/// <summary>
-		/// 用户ID
-		/// </summary>
-		public string UserId { get; set; }
-
-		/// <summary>
-		/// 用户名称
-		/// </summary>
-		public string UserName { get; set; }
-	}
-	public class UserUpdateDto : UserAddDto
-	{
-		public string Id { get; set; }
-	}
-
-	public class UserDeleteDto
-	{
-		public List<string> Ids { get; set; }
-	}
-	public class UserBaseDto
-	{
-		public DateTime? LastModificationTime { get; set; }
-
-		public bool IsDeleted { get; set; }
-
-		/// <summary>
-		/// 删除时间
-		/// </summary>
-		public DateTime? DeletionTime { get; set; }
-
-
-		/// <summary>
-		/// 创建时间
-		/// </summary>
-		public DateTime CreationTime { get; set; }
-
-		public string Id { get; set; }
-
-		/// <summary>
-		/// 组织Id
-		/// </summary>
-		public string? CreatorOrgId { get; set; }
-
-
-		public string? CreatorOrgName { get; set; }
-
-		/// <summary>
-		/// 创建人
-		/// </summary>
-		public string? CreatorId { get; set; }
-
-		public string? CreatorName { get; set; }
-	}
-
-	public record UserListDto : PagedKeywordRequest {
-	
-	}
+    public class SchedulingUserDto : UserBaseDto
+    {
+        /// <summary>
+        /// 用户ID
+        /// </summary>
+        public string UserId { get; set; }
+
+        /// <summary>
+        /// 用户名称
+        /// </summary>
+        public string? UserName { get; set; }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        public UserDto User { get; set; }
+    }
+    public class UserAddDto
+    {
+        /// <summary>
+        /// 用户ID
+        /// </summary>
+        public string UserId { get; set; }
+
+        /// <summary>
+        /// 用户名称
+        /// </summary>
+        public string UserName { get; set; }
+    }
+    public class UserUpdateDto : UserAddDto
+    {
+        public string Id { get; set; }
+    }
+
+    public class UserDeleteDto
+    {
+        public List<string> Ids { get; set; }
+    }
+    public class UserBaseDto
+    {
+        public DateTime? LastModificationTime { get; set; }
+
+        public bool IsDeleted { get; set; }
+
+        /// <summary>
+        /// 删除时间
+        /// </summary>
+        public DateTime? DeletionTime { get; set; }
+
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        public DateTime CreationTime { get; set; }
+
+        public string Id { get; set; }
+
+        /// <summary>
+        /// 组织Id
+        /// </summary>
+        public string? CreatorOrgId { get; set; }
+
+
+        public string? CreatorOrgName { get; set; }
+
+        /// <summary>
+        /// 创建人
+        /// </summary>
+        public string? CreatorId { get; set; }
+
+        public string? CreatorName { get; set; }
+    }
+
+    public record UserListDto : PagedKeywordRequest
+    {
+
+    }
+
+    public class SchedulingStatisticsDto
+    {
+        public string? Date { get; set; }
+
+        public string? UserName { get; set; }
+
+        public int Count { get; set; }
+    }
+
+
 }

+ 99 - 1
src/Hotline.Share/Dtos/Settings/SystemMobilAreaDto.cs

@@ -1,4 +1,6 @@
-namespace Hotline.Share.Dtos.Settings
+using Hotline.Share.Requests;
+
+namespace Hotline.Share.Dtos.Settings
 {
     public class SystemMobilAreaDto
     {
@@ -17,4 +19,100 @@
         /// </summary>
         public string? OperatorName { get; set; }
     }
+
+    public class AddSystemMobilAreaDto
+    {
+        /// <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; }
+    }
+
+    public class UpdateSystemMobilAreaDto : AddSystemMobilAreaDto
+    {
+        public string Id { get; set; }
+    }
+
+    public record SystemMobilAreaRequestDto : PagedKeywordRequest
+    {
+        /// <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; }
+    }
+
+    public class SystemMobilAreaListDto
+    {
+        public string? Id { 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; }
+        public string OFlagText => OFlag == "1" ? "中国电信" : OFlag == "2" ? "中国移动" : OFlag == "3" ? "中国联通" : "其他";
+
+        /// <summary>
+        /// 卡类型
+        /// </summary>
+        public string OperatorName { get; set; }
+
+        public DateTime? CreationTime { get; set; }
+
+        public string? CreatorName { get; set; }
+    }
 }

+ 100 - 0
src/Hotline/Orders/ObservationPiece.cs

@@ -0,0 +1,100 @@
+using Hotline.Share.Enums.Order;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Orders
+{
+    /// <summary>
+    /// 观察件
+    /// </summary>
+    [Description("观察件")]
+    public class ObservationPiece : CreationEntity
+    {
+        /// <summary>
+        /// 工单编号(冗余)
+        /// </summary>
+        public string No { get; set; }
+
+        /// <summary>
+        /// 工单ID
+        /// </summary>
+        public string OrderId { get; set; }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        [Navigate(NavigateType.OneToOne, nameof(OrderId))]
+        public Order? Order { get; set; }
+
+        /// <summary>
+        /// 观察单位
+        /// </summary>
+        public string? ObserveOrgId { get; set; }
+
+        /// <summary>
+        /// 审批状态
+        /// </summary>
+        public EDelayState State { get; set; }
+
+        /// <summary>
+        /// 审批时间
+        /// </summary>
+        public string? AuditUserId { get; set; }
+        public string? AuditUserName { get; set; }
+
+        /// <summary>
+        /// 审批部门
+        /// </summary>
+        public string? AuditOrgId { get; set; }
+        public string? AuditOrgName { get; set; }
+
+        /// <summary>
+        /// 审批时间
+        /// </summary>
+        public DateTime? AuditTime { get; set; }
+
+        /// <summary>
+        /// 审批内容
+        /// </summary>
+        public string? AuditContent { get; set; }
+
+        /// <summary>
+        /// 回复内容
+        /// </summary>
+        public string? ReplyContent { get; set; }
+
+        /// <summary>
+        /// 回复时间
+        /// </summary>
+        public DateTime? ReplyTime { get; set; }
+
+        /// <summary>
+        /// 完成时间
+        /// </summary>
+        public DateTime? CompletionTime { get; set; }
+
+        /// <summary>
+        /// 是否回复
+        /// </summary>
+        public bool IsReply { get; set; }
+
+        /// <summary>
+        /// 回复人
+        /// </summary>
+        public string? ReplyUserId { get; set; }
+        public string? ReplyUserName { get; set; }
+
+        /// <summary>
+        /// 回复部门
+        /// </summary>
+        public string? ReplyOrgId { get; set; }
+        public string? ReplyOrgName { get; set; }
+
+    }
+}