Pārlūkot izejas kodu

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

Dun.Jason 2 nedēļas atpakaļ
vecāks
revīzija
afd0f50d15
26 mainītis faili ar 446 papildinājumiem un 115 dzēšanām
  1. 75 4
      src/Hotline.Api/Controllers/Bi/BiOrderController.cs
  2. 2 0
      src/Hotline.Api/Controllers/Exam/ExamManageController.cs
  3. 6 1
      src/Hotline.Api/Controllers/Exam/UserExamController.cs
  4. 1 1
      src/Hotline.Application/Exam/QueryExtensions/ExamManages/UserExamQueryExtensions.cs
  5. 3 3
      src/Hotline.Application/Exam/Service/ExamManages/ExamManageService.cs
  6. 55 51
      src/Hotline.Application/Exam/Service/ExamManages/UserExamService.cs
  7. 4 1
      src/Hotline.Application/Exam/Service/Trains/TrainRecordService.cs
  8. 4 2
      src/Hotline.Application/Jobs/ApptaskJob.cs
  9. 31 11
      src/Hotline.Application/OrderApp/Handlers/OrderDelayHandler/OrderDelayBatchReviewTaskCompetedHandler.cs
  10. 14 0
      src/Hotline.Application/OrderApp/IOrderApplication.cs
  11. 119 9
      src/Hotline.Application/OrderApp/OrderApplication.cs
  12. 3 1
      src/Hotline.Application/OrderApp/OrderDelayApp/OrderDelayApplication.cs
  13. 16 0
      src/Hotline.Application/OrderApp/OrderDelayApp/OrderDelayReviewWithSessionRequest.cs
  14. 1 1
      src/Hotline.Application/OrderApp/OrderVisitApp/VoiceVisitTaskExecutor.cs
  15. 16 0
      src/Hotline.Application/OrderApp/OrderVisitApp/VoiceVisitWithSessionRequest.cs
  16. 3 0
      src/Hotline.Share/Dtos/Order/OrderBiDto.cs
  17. 15 0
      src/Hotline.Share/Dtos/Order/OrderDelay/BatchOrderDelayReviewRequest.cs
  18. 7 0
      src/Hotline.Share/Dtos/Order/OrderDelay/DelayWithStepId.cs
  19. 0 18
      src/Hotline.Share/Dtos/Order/OrderDelay/OrderDelayReviewRequest.cs
  20. 6 1
      src/Hotline.Share/Enums/Exams/EExamStatus.cs
  21. 23 0
      src/Hotline.Share/Requests/PagedKeywordRequest.cs
  22. 13 1
      src/Hotline/Authentications/SessionContextProvider.cs
  23. 11 7
      src/Hotline/BatchTask/ApptaskDomainService.cs
  24. 2 1
      src/Hotline/BatchTask/IApptaskDomainService.cs
  25. 14 0
      src/Hotline/BatchTask/IApptaskRequest.cs
  26. 2 2
      src/XF.Domain/Authentications/ISessionContextProvider.cs

+ 75 - 4
src/Hotline.Api/Controllers/Bi/BiOrderController.cs

@@ -610,11 +610,29 @@ namespace Hotline.Api.Controllers.Bi
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpGet("centre_data_list")]
-        public async Task<List<OrderBiCentreDataListVo>> CentreDataList([FromQuery] ReportPagedRequest dto)
+        public async Task<TotalList<OrderBiCentreDataListVo>> CentreDataList([FromQuery] ReportPagedRequest dto)
         {
-            var query = _orderApplication.CentreDataList(dto);
+            ISugarQueryable<OrderBiCentreDataListVo> query;
+            if (_appOptions.Value.IsZiGong)
+                query = _orderApplication.CentreDataListZG(dto);
+            else
+                query = _orderApplication.CentreDataList(dto);
+
             var list = await query.Where(x => (x.CentreArchive + x.CentreCareOf + x.NoCentreCareOf + x.Invalid + x.Repeat) != 0).ToListAsync(HttpContext.RequestAborted);
-            return list;
+
+            var total = new OrderBiCentreDataListVo
+            {
+                UserName = "合计",
+                UserId = "",
+                CentreArchive = list.Select(s => s.CentreArchive).Sum(),
+                CentreCareOf = list.Select(s => s.CentreCareOf).Sum(),
+                NoCentreCareOf = list.Select(s => s.NoCentreCareOf).Sum(),
+                Invalid = list.Select(s => s.Invalid).Sum(),
+                Repeat = list.Select(s => s.Repeat).Sum(),
+                Subtotal = list.Select(s => s.Subtotal).Sum()
+            };
+
+            return new TotalList<OrderBiCentreDataListVo>(list, total);
         }
 
         /// <summary>
@@ -626,7 +644,13 @@ namespace Hotline.Api.Controllers.Bi
         [LogFilterAlpha("导出日志")]
         public async Task<FileStreamResult> CentreDataListExport([FromBody] ExportExcelDto<ReportPagedRequest> dto)
         {
-            var query = _orderApplication.CentreDataList(dto.QueryDto);
+            ISugarQueryable<OrderBiCentreDataListVo> query;
+            if (_appOptions.Value.IsZiGong)
+                query = _orderApplication.CentreDataListZG(dto.QueryDto);
+            else
+                query = _orderApplication.CentreDataList(dto.QueryDto);
+
+            //var query = _orderApplication.CentreDataList(dto.QueryDto);
             List<OrderBiCentreDataListVo> data = await query.Where(x => (x.CentreArchive + x.CentreCareOf + x.NoCentreCareOf + x.Invalid + x.Repeat) != 0).ToListAsync(HttpContext.RequestAborted);
             data.Add(new OrderBiCentreDataListVo
             {
@@ -648,6 +672,53 @@ namespace Hotline.Api.Controllers.Bi
             return ExcelStreamResult(stream, "话务员办件统计");
         }
 
+        /// <summary>
+        /// 话务员办件统计明细列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("centre_data_list_detail")]
+        public async Task<PagedDto<OrderDto>> CentreDataListDetailExport([FromQuery] CentreDataListDetailRequest dto)
+        {
+            var (total, items) = await _orderApplication.CentreDataListDetailZG(dto).ToPagedListAsync(dto, HttpContext.RequestAborted);
+            return new PagedDto<OrderDto>(total, _mapper.Map<List<OrderDto>>(items));
+        }
+
+        /// <summary>
+        /// 话务员办件统计明细列表--导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("centre_data_list_detail_export")]
+        [LogFilterAlpha("导出日志")]
+        public async Task<FileStreamResult> CentreDataListDetailExport([FromBody] ExportExcelDto<CentreDataListDetailRequest> dto)
+        {
+            var query = _orderApplication.CentreDataListDetailZG(dto.QueryDto);
+            List<Order> orders;
+            if (dto.IsExportAll)
+            {
+                orders = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                orders = items;
+            }
+
+            var orderDtos = _mapper.Map<ICollection<OrderDto>>(orders);
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderDto>(dto.ColumnInfos);
+
+            var dtos = orderDtos
+                .Select(stu => _mapper.Map(stu, typeof(OrderDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+
+            return ExcelStreamResult(stream, "话务员办件统计明细列表");
+        }
+
         /// <summary>
         /// 工单业务量统计
         /// </summary>

+ 2 - 0
src/Hotline.Api/Controllers/Exam/ExamManageController.cs

@@ -59,6 +59,8 @@ namespace Hotline.Api.Controllers.Exam
         [HttpPost(ExamManageApiRoute.GetPagedList)]
         public async Task<ExamManagePageViewResponse> GetPagedList([FromBody] ExamManagePagedRequest questionPagedRequest)
         {
+            await _examManageService.UpdateExamStatus(new EntityQueryRequest(), HttpContext.RequestAborted);
+
             var questionPageViewResponse = await _examManageService.GetPagedListAsync(questionPagedRequest);
 
             return questionPageViewResponse as ExamManagePageViewResponse;

+ 6 - 1
src/Hotline.Api/Controllers/Exam/UserExamController.cs

@@ -10,16 +10,19 @@ using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
 using System.ComponentModel;
 using Hotline.Application.Exam.Interface.ExamManages;
+using Exam.Infrastructure.Data.Entity;
 
 namespace Hotline.Api.Controllers.Exam
 {
     public class UserExamController : BaseController
     {
         private readonly IUserExamService _userExamService;
+        private readonly IExamManageService _examManageService;
 
-        public UserExamController(IUserExamService userExamService)
+        public UserExamController(IUserExamService userExamService,IExamManageService examManageService)
         {
             this._userExamService = userExamService;
+            this._examManageService = examManageService;
         }
 
         /// <summary>
@@ -30,6 +33,8 @@ namespace Hotline.Api.Controllers.Exam
         [HttpPost(UserExamApiRoute.GetPagedList)]
         public async Task<UserExamResultPageViewResponse> GetPagedList([FromBody] UserExamPagedRequest userExamPagedRequest)
         {
+            await _examManageService.UpdateExamStatus(new EntityQueryRequest(), HttpContext.RequestAborted);
+
             return await _userExamService.GetPagedListAsync(userExamPagedRequest) as UserExamResultPageViewResponse;
         }
 

+ 1 - 1
src/Hotline.Application/Exam/QueryExtensions/ExamManages/UserExamQueryExtensions.cs

@@ -78,7 +78,7 @@ namespace Hotline.Application.Exam.QueryExtensions.ExamManages
             Expression<Func<ExamUserExam, bool>> expression = m => m.Id != null;
 
             expression = ExpressionableUtility.CreateExpression<ExamUserExam>()
-                .And(x=>x.ExamStatus == Share.Enums.Exams.EExamStatus.NoStart)
+                .And(x=>x.ExamStatus == Share.Enums.Exams.EExamStatus.Absent)
             .ToExpression();
 
             return expression;

+ 3 - 3
src/Hotline.Application/Exam/Service/ExamManages/ExamManageService.cs

@@ -332,7 +332,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
         {
             List<ExamManage> examManages = await UpdateExamManageStatus(entityQueryRequest, requestAborted);
 
-            //await UdpateUserExam(examManages, requestAborted);
+            await UdpateUserExam(examManages, requestAborted);
 
         }
         #endregion
@@ -696,7 +696,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
             userExams.ForEach(item =>
             {
-                item.ExamStatus = Share.Enums.Exams.EExamStatus.Complete;
+                item.ExamStatus = item.ExamStatus== Share.Enums.Exams.EExamStatus.NoStart? Share.Enums.Exams.EExamStatus.Absent: item.ExamStatus;
             });
 
             userExams.ToUpdate(_sessionContext);
@@ -708,7 +708,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
         {
             var queryable = _repository.Queryable()
                 .WhereIF(entityQueryRequest != null && entityQueryRequest.Ids != null, x => entityQueryRequest.Ids.Contains(x.Id))
-                .Where(x => x.EndTime < DateTime.Now);
+                .Where(x => x.EndTime < DateTime.Now && x.ExamStatus != Share.Enums.Exams.EExamStatus.Complete);
             var examManages = await queryable.ToListAsync();
 
             examManages.ForEach(item =>

+ 55 - 51
src/Hotline.Application/Exam/Service/ExamManages/UserExamService.cs

@@ -106,12 +106,12 @@ namespace Hotline.Application.Exam.Service.ExamManages
             {
                 var examQuestionDto = _mapper.Map<ExamQuestionDto>(question);
 
-                var questionScore = await new ExamRepository<ExamQuestionScoreBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).GetAsync(x=>x.QuestionType == question.QuestionType && x.ExamManageId == question.ExamId);
+                var questionScore = await new ExamRepository<ExamQuestionScoreBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).GetAsync(x => x.QuestionType == question.QuestionType && x.ExamManageId == question.ExamId);
 
                 if (questionScore != null)
                 {
                     examQuestionDto.Score = questionScore.Score;
-                }               
+                }
 
                 if (examQuestionDto.QuestionType.CheckSelectType())
                 {
@@ -383,7 +383,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
             }
             // TODO: 删除之前选项和答案
-            else if(userExam.ExamStatus == EExamStatus.Complete)
+            else if (userExam.ExamStatus == EExamStatus.Complete)
             {
                 await ReExam(userExam, cancellationToken);
             }
@@ -646,9 +646,9 @@ namespace Hotline.Application.Exam.Service.ExamManages
             return gradingExamQuestionDtos;
         }
 
-        private ISugarQueryable<GradingExamQuestionTempDto> GetViewExamQuestionTempDtos(Expression<Func<ExamUserExam,bool>> expression)
+        private ISugarQueryable<GradingExamQuestionTempDto> GetViewExamQuestionTempDtos(Expression<Func<ExamUserExam, bool>> expression)
         {
-           
+
             var userExamTable = _repository.Queryable().Where(expression);
 
             var questionScoreRepository = new ExamRepository<ExamQuestionScoreBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
@@ -662,7 +662,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
             var questionScoreTable = questionScoreRepository.Queryable();
 
             return userExamTable.InnerJoin(userExamItemTable, (e, i) => e.Id == i.UserExamId)
-                .InnerJoin(questionTable, (e, i, q) => i.QuestionId == q.QuestionId && q.ExamId == e.ExamId )
+                .InnerJoin(questionTable, (e, i, q) => i.QuestionId == q.QuestionId && q.ExamId == e.ExamId)
                 .LeftJoin(userExamItemOptionTable, (e, i, q, o) => i.Id == o.UserExamItemId)
                 .LeftJoin(quesitonOptionTable, (e, i, q, o, qo) => o.QuestionOptionId == qo.Id)
                 .LeftJoin(examAnswerTable, (e, i, q, o, qo, a) => i.Id == a.UserExamItemId)
@@ -700,8 +700,8 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
         public async Task<UnExamUserPageViewResponse> GetUnExamUsers(UnExamUserReportPagedRequest unExamUserReportPagedRequest)
         {
-            if(unExamUserReportPagedRequest.EndTime == null)
-            unExamUserReportPagedRequest.ResolveEndTime();
+            if (unExamUserReportPagedRequest.EndTime == null)
+                unExamUserReportPagedRequest.ResolveEndTime();
 
             var examManageRepository = new ExamRepository<ExamManage>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
             var userRepository = new ExamRepository<User>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
@@ -719,7 +719,9 @@ namespace Hotline.Application.Exam.Service.ExamManages
                     ExamName = e.Name,
                     OrgName = u.Organization.Name,
                     UserName = u.Name
-                });
+                })
+                .MergeTable()
+                .OrderByPropertyNameIF(!string.IsNullOrEmpty(unExamUserReportPagedRequest.SortField), unExamUserReportPagedRequest.SortField, (OrderByType)(unExamUserReportPagedRequest.SortRule ?? 0));
 
             var total = await queryResult.CountAsync();
             var items = await queryResult.ToPageListAsync(unExamUserReportPagedRequest.PageIndex, unExamUserReportPagedRequest.PageSize);
@@ -734,8 +736,8 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
         public async Task<UserExamResultPageViewResponse> GetUserExamResults(UserExamResultReportPagedRequest userExamResultReportPagedRequest)
         {
-            if(userExamResultReportPagedRequest.EndTime == null)
-            userExamResultReportPagedRequest.ResolveEndTime();
+            if (userExamResultReportPagedRequest.EndTime == null)
+                userExamResultReportPagedRequest.ResolveEndTime();
 
             var examManageRepository = new ExamRepository<ExamManage>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
             var userRepository = new ExamRepository<User>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
@@ -748,18 +750,20 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
             var queryResult = userExamTable.InnerJoin(examManageTable, (ue, e) => ue.ExamId == e.Id)
                 .InnerJoin(userTable, (ue, e, u) => ue.UserId == u.Id)
-                .Select((ue, e, u) => new UserExamResultViewResponse
-                {
-                    ExamName = e.Name,
-                    OrgName = u.Organization.Name,
-                    UserName = u.Name,
-                    TotalScore = e.TotalScore,
-                    CutoffScore = e.CutoffScore,
-                    Score = ue.Score ?? 0,
-
-                })
+               .Select((ue, e, u) => new UserExamResultViewResponse
+               {
+                   ExamName = e.Name,
+                   OrgName = u.Organization.Name,
+                   UserName = u.Name,
+                   TotalScore = e.TotalScore,
+                   CutoffScore = e.CutoffScore,
+                   Score = ue.Score ?? 0,
+
+               })
                 .MergeTable()
-                .OrderByDescending(x => x.Score);
+               .OrderByPropertyNameIF(!string.IsNullOrEmpty(userExamResultReportPagedRequest.SortField), userExamResultReportPagedRequest.SortField, (OrderByType)(userExamResultReportPagedRequest.SortRule ?? 0))
+                .OrderByDescending(x => x.Score)
+      ;
 
             var total = await queryResult.CountAsync();
             var items = await queryResult.ToPageListAsync(userExamResultReportPagedRequest.PageIndex, userExamResultReportPagedRequest.PageSize);
@@ -912,7 +916,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
             var userExamIds = addUserExamItemDtos.Select(x => x.UserExamId).ToList();
             var questionTypes = addUserExamItemDtos.Select(x => x.QuestionType).ToList();
 
-            List<ExamQuestionOptionsBak> examQuestionOptions = await GetQuestionOptionBaks(questionIds, userExamIds,true).ToListAsync();
+            List<ExamQuestionOptionsBak> examQuestionOptions = await GetQuestionOptionBaks(questionIds, userExamIds, true).ToListAsync();
 
             var userExamItemOptionRepository = new ExamRepository<ExamUserExamItemOptions>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
             var examQuestionScoreRepository = new ExamRepository<ExamQuestionScoreBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
@@ -943,7 +947,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
             await userExamItemRepository.UpdateWithValidateAsync(userExamItems, cancellationToken);
         }
 
-        private ISugarQueryable<ExamQuestionOptionsBak> GetQuestionOptionBaks(List<string> questionIds, List<string> userExamIds,bool isFilterAnswer)
+        private ISugarQueryable<ExamQuestionOptionsBak> GetQuestionOptionBaks(List<string> questionIds, List<string> userExamIds, bool isFilterAnswer)
         {
             var questionRepository = new ExamRepository<Exams.ExamManages.ExamQuestionBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
             var questionTable = questionRepository.Queryable().Where(x => x.QuestionType == EQuestionType.Single || x.QuestionType == EQuestionType.Multi || x.QuestionType == EQuestionType.Judge);
@@ -953,7 +957,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
             var examQuestionOptionsRepository = new ExamRepository<ExamQuestionOptionsBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
             var examQuestionOptionsTable = examQuestionOptionsRepository.Queryable()
                 .Where(x => questionIds.Contains(x.QuestionId))
-                .WhereIF(isFilterAnswer,x=>x.IsAnswer);
+                .WhereIF(isFilterAnswer, x => x.IsAnswer);
             var examQuestionOptions = examQuestionOptionsTable.InnerJoin(questionTable, (t, i) => t.ExamQuestionId == i.Id)
                 .InnerJoin(examManageTable, (t, i, e) => i.ExamId == e.Id)
                 .InnerJoin(userExamTable, (t, i, e, u) => e.Id == u.ExamId)
@@ -1340,7 +1344,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 Score = u.Score ?? 0,
                 Status = u.Status,
                 SortIndex = u.SortIndex,
-                ExamStatus = u.ExamStatus,
+                ExamStatus = u.ExamStatus == EExamStatus.Absent? EExamStatus.Complete: u.ExamStatus,
                 IsSuccess = u.IsCheck ? u.IsSuccess : null,
                 EndTime = e.EndTime,
                 StartTime = e.StartTime,
@@ -1349,15 +1353,15 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 ExamId = e.Id,
                 IsCheck = u.IsCheck,
                 IsReExam = u.IsReExam,
-                CanReExam = SqlFunc.Subqueryable<ExamUserExamItem>().Where(x=>x.UserExamId == u.Id).Count()< e.Count
+                CanReExam = SqlFunc.Subqueryable<ExamUserExamItem>().Where(x => x.UserExamId == u.Id).Count() < e.Count
             });
             return queryable;
         }
 
         public async Task<List<ViewExamQuestionDto>> View(string id)
         {
-           
-            List<ViewExamQuestionDto> viewExamQuestionDtos = await GetViewExamQuestion(id,null);
+
+            List<ViewExamQuestionDto> viewExamQuestionDtos = await GetViewExamQuestion(id, null);
 
             var examQuestionIds = viewExamQuestionDtos.Select(x => x.ExamQuestionId).ToList();
             var questionIds = viewExamQuestionDtos.Select(x => x.QuestionId).ToList();
@@ -1414,12 +1418,12 @@ namespace Hotline.Application.Exam.Service.ExamManages
             });
         }
 
-        private  async Task<List<QuestionSourcewareDto>> GetSourcewares(List<string> questionIds)
+        private async Task<List<QuestionSourcewareDto>> GetSourcewares(List<string> questionIds)
         {
             var questionSourcewareTable = new ExamRepository<ExamQuestionSourcewareBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
             var sourcewareTable = new ExamRepository<ExamSourceware>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
 
-            var querable = questionSourcewareTable.InnerJoin<ExamQuestionSourceware>((qsb,qs)=>qsb.SourcewareId == qs.Id).InnerJoin(sourcewareTable, (qsb,qs, s) => qs.SourcewareId == s.Id).Select((qsb, qs, s) => new QuestionSourcewareDto
+            var querable = questionSourcewareTable.InnerJoin<ExamQuestionSourceware>((qsb, qs) => qsb.SourcewareId == qs.Id).InnerJoin(sourcewareTable, (qsb, qs, s) => qs.SourcewareId == s.Id).Select((qsb, qs, s) => new QuestionSourcewareDto
             {
                 Id = qs.Id,
                 Name = s.Name,
@@ -1431,28 +1435,28 @@ namespace Hotline.Application.Exam.Service.ExamManages
             return await querable.ToListAsync();
         }
 
-        private  async Task<List<QuestionKnowladgeDto>> GetQuestionKnowladges(List<string> questionIds)
+        private async Task<List<QuestionKnowladgeDto>> GetQuestionKnowladges(List<string> questionIds)
         {
             var questionKnowladgeTable = new ExamRepository<ExamQuestionKnowladgeBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
-            
+
 
             return await questionKnowladgeTable.Where(x => questionIds.Contains(x.ExamQuestionId))
-                .InnerJoin<ExamQuestionKnowladge>((kb,k)=>kb.KnowladgeId == k.Id).Select((kb, k) => new QuestionKnowladgeDto
-            {
-                Id = kb.Id,
-                QuestionId = kb.ExamQuestionId,
-                KnowladgeId = k.KnowladgeId,
-                Title = kb.Title
-            }).ToListAsync();
+                .InnerJoin<ExamQuestionKnowladge>((kb, k) => kb.KnowladgeId == k.Id).Select((kb, k) => new QuestionKnowladgeDto
+                {
+                    Id = kb.Id,
+                    QuestionId = kb.ExamQuestionId,
+                    KnowladgeId = k.KnowladgeId,
+                    Title = kb.Title
+                }).ToListAsync();
         }
 
-        private  async Task<List<ViewQuestionOptionDto>> GetQuestionOptions(List<string> questionIds,List<string> userExamIds)
+        private async Task<List<ViewQuestionOptionDto>> GetQuestionOptions(List<string> questionIds, List<string> userExamIds)
         {
-            var selectQuestionOptions = GetQuestionOptionBaks(questionIds, userExamIds,false).MergeTable();
+            var selectQuestionOptions = GetQuestionOptionBaks(questionIds, userExamIds, false).MergeTable();
 
             var userExamItemOptionTable = _userExamItemOptionRepository.Queryable();
 
-            var querable = selectQuestionOptions 
+            var querable = selectQuestionOptions
                 .LeftJoin(userExamItemOptionTable, (op, uio) => op.Id == uio.QuestionOptionId)
                 .Select((op, uio) => new ViewQuestionOptionDto
                 {
@@ -1468,7 +1472,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 .ToListAsync();
         }
 
-        private  async Task<List<ViewQuestionAnswerDto>> GetQuestionAnswers(string id, List<string> questionIds)
+        private async Task<List<ViewQuestionAnswerDto>> GetQuestionAnswers(string id, List<string> questionIds)
         {
             var userExamTable = _repository.Queryable().Where(x => x.Id == id);
             var userExamItemTable = _userExamItemRepository.Queryable();
@@ -1477,11 +1481,11 @@ namespace Hotline.Application.Exam.Service.ExamManages
             var questionAnswerTable = new ExamRepository<ExamQuestionAnswerBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
 
             var querable = examAnswerTable
-                .InnerJoin(userExamItemTable, (a, ui) => ui.Id == a.UserExamItemId &&  ui.UserExamId == id)
-                .LeftJoin(questionAnswerTable, (a, ui, qab) => qab.QuestionId == ui.QuestionId  )
-                .LeftJoin<ExamQuestionAnswer>((a, ui, qab ,qa) => qab.QuestionAnswerId == qa.Id )
-                .LeftJoin(questionTable, (a, ui, qab, qa,q)=>qab.QuestionId == q.QuestionId && questionIds.Contains(q.Id))
-                .Select((a, ui, qab, qa,q) => new ViewQuestionAnswerDto
+                .InnerJoin(userExamItemTable, (a, ui) => ui.Id == a.UserExamItemId && ui.UserExamId == id)
+                .LeftJoin(questionAnswerTable, (a, ui, qab) => qab.QuestionId == ui.QuestionId)
+                .LeftJoin<ExamQuestionAnswer>((a, ui, qab, qa) => qab.QuestionAnswerId == qa.Id)
+                .LeftJoin(questionTable, (a, ui, qab, qa, q) => qab.QuestionId == q.QuestionId && questionIds.Contains(q.Id))
+                .Select((a, ui, qab, qa, q) => new ViewQuestionAnswerDto
                 {
                     Answer = a.Answer,
                     CorrectAnswer = qa.Answer != null ? qa.Answer : string.Empty,
@@ -1491,7 +1495,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
             return await querable.ToListAsync();
         }
 
-        private  async Task<List<ViewExamQuestionDto>> GetViewExamQuestion(string id,string questionId)
+        private async Task<List<ViewExamQuestionDto>> GetViewExamQuestion(string id, string questionId)
         {
             var expression = ExpressionableUtility.CreateExpression<ExamUserExam>()
                 .And(x => x.Id == id).ToExpression();
@@ -1510,7 +1514,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
             {
                 Answer = g.FirstOrDefault().Answer,
                 QuestionType = g.Key.QuestionType,
-                QuestionId= g.FirstOrDefault().QuestionId,
+                QuestionId = g.FirstOrDefault().QuestionId,
                 ExamQuestionId = g.FirstOrDefault().ExamQuestionId,
                 Id = g.Key.Id,
                 Score = g.FirstOrDefault().QuestionScore,

+ 4 - 1
src/Hotline.Application/Exam/Service/Trains/TrainRecordService.cs

@@ -32,6 +32,7 @@ using JiebaNet.Segmenter.Common;
 using Hotline.Repository.SqlSugar.Exam.Service;
 using Hotline.Repository.SqlSugar.Exam.Extensions;
 using DocumentFormat.OpenXml.Office2010.Excel;
+using SqlSugar;
 
 namespace Hotline.Application.Exam.Service.Trains
 {
@@ -236,7 +237,9 @@ namespace Hotline.Application.Exam.Service.Trains
                     IsComplete = r.IsComplete,
                     SortIndex = r.SortIndex,
                     Status = r.Status
-                });
+                })
+                .MergeTable()
+               .OrderByPropertyNameIF(!string.IsNullOrEmpty(trainResultReportPagedRequest.SortField), trainResultReportPagedRequest.SortField, (OrderByType)(trainResultReportPagedRequest.SortRule ?? 0));
 
             var total = await queryResult.CountAsync();
 

+ 4 - 2
src/Hotline.Application/Jobs/ApptaskJob.cs

@@ -6,6 +6,8 @@ using Microsoft.Extensions.DependencyInjection;
 using Hotline.EventBus;
 using Hotline.Share.Dtos.Order.OrderVisit;
 using Hotline.Share.Dtos.Order.OrderDelay;
+using Hotline.Application.OrderApp.OrderDelayApp;
+using Hotline.Application.OrderApp.OrderVisitApp;
 
 namespace Hotline.Application.Jobs
 {
@@ -34,13 +36,13 @@ namespace Hotline.Application.Jobs
             switch (task.TaskType)
             {
                 case ETaskType.OrderDelay:
-                    var delayExecutor = _serviceProvider.GetService<IApptaskExecutor<OrderDelayReviewRequest>>();
+                    var delayExecutor = _serviceProvider.GetService<IApptaskExecutor<OrderDelayReviewWithSessionRequest>>();
                     result = await _apptaskDomainService.ExecuteAsync(delayExecutor, task, context.CancellationToken);
                     break;
                 case ETaskType.OrderScreen:
                     break;
                 case ETaskType.VoiceVisit:
-                    var vvExecutor = _serviceProvider.GetService<IApptaskExecutor<VoiceVisitRequest>>();
+                    var vvExecutor = _serviceProvider.GetService<IApptaskExecutor<VoiceVisitWithSessionRequest>>();
                     result = await _apptaskDomainService.ExecuteAsync(vvExecutor, task, context.CancellationToken);
                     break;
                 default:

+ 31 - 11
src/Hotline.Application/OrderApp/Handlers/OrderDelayHandler/OrderDelayBatchReviewTaskCompetedHandler.cs

@@ -9,9 +9,12 @@ using System.Threading.Tasks;
 using Hotline.BatchTask;
 using Hotline.Share.Enums.BatchTask;
 using Hotline.Article;
+using Hotline.Orders;
 using Hotline.Share.Dtos.Article;
 using Hotline.Share.Enums.Article;
+using Hotline.Share.Enums.Order;
 using XF.Domain.Authentications;
+using XF.Domain.Repository;
 
 namespace Hotline.Application.OrderApp.Handlers.OrderDelayHandler;
 
@@ -20,14 +23,17 @@ namespace Hotline.Application.OrderApp.Handlers.OrderDelayHandler;
 /// </summary>
 public class OrderDelayBatchReviewTaskCompetedHandler : INotificationHandler<ApptaskCompletedNotify>
 {
-    private readonly IApptaskDomainService _apptaskDomainService;
+    private readonly IRepository<Apptask> _apptaskRepository;
+    private readonly IOrderDelayRepository _orderDelayRepository;
     private readonly ICircularRecordDomainService _circularRecordDomainService;
 
     public OrderDelayBatchReviewTaskCompetedHandler(
-        IApptaskDomainService apptaskDomainService,
+        IRepository<Apptask> apptaskRepository,
+        IOrderDelayRepository orderDelayRepository,
         ICircularRecordDomainService circularRecordDomainService)
     {
-        _apptaskDomainService = apptaskDomainService;
+        _apptaskRepository = apptaskRepository;
+        _orderDelayRepository = orderDelayRepository;
         _circularRecordDomainService = circularRecordDomainService;
     }
 
@@ -36,25 +42,39 @@ public class OrderDelayBatchReviewTaskCompetedHandler : INotificationHandler<App
     /// <param name="cancellationToken">Cancellation token</param>
     public async Task Handle(ApptaskCompletedNotify notification, CancellationToken cancellationToken)
     {
-        if(notification.ApptaskItem.TaskType is not ETaskType.OrderDelay) return;
+        if (notification.ApptaskItem.TaskType is not ETaskType.OrderDelay) return;
+
+        var apptask = await _apptaskRepository.Queryable()
+            .Includes(d => d.ApptaskItems)
+            .FirstAsync(d => d.Id == notification.ApptaskItem.ApptaskId, cancellationToken);
+        var unSuccessItems = apptask.ApptaskItems
+            .Where(d => d.TaskStatus != ETaskStatus.Succeeded)
+            .ToList();
+        if (unSuccessItems.Count > 0)
+        {
+            // 回滚delay状态为待审批
+            await _orderDelayRepository.Updateable()
+                .SetColumns(d => d.DelayState == EDelayState.Examining)
+                .Where(d => unSuccessItems.Select(x => x.BusinessId).Contains(d.Id))
+                .ExecuteCommandAsync(cancellationToken);
+        }
 
-        var progress = await _apptaskDomainService.GetProgressAsync(notification.ApptaskItem.ApptaskId, cancellationToken);
         await _circularRecordDomainService.AddCircularMessage(new AddCircularDto
         {
-            Title = $"{progress.Name} 执行完成",
-            Content = $"总共:{progress.Total}条数据,成功:{progress.Succeeded}条,失败:{progress.Failed}条",
+            Title = $"{apptask.Name} 执行完成",
+            Content = $"总共:{apptask.ApptaskItems.Count}个任务,成功:{apptask.ApptaskItems.Count(d => d.TaskStatus == ETaskStatus.Succeeded)},失败:{apptask.ApptaskItems.Count(d => d.TaskStatus == ETaskStatus.Failed)}",
             CircularTypeId = "5",
             CircularTypeName = "系统消息",
             CircularType = ECircularType.Person,
             IsMustRead = false,
-            SourceOrgId = progress.CreatorId,
-            SourceOrgName = progress.CreatorName,
+            SourceOrgId = apptask.CreatorId,
+            SourceOrgName = apptask.CreatorName,
             CircularReadGroups = new List<CircularReadGroupDto>
             {
                 new()
                 {
-                    UserId = progress.CreatorId,
-                    UserName = progress.CreatorName
+                    UserId = apptask.CreatorId,
+                    UserName = apptask.CreatorName
                 }
             }
         }, cancellationToken);

+ 14 - 0
src/Hotline.Application/OrderApp/IOrderApplication.cs

@@ -245,6 +245,20 @@ namespace Hotline.Application.OrderApp
         /// <returns></returns>
         ISugarQueryable<OrderBiCentreDataListVo> CentreDataList(ReportPagedRequest dto);
 
+        /// <summary>
+        /// 话务员办件统计--自贡专用
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<OrderBiCentreDataListVo> CentreDataListZG(ReportPagedRequest dto);
+
+        /// <summary>
+        /// 话务员办件统计明细--自贡专用
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<Order> CentreDataListDetailZG(CentreDataListDetailRequest dto);
+
         /// <summary>
         /// 工单业务量统计
         /// </summary>

+ 119 - 9
src/Hotline.Application/OrderApp/OrderApplication.cs

@@ -46,6 +46,7 @@ using Hotline.Share.Enums.Settings;
 using Hotline.Share.Mq;
 using Hotline.Share.Requests;
 using Hotline.Share.Tools;
+using Hotline.Snapshot.IRepository;
 using Hotline.Statistics;
 using Hotline.Tools;
 using Hotline.Users;
@@ -71,6 +72,7 @@ namespace Hotline.Application.OrderApp;
 
 public class OrderApplication : IOrderApplication, IScopeDependency
 {
+    private readonly IOrderSnapshotRepository _orderSnapshotRepository;
     private readonly IMediator _mediator;
     private readonly IRepository<TranspondCityRawData> _transpondCityRawDataRepository;
     private readonly ISessionContextProvider _sessionContextProvider;
@@ -181,7 +183,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         IRepository<OrderVisitDetailCopy> orderVisitDetailCopyRepository,
         IRepository<OrderDelayAutomatic> orderDelayAutomaticRepository,
         IRepository<Hotline.Orders.ObservationPiece> observationPieceRepository
-        )
+,
+        IOrderSnapshotRepository orderSnapshotRepository)
     {
         _orderDomainService = orderDomainService;
         _workflowDomainService = workflowDomainService;
@@ -236,6 +239,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         _orderVisitDetailCopyRepository = orderVisitDetailCopyRepository;
         _orderDelayAutomaticRepository = orderDelayAutomaticRepository;
         _observationPieceRepository = observationPieceRepository;
+        _orderSnapshotRepository = orderSnapshotRepository;
     }
 
     /// <summary>
@@ -1764,15 +1768,23 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     {
         var orderVisitList = await _orderVisitRepository.Queryable()
             .Includes(d => d.Order)
-            .Where(d => dto.Ids.Contains(d.Id) && (d.VisitState == EVisitState.WaitForVisit || d.VisitState == EVisitState.NoSatisfiedWaitForVisit ||
-                                                   d.VisitState == EVisitState.SMSUnsatisfied))
+            .Where(d => dto.Ids.Contains(d.Id) && (d.VisitState == EVisitState.WaitForVisit || d.VisitState == EVisitState.NoSatisfiedWaitForVisit || d.VisitState == EVisitState.SMSUnsatisfied))
             .Select(d => new { d.Id, d.Order.SourceChannelCode, d.Order.Contact, d.Order.Password, d.No, d.OrderId, d.Order.Title, d.Order.FromName })
             .ToListAsync(cancellationToken);
 
         foreach (var item in orderVisitList)
         {
             var code = "1013";
-            if (item.SourceChannelCode == "ZGSSP") code = "1012";
+            if (_systemSettingCacheManager.Snapshot && item.SourceChannelCode == "ZGSSP")
+            {
+                await _orderSnapshotRepository.Queryable().Where(m => m.Id == item.OrderId)
+                    .Select(m => m.IndustryName)
+                    .FirstAsync()
+                    .Then(name => 
+                    {
+                        if (name.Trim() == "电气焊作业申报") code = "1012";
+                    });
+            }
             var messageDto = new Share.Dtos.Push.MessageDto
             {
                 PushBusiness = EPushBusiness.VisitSms,
@@ -1875,8 +1887,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                                                                                                                //.WhereIF(!string.IsNullOrEmpty(dto.OrgId), d => d.CurrentHandleOrgId == dto.OrgId)//接办部门
                 .WhereIF(!string.IsNullOrEmpty(dto.OrgLevelOneName), d => d.OrgLevelOneName.Contains(dto.OrgLevelOneName)) //一级部门
                 .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), d => d.ActualHandleOrgName.Contains(dto.ActualHandleOrgName)) //接办部门(综合查询模糊)
-				.WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgCode), d => d.ActualHandleOrgCode.StartsWith(dto.ActualHandleOrgCode)) //接办部门(综合查询模糊)
-				.WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName == dto.NameOrNo! || d.AcceptorStaffNo == dto.NameOrNo!) //受理人/坐席
+                .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgCode), d => d.ActualHandleOrgCode.StartsWith(dto.ActualHandleOrgCode)) //接办部门(综合查询模糊)
+                .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName == dto.NameOrNo! || d.AcceptorStaffNo == dto.NameOrNo!) //受理人/坐席
                 .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
                 .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
                 .WhereIF(dto.StartTimeStart.HasValue, d => d.StartTime >= dto.StartTimeStart) //流程开启时间开始
@@ -1934,9 +1946,9 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 .WhereIF(!string.IsNullOrEmpty(dto.OrderTagCode), d => d.OrderTags.Any(ot => ot.DicDataValue == dto.OrderTagCode)) //工单标签
                 .WhereIF(!string.IsNullOrEmpty(dto.FocusOnEvents),
                     d => d.FocusOnEvents.Contains(dto.FocusOnEvents) && !d.FocusOnEvents.Contains("99")) //!string.IsNullOrEmpty(d.FocusOnEvents) && SqlFunc.SplitIn(d.FocusOnEvents, dto.FocusOnEvents))
-				 .WhereIF(dto.SeatEvaluate.Any(), d => dto.SeatEvaluate.Contains(d.SeatEvaluate.Value)) //话务员评价(话务评价)
-				.WhereIF(dto.OrgProcessingResults.Any(),d => dto.OrgProcessingResults.Contains(SqlFunc.JsonField(d.OrgProcessingResults, "Key")))//部门办件结果
-				.OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.CreationTime, OrderByType.Desc) //默认排序时间为创建时间
+                 .WhereIF(dto.SeatEvaluate.Any(), d => dto.SeatEvaluate.Contains(d.SeatEvaluate.Value)) //话务员评价(话务评价)
+                .WhereIF(dto.OrgProcessingResults.Any(), d => dto.OrgProcessingResults.Contains(SqlFunc.JsonField(d.OrgProcessingResults, "Key")))//部门办件结果
+                .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.CreationTime, OrderByType.Desc) //默认排序时间为创建时间
                 .OrderByIF(dto is { SortField: "no", SortRule: 0 }, d => d.No, OrderByType.Asc) //工单编号升序
                 .OrderByIF(dto is { SortField: "no", SortRule: 1 }, d => d.No, OrderByType.Desc) //工单编号降序
                 .OrderByIF(dto is { SortField: "isProvinceText", SortRule: 0 }, d => d.IsProvince, OrderByType.Asc) //是否省工单升序
@@ -3558,6 +3570,104 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         return query;
     }
 
+    /// <summary>
+    /// 话务员办件统计--自贡专用
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public ISugarQueryable<OrderBiCentreDataListVo> CentreDataListZG(ReportPagedRequest dto)
+    {
+        if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
+
+        var query = _orderRepository.Queryable(false, false, false)
+            .WhereIF(dto.StartTime.HasValue, it => it.CreationTime >= dto.StartTime)
+            .WhereIF(dto.EndTime.HasValue, it => it.CreationTime <= dto.EndTime)
+            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), it => it.SignerName.Contains(dto.Keyword!))
+            .GroupBy(it => new { it.AcceptorId })
+            .Select(it => new OrderBiCentreDataListVo
+            {
+                UserId = it.AcceptorId,
+                CentreArchive = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed && it.FileOrgIsCenter == true, 1, 0)), //中心归档件
+
+                CentreCareOf = SqlFunc.AggregateSum(SqlFunc.IIF((it.Status >= EOrderStatus.Filed && it.FileOrgIsCenter == false) ||
+               (it.ActualHandleStepName != "话务部" && it.Status < EOrderStatus.Filed && it.Status > EOrderStatus.WaitForAccept)
+               , 1, 0)),//转办件(部门归档件+已开启流程且当前节点在非话务部的办理中的工单)
+
+                NoCentreCareOf = SqlFunc.AggregateSum(SqlFunc.IIF(it.ActualHandleStepName == "话务部" &&
+                it.Status < EOrderStatus.Filed && it.Status > EOrderStatus.WaitForAccept, 1, 0)),//待转办信件(当前节点为话务部,已受理未归档的工单)
+                Invalid = 0,
+                Repeat = 0,
+                Subtotal = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status > EOrderStatus.WaitForAccept, 1, 0))//排除待受理工单
+            })
+            .LeftJoin<User>((it, u) => it.UserId == u.Id)
+            .Select((it, u) => new OrderBiCentreDataListVo
+            {
+                UserId = it.UserId,
+                UserName = u.Name,
+                CentreArchive = it.CentreArchive,
+                CentreCareOf = it.CentreCareOf,
+                NoCentreCareOf = it.NoCentreCareOf,
+                Invalid = it.Invalid,
+                Repeat = it.Repeat,
+                Subtotal = it.Subtotal
+            }).MergeTable()
+            ;
+        switch (dto.SortField)
+        {
+            case "centreArchive":
+                query = dto.SortRule is 0 ? query.OrderBy(x => x.CentreArchive) : query.OrderByDescending(x => x.CentreArchive);
+                break;
+            case "centreCareOf":
+                query = dto.SortRule is 0 ? query.OrderBy(x => x.CentreCareOf) : query.OrderByDescending(x => x.CentreCareOf);
+                break;
+            case "noCentreCareOf":
+                query = dto.SortRule is 0 ? query.OrderBy(x => x.NoCentreCareOf) : query.OrderByDescending(x => x.NoCentreCareOf);
+                break;
+            case "subtotal":
+                query = dto.SortRule is 0 ? query.OrderBy(x => x.Subtotal) : query.OrderByDescending(x => x.Subtotal);
+                break;
+        }
+
+        if (string.IsNullOrEmpty(dto.SortField))
+        {
+            query = query.OrderByDescending(x => x.Subtotal);
+        }
+
+        return query;
+    }
+
+    /// <summary>
+    /// 话务员办件统计明细--自贡专用
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public ISugarQueryable<Order> CentreDataListDetailZG(CentreDataListDetailRequest dto)
+    {
+        var query = _orderRepository.Queryable(false, false, false)
+       .WhereIF(dto.StartTime.HasValue, p => p.CreationTime >= dto.StartTime)
+       .WhereIF(dto.EndTime.HasValue, p => p.CreationTime <= dto.EndTime)
+       .WhereIF(!string.IsNullOrEmpty(dto.UserId), p => p.AcceptorId == dto.UserId)
+       .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.No == dto.No)
+       .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Title.Contains(dto.Title))
+       ;
+        if (dto.FieldName == "subtotal")//所有信件
+            query = query.Where(p => p.Status > EOrderStatus.WaitForAccept);
+
+        if (dto.FieldName == "centreArchive")//中心归档件
+            query = query.Where(p => p.Status >= EOrderStatus.Filed && p.FileOrgIsCenter == true);
+
+        if (dto.FieldName == "centreCareOf")//转办信件
+            query = query.Where(p => (p.Status >= EOrderStatus.Filed && p.FileOrgIsCenter == false) ||
+               (p.ActualHandleStepName != "话务部" && p.Status < EOrderStatus.Filed && p.Status > EOrderStatus.WaitForAccept));
+
+        if (dto.FieldName == "noCentreCareOf")//待转办信件
+            query = query.Where(p => p.ActualHandleStepName == "话务部" && p.Status < EOrderStatus.Filed && p.Status > EOrderStatus.WaitForAccept);
+
+        query = query.OrderByDescending(p => p.CreationTime);
+
+        return query;
+    }
+
     /// <summary>
     /// 工单业务量统计
     /// </summary>

+ 3 - 1
src/Hotline.Application/OrderApp/OrderDelayApp/OrderDelayApplication.cs

@@ -6,6 +6,7 @@ using Hotline.Share.Enums.FlowEngine;
 using MapsterMapper;
 using Microsoft.AspNetCore.Http;
 using System.Threading;
+using Hotline.Authentications;
 using Hotline.BatchTask;
 using Hotline.Orders;
 using Hotline.Share.Dtos.BatchTask;
@@ -186,8 +187,9 @@ public class OrderDelayApplication : IOrderDelayApplication, IScopeDependency
             .ToListAsync(cancellation);
 
         var apptaskItems = new List<AddApptaskItemRequest>();
-        var req = new OrderDelayReviewRequest
+        var req = new OrderDelayReviewWithSessionRequest
         {
+            SessionContext = _sessionContext,
             IsPass = request.IsPass,
             NextWorkflow = request.NextWorkflow
         };

+ 16 - 0
src/Hotline.Application/OrderApp/OrderDelayApp/OrderDelayReviewWithSessionRequest.cs

@@ -0,0 +1,16 @@
+using Hotline.Share.Dtos.Order.OrderDelay;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Hotline.BatchTask;
+using XF.Domain.Authentications;
+
+namespace Hotline.Application.OrderApp.OrderDelayApp
+{
+    public class OrderDelayReviewWithSessionRequest : OrderDelayReviewRequest, IApptaskRequest
+    {
+        public ISessionContext SessionContext { get; set; }
+    }
+}

+ 1 - 1
src/Hotline.Application/OrderApp/OrderVisitApp/VoiceVisitTaskExecutor.cs

@@ -42,7 +42,7 @@ namespace Hotline.Application.OrderApp.OrderVisitApp
 
             var client = _httpClientFactory.CreateClient();
             client.BaseAddress = new Uri(baseAddress);
-            var url = $"{baseAddress}/groupcall?content=&called1={request.PhoneNo}&called2=&called3=&called4=&called5=&caller=&customerid={request.VisitId}";
+            var url = $"{baseAddress}/groupcall?content=&called1={request.PhoneNo}&called2=&called3=&called4=&called5=&caller=12345&customerid={request.VisitId}";
             var result = await client.GetAsync(url, cancellation);
             return result.IsSuccessStatusCode
                 ? ApptaskExecuteResult.Success()

+ 16 - 0
src/Hotline.Application/OrderApp/OrderVisitApp/VoiceVisitWithSessionRequest.cs

@@ -0,0 +1,16 @@
+using Hotline.Share.Dtos.Order.OrderVisit;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Hotline.BatchTask;
+using XF.Domain.Authentications;
+
+namespace Hotline.Application.OrderApp.OrderVisitApp
+{
+    public class VoiceVisitWithSessionRequest : VoiceVisitRequest, IApptaskRequest
+    {
+        public ISessionContext SessionContext { get; set; }
+    }
+}

+ 3 - 0
src/Hotline.Share/Dtos/Order/OrderBiDto.cs

@@ -74,6 +74,9 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public int Repeat { get; set; }
 
+        /// <summary>
+        /// 所有信件
+        /// </summary>
         //public int Subtotal => CentreArchive + CentreCareOf + NoCentreCareOf + Invalid + Repeat;
         public int Subtotal { get; set; }
     }

+ 15 - 0
src/Hotline.Share/Dtos/Order/OrderDelay/BatchOrderDelayReviewRequest.cs

@@ -0,0 +1,15 @@
+using Hotline.Share.Dtos.FlowEngine.Workflow;
+
+namespace Hotline.Share.Dtos.Order.OrderDelay;
+
+public class BatchOrderDelayReviewRequest
+{
+    public List<DelayWithStepId> DelayWithStepIds { get; set; }
+
+    /// <summary>
+    /// 是否通过
+    /// </summary>
+    public bool IsPass { get; set; }
+
+    public NextWorkflowDto NextWorkflow { get; set; }
+}

+ 7 - 0
src/Hotline.Share/Dtos/Order/OrderDelay/DelayWithStepId.cs

@@ -0,0 +1,7 @@
+namespace Hotline.Share.Dtos.Order.OrderDelay;
+
+public class DelayWithStepId
+{
+    public string DelayId { get; set; }
+    public string StepId { get; set; }
+}

+ 0 - 18
src/Hotline.Share/Dtos/Order/OrderDelay/OrderDelayReviewRequest.cs

@@ -8,24 +8,6 @@ public class OrderDelayReviewRequest
     /// 是否通过
     /// </summary>
     public bool IsPass { get; set; }
-    
-    public NextWorkflowDto NextWorkflow { get; set; }
-}
-
-public class BatchOrderDelayReviewRequest
-{
-    public List<DelayWithStepId> DelayWithStepIds { get; set; }
-
-    /// <summary>
-    /// 是否通过
-    /// </summary>
-    public bool IsPass { get; set; }
 
     public NextWorkflowDto NextWorkflow { get; set; }
-}
-
-public class DelayWithStepId
-{
-    public string DelayId { get; set; }
-    public string StepId { get; set; }
 }

+ 6 - 1
src/Hotline.Share/Enums/Exams/EExamStatus.cs

@@ -18,6 +18,11 @@ namespace Hotline.Share.Enums.Exams
         /// 开始结束
         /// </summary>
         [Description("考试结束")]
-        Complete=2
+        Complete=2,
+        /// <summary>
+        /// 缺考
+        /// </summary>
+        [Description("缺考")]
+        Absent = 3
     }
 }

+ 23 - 0
src/Hotline.Share/Requests/PagedKeywordRequest.cs

@@ -1769,4 +1769,27 @@ public record AreaSubordinateRequest
     /// 线路号
     /// </summary>
     public string? Line { get; set; }
+}
+
+public record CentreDataListDetailRequest : PagedKeywordRequest
+{
+    /// <summary>
+    /// 用户id
+    /// </summary>
+    public string? UserId { get; set; }
+
+    /// <summary>
+    /// 类型
+    /// </summary>
+    public string? FieldName { get; set; }
+
+    /// <summary>
+    /// 编号
+    /// </summary>
+    public string? No {  get; set; }
+
+    /// <summary>
+    /// 标题
+    /// </summary>
+    public string? Title {  get; set; }
 }

+ 13 - 1
src/Hotline/Authentications/SessionContextProvider.cs

@@ -84,7 +84,7 @@ public class SessionContextProvider : ISessionContextProvider, IScopeDependency
         httpContext.User = new ClaimsPrincipal(new ClaimsIdentity(userClaims));
     }
 
-    public void ChangeSession(string userId, string username, string orgId, string orgname, int orgLevel)
+    public void ChangeSession(string userId, string username, string orgId, string orgname, int orgLevel, string orgAreaCode, string orgAreaName)
     {
         var httpContext = _serviceProvider.GetRequiredService<IHttpContextAccessor>().HttpContext;
         httpContext ??= new DefaultHttpContext();
@@ -97,10 +97,22 @@ public class SessionContextProvider : ISessionContextProvider, IScopeDependency
             new(AppClaimTypes.DepartmentId, orgId ?? string.Empty),
             new(AppClaimTypes.DepartmentIsCenter, orgId?.IsCenter().ToString() ?? string.Empty),
             new(AppClaimTypes.DepartmentName, orgname ?? string.Empty),
+            new(AppClaimTypes.DepartmentAreaCode, orgAreaCode ?? string.Empty),
+            new(AppClaimTypes.DepartmentAreaName, orgAreaName ?? string.Empty),
             new(AppClaimTypes.DepartmentLevel, orgLevel.ToString() ?? string.Empty),
             new(AppClaimTypes.AreaId, orgId?.GetHigherOrgId() ?? string.Empty),
         ];
         httpContext.User = new ClaimsPrincipal(new ClaimsIdentity(userClaims));
     }
 
+    public void ChangeSession(ISessionContext sessionContext) =>
+        ChangeSession(
+            sessionContext.UserId,
+            sessionContext.UserName,
+            sessionContext.OrgId,
+            sessionContext.OrgName,
+            sessionContext.OrgLevel,
+            sessionContext.OrgAreaCode,
+            sessionContext.OrgAreaName
+        );
 }

+ 11 - 7
src/Hotline/BatchTask/ApptaskDomainService.cs

@@ -15,17 +15,20 @@ public class ApptaskDomainService : IApptaskDomainService, IScopeDependency
 {
     private readonly IRepository<Apptask> _apptaskRepository;
     private readonly IRepository<ApptaskItem> _apptaskItemRepository;
+    private readonly ISessionContextProvider _sessionContextProvider;
     private readonly IMapper _mapper;
     private readonly ILogger<ApptaskDomainService> _logger;
 
     public ApptaskDomainService(
         IRepository<Apptask> apptaskRepository,
         IRepository<ApptaskItem> apptaskItemRepository,
+        ISessionContextProvider sessionContextProvider,
         IMapper mapper,
         ILogger<ApptaskDomainService> logger)
     {
         _apptaskRepository = apptaskRepository;
         _apptaskItemRepository = apptaskItemRepository;
+        _sessionContextProvider = sessionContextProvider;
         _mapper = mapper;
         _logger = logger;
     }
@@ -162,16 +165,17 @@ public class ApptaskDomainService : IApptaskDomainService, IScopeDependency
     /// <param name="cancellation"></param>
     /// <returns></returns>
     public async Task<ApptaskExecuteResult> ExecuteAsync<TRequest>(IApptaskExecutor<TRequest> executor, ApptaskItem apptaskItem, CancellationToken cancellation)
+    where TRequest : class, IApptaskRequest
     {
         try
         {
-            TRequest request = default;
-            if (!string.IsNullOrEmpty(apptaskItem.TaskParams))
-            {
-                request = System.Text.Json.JsonSerializer.Deserialize<TRequest>(apptaskItem.TaskParams);
-                if (request is null)
-                    throw new UserFriendlyException("任务参数反序列化异常");
-            }
+            if (string.IsNullOrEmpty(apptaskItem.TaskParams))
+                throw new UserFriendlyException($"无效任务参数, taskItemId: {apptaskItem.Id}");
+
+            var request = System.Text.Json.JsonSerializer.Deserialize<TRequest>(apptaskItem.TaskParams);
+            if (request is null)
+                throw new UserFriendlyException($"任务参数反序列化失败, taskItemId: {apptaskItem.Id}");
+            _sessionContextProvider.ChangeSession(request.SessionContext);
             var result = await executor.ExecuteAsync(request, cancellation);
             apptaskItem.TaskStatus = result.IsSuccess ? ETaskStatus.Succeeded : ETaskStatus.Failed;
             apptaskItem.Message = result.Message;

+ 2 - 1
src/Hotline/BatchTask/IApptaskDomainService.cs

@@ -51,6 +51,7 @@ namespace Hotline.BatchTask
         /// <param name="apptaskItem"></param>
         /// <param name="cancellation"></param>
         /// <returns></returns>
-        Task<ApptaskExecuteResult> ExecuteAsync<TRequest>(IApptaskExecutor<TRequest> executor, ApptaskItem apptaskItem, CancellationToken cancellation);
+        Task<ApptaskExecuteResult> ExecuteAsync<TRequest>(IApptaskExecutor<TRequest> executor, ApptaskItem apptaskItem, CancellationToken cancellation)
+            where TRequest : class, IApptaskRequest;
     }
 }

+ 14 - 0
src/Hotline/BatchTask/IApptaskRequest.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Authentications;
+
+namespace Hotline.BatchTask
+{
+    public interface IApptaskRequest
+    {
+        public ISessionContext SessionContext { get; set; }
+    }
+}

+ 2 - 2
src/XF.Domain/Authentications/ISessionContextProvider.cs

@@ -14,8 +14,8 @@ namespace XF.Domain.Authentications
         //public void SetContext(string key);
 
         HttpContext ChangeSessionByUserId(string id, HttpContext httpContext);
-
         Task ChangeSessionByUserIdAsync(string userId, CancellationToken cancellation);
-        void ChangeSession(string userId, string username, string orgId, string orgname, int orgLevel);
+        void ChangeSession(string userId, string username, string orgId, string orgname, int orgLevel, string orgAreaCode, string orgAreaName);
+        void ChangeSession(ISessionContext sessionContext);
     }
 }