Procházet zdrojové kódy

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

田爽 před 1 týdnem
rodič
revize
a146b21cc7
31 změnil soubory, kde provedl 636 přidání a 47 odebrání
  1. 273 6
      src/Hotline.Api/Controllers/OrderApi/OrderComplementController.cs
  2. 3 9
      src/Hotline.Api/Controllers/OrderController.cs
  3. 3 2
      src/Hotline.Application/Exam/QueryExtensions/ExamManages/OfflineExamQueryExtensions.cs
  4. 12 1
      src/Hotline.Application/OrderApp/OrderApplication.cs
  5. 9 6
      src/Hotline.Application/OrderApp/OrderDelayApp/OrderDelayApplication.cs
  6. 1 1
      src/Hotline.Repository.SqlSugar/Exam/Repositories/ExamManages/OfflineExamAnalysisRepository.cs
  7. 7 2
      src/Hotline.Repository.SqlSugar/Exam/Validators/ExamManages/OfflineExamAnalysisValidator.cs
  8. 8 0
      src/Hotline.Share/Dtos/Order/AddOrderComplementDto.cs
  9. 86 7
      src/Hotline.Share/Dtos/Order/ComplementOrderDto.cs
  10. 34 0
      src/Hotline.Share/Dtos/Order/ComplementOrderRequestDto.cs
  11. 6 1
      src/Hotline.Share/Dtos/Order/OrderStartFlowDto.cs
  12. 5 0
      src/Hotline.Share/Dtos/Order/QueryOrderHistoryDto.cs
  13. 3 3
      src/Hotline/Exams/ExamManages/ExamOfflineExamAnalysis.cs
  14. 2 2
      src/Hotline/Exams/ExamManages/OfflineExamAnalysisExcel.cs
  15. 6 0
      src/Hotline/File/File.cs
  16. 7 1
      src/Hotline/Orders/Citizen.cs
  17. 65 0
      src/Hotline/Orders/ComplementOrderService.cs
  18. 22 0
      src/Hotline/Orders/IComplementOrderService.cs
  19. 5 0
      src/Hotline/Orders/OrderComplement.cs
  20. 18 0
      src/Hotline/Orders/OrderComplementCopy.cs
  21. 5 0
      src/Hotline/Orders/OrderDelay.cs
  22. 6 0
      src/Hotline/Orders/OrderVisit.cs
  23. 5 0
      src/Hotline/Orders/OrderVisitDetail.cs
  24. 2 2
      src/Hotline/Push/FWMessage/Message.cs
  25. 6 0
      src/Hotline/Snapshot/CommunityInfo.cs
  26. 8 2
      src/Hotline/Snapshot/OrderSnapshot.cs
  27. 6 0
      src/Hotline/Snapshot/RedPackAudit.cs
  28. 8 2
      src/Hotline/Snapshot/RedPackRecord.cs
  29. 7 0
      src/Hotline/Snapshot/SnapshotPointsRecord.cs
  30. 6 0
      src/Hotline/ThirdAccountDomainServices/ThirdAccount.cs
  31. 2 0
      test/Hotline.Tests/Application/OrderSnapshotApplicationTest.cs

+ 273 - 6
src/Hotline.Api/Controllers/OrderApi/OrderComplementController.cs

@@ -1,10 +1,14 @@
 using Hotline.Article;
 using Hotline.FlowEngine.Workflows;
 using Hotline.Orders;
+using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Article;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.Article;
+using Hotline.Tools;
 using Hotline.Users;
+using MapsterMapper;
 using Microsoft.AspNetCore.Mvc;
 using XF.Domain.Authentications;
 using XF.Domain.Exceptions;
@@ -20,13 +24,19 @@ public class OrderComplementController : BaseController
     private readonly IRepository<WorkflowStep> _workflowStepRepository;
     private readonly IRepository<User> _userRepository;
     private readonly ICircularRecordDomainService _circularRecordDomainService;
+    private readonly IComplementOrderService _complementOrderService;
+    private readonly IMapper _mapper;
+    private readonly IRepository<OrderComplementCopy> _orderComplementCopyRepository;
 
     public OrderComplementController(IOrderDomainService orderDomainService,
        ISessionContext sessionContext,
        IRepository<OrderComplement> orderComplementRepository,
        IRepository<WorkflowStep> workflowStepRepository,
        IRepository<User> userRepository,
-       ICircularRecordDomainService circularRecordDomainService)
+       ICircularRecordDomainService circularRecordDomainService,
+       IComplementOrderService complementOrderService,
+       IMapper mapper,
+       IRepository<OrderComplementCopy> orderComplementCopyRepository)
     {
         _orderDomainService = orderDomainService;
         _sessionContext = sessionContext;
@@ -34,8 +44,11 @@ public class OrderComplementController : BaseController
         _workflowStepRepository = workflowStepRepository;
         _userRepository = userRepository;
         _circularRecordDomainService = circularRecordDomainService;
+        _complementOrderService = complementOrderService;
+        _mapper = mapper;
+        _orderComplementCopyRepository = orderComplementCopyRepository;
     }
-    
+
     /// <summary>
     /// 补充
     /// </summary>
@@ -47,10 +60,8 @@ public class OrderComplementController : BaseController
         return await _orderDomainService.AddOrderComplementAsync(dto, HttpContext.RequestAborted);
     }
 
-    #region 添加补充
-
     /// <summary>
-    /// 添加补充 _notificationWaitSendRepository
+    /// 添加补充 
     /// </summary>
     /// <param name="dto"></param>
     /// <returns></returns>
@@ -72,6 +83,7 @@ public class OrderComplementController : BaseController
             OrderId = dto.OrderId,
             Opinion = dto.Opinion,
             SupplyName = _sessionContext.UserName,
+            SupplyOrg = _sessionContext.OrgName,
             SupplyTime = DateTime.Now,
             No = data.No,
             IsProComplement = false
@@ -146,5 +158,260 @@ public class OrderComplementController : BaseController
         }
     }
 
-    #endregion
+    /// <summary>
+    /// 修改补充
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("update_order_complement")]
+    public async Task UpdateOrderComplement([FromBody] UpdateComplementDto dto)
+    {
+        if (dto == null)
+            throw UserFriendlyException.SameMessage("数据错误!");
+        if (string.IsNullOrEmpty(dto.Opinion))
+            throw UserFriendlyException.SameMessage("补充内容不能为空!");
+        if (dto.Opinion.Length > 2000)
+            throw UserFriendlyException.SameMessage("补充内容限制2000字!");
+        var data = await _orderComplementRepository.GetAsync(p => p.Id == dto.Id, cancellationToken: HttpContext.RequestAborted);
+        if (data == null)
+            throw UserFriendlyException.SameMessage("补充查询失败!");
+        //修改记录
+        var dataCopy = new OrderComplementCopy
+        {
+            OperationType = "0",
+            OrderId = data.OrderId,
+            Opinion = data.Opinion,
+            SupplyName = data.SupplyName,
+            SupplyOrg = data.SupplyOrg,
+            SupplyTime = data.SupplyTime,
+            DsBisId = data.DsBisId,
+            No = data.No,
+            IsProComplement = data.IsProComplement,
+            FileJson = data.FileJson,
+            ComplementId = data.Id
+        };
+
+        await _orderComplementCopyRepository.AddAsync(dataCopy, HttpContext.RequestAborted);
+        //修改
+        data.Opinion = dto.Opinion;
+        await _orderComplementRepository.UpdateAsync(data, HttpContext.RequestAborted);
+    }
+
+    /// <summary>
+    /// 删除补充
+    /// </summary>
+    /// <returns></returns>
+    [HttpGet("delete_order_complement/{id}")]
+    public async Task DeleteOrderComplement(string id)
+    {
+        var data = await _orderComplementRepository.GetAsync(p => p.Id == id, cancellationToken: HttpContext.RequestAborted);
+        if (data == null)
+            throw UserFriendlyException.SameMessage("补充查询失败!");
+
+        //修改记录
+        var dataCopy = new OrderComplementCopy
+        {
+            OperationType = "1",
+            OrderId = data.OrderId,
+            Opinion = data.Opinion,
+            SupplyName = data.SupplyName,
+            SupplyOrg = data.SupplyOrg,
+            SupplyTime = data.SupplyTime,
+            DsBisId = data.DsBisId,
+            No = data.No,
+            IsProComplement = data.IsProComplement,
+            FileJson = data.FileJson,
+            ComplementId = data.Id
+        };
+
+        await _orderComplementCopyRepository.AddAsync(dataCopy, HttpContext.RequestAborted);
+
+        //删除
+        await _orderComplementRepository.RemoveAsync(p => p.Id == id, false, HttpContext.RequestAborted);
+    }
+
+    /// <summary>
+    /// 补充查询
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("get-order-complement-list")]
+    public async Task<PagedDto<ComplementOrderDto>> GetOrderComplementList([FromQuery] ComplementOrderRequestDto dto)
+    {
+        var (total, items) = await _complementOrderService.GetOrderComplementList(dto)
+              .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+        return new PagedDto<ComplementOrderDto>(total, _mapper.Map<IReadOnlyList<ComplementOrderDto>>(items));
+    }
+
+    /// <summary>
+    /// 补充查询列表导出
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+
+    [HttpPost("get-order-complement-list/export")]
+    public async Task<FileStreamResult> OrderTerminateListExport([FromBody] ExportExcelDto<ComplementOrderRequestDto> dto)
+    {
+        var query = _complementOrderService.GetOrderComplementList(dto.QueryDto);
+        List<OrderComplement> 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<ComplementOrderDto>>(data);
+
+        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<ComplementOrderDto>(dto.ColumnInfos);
+
+        var dtos = dataDtos
+            .Select(stu => _mapper.Map(stu, typeof(ComplementOrderDto), dynamicClass))
+            .Cast<object>()
+            .ToList();
+
+        var stream = ExcelHelper.CreateStream(dtos);
+
+        return ExcelStreamResult(stream, "补充查询列表");
+    }
+
+    /// <summary>
+    /// 补充操作记录查询
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("get-order-complement-copy-list")]
+    public async Task<PagedDto<ComplementOrderCopDto>> GetOrderComplementCopyList([FromQuery] ComplementOrderCopyRequestDto dto)
+    {
+        var (total, items) = await _complementOrderService.GetOrderComplementCopyList(dto)
+              .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+        return new PagedDto<ComplementOrderCopDto>(total, _mapper.Map<IReadOnlyList<ComplementOrderCopDto>>(items));
+    }
+
+    /// <summary>
+    /// 补充操作记录列表导出
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("get-order-complement-copy-list/export")]
+    public async Task<FileStreamResult> OrderTerminateCopyListExport([FromBody] ExportExcelDto<ComplementOrderCopyRequestDto> dto)
+    {
+        var query = _complementOrderService.GetOrderComplementCopyList(dto.QueryDto);
+        List<OrderComplementCopy> 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<ComplementOrderCopDto>>(data);
+
+        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<ComplementOrderCopDto>(dto.ColumnInfos);
+
+        var dtos = dataDtos
+            .Select(stu => _mapper.Map(stu, typeof(ComplementOrderCopDto), dynamicClass))
+            .Cast<object>()
+            .ToList();
+
+        var stream = ExcelHelper.CreateStream(dtos);
+
+        return ExcelStreamResult(stream, " 补充操作记录列表");
+    }
+
+    /// <summary>
+    /// 查看记录删除
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    [HttpGet("get-complement-order-copy-delete/{id}")]
+    public async Task<ComplementOrderCopyDetailDto> GetComplementOrderCopyDelete(string id)
+    {
+        ComplementOrderCopyDetailDto detailDto = new ComplementOrderCopyDetailDto();
+        var data = await _orderComplementCopyRepository.Queryable()
+            .Includes(p => p.Order)
+            .Where(p => p.Id == id)
+            .FirstAsync();
+        if (data != null)
+        {
+            detailDto.No = data.No;
+            detailDto.OrderTitle = data.Order.Title;
+            detailDto.UserName = data.SupplyName;
+            detailDto.OrgName = data.CreatorOrgName;
+            detailDto.Opinion = data.Opinion;
+            detailDto.OperationName = data.CreatorName;
+            detailDto.OperationTime = data.CreationTime;
+        }
+        return detailDto;
+    }
+
+    /// <summary>
+    /// 查看记录修改
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    [HttpGet("get-complement-order-copy-update/{id}")]
+    public async Task<object> GetComplementOrderCopyUpdate(string id)
+    {
+        ComplementOrderCopyDetailListDto copyDetailListDto = new ComplementOrderCopyDetailListDto();
+        var updateData = await _orderComplementCopyRepository.Queryable()
+            .Includes(p => p.Order)
+            .Where(p => p.Id == id)
+            .FirstAsync();
+        if (updateData is null)
+            throw UserFriendlyException.SameMessage("修改明细查询失败!");
+
+        ComplementOrderCopyDetailDto oldInfo = new ComplementOrderCopyDetailDto
+        {
+            No = updateData.No,
+            OrderTitle = updateData.Order.Title,
+            UserName = updateData.SupplyName,
+            OrgName = updateData.SupplyOrg,
+            SupplyTime = updateData.SupplyTime,
+            Opinion = updateData.Opinion,
+        };
+
+        var copyNew = await _orderComplementCopyRepository.Queryable()
+            .OrderBy(x => x.CreationTime)
+            .FirstAsync(p => p.ComplementId == updateData.ComplementId && p.CreationTime > updateData.CreationTime);
+
+        ComplementOrderCopyDetailDto newInfo = null;
+        if (copyNew != null)
+        {
+            newInfo = new ComplementOrderCopyDetailDto
+            {
+                No = copyNew.No,
+                OrderTitle = updateData.Order.Title,
+                UserName = updateData.CreatorName,
+                OrgName = updateData.CreatorOrgName,
+                SupplyTime = updateData.CreationTime,
+                Opinion = copyNew.Opinion,
+            };
+        }
+        else
+        {
+            var orderComplement = await _orderComplementRepository.Queryable()
+                .FirstAsync(d => d.Id == updateData.ComplementId);
+            if (orderComplement is not null)
+            {
+                newInfo = new ComplementOrderCopyDetailDto
+                {
+                    No = orderComplement.No,
+                    OrderTitle = updateData.Order.Title,
+                    UserName = updateData.CreatorName,
+                    OrgName = updateData.CreatorOrgName,
+                    SupplyTime = updateData.CreationTime,
+                    Opinion = orderComplement.Opinion
+                };
+            }
+        }
+
+        return new { OldInfo = oldInfo, NewInfo = newInfo };
+    }
 }

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

@@ -4599,18 +4599,12 @@ public class OrderController : BaseController
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!));
 
         //随手拍
-        if (_systemSettingCacheManager.Snapshot && !string.IsNullOrEmpty(dto.IndustryId))
+        if (_systemSettingCacheManager.Snapshot)
         {
-            query.Where(d => d.OrderSnapshot.IndustryId == dto.IndustryId);
+            query = query.WhereIF(dto.IndustryId.NotNullOrEmpty(),  d => d.OrderSnapshot.IndustryId == dto.IndustryId);
+            query = query.WhereIF(dto.IsSnapshot.HasValue && dto.IsSnapshot.Value == true, d => d.OrderSnapshot.Id != null);
         }
 
-        //var (total, items) = await _orderRepository.Queryable()
-        //    .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.Contact == dto.PhoneNo)
-        //    .WhereIF(!string.IsNullOrEmpty(dto.OrderId), d => d.Id != dto.OrderId)
-        //    .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
-        //    .OrderByDescending(d => d.CreationTime)
-        //    .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
-
         var (total, items) = await query
             .OrderByDescending(d => d.CreationTime)
             .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

+ 3 - 2
src/Hotline.Application/Exam/QueryExtensions/ExamManages/OfflineExamQueryExtensions.cs

@@ -21,8 +21,9 @@ namespace Hotline.Application.Exam.QueryExtensions.ExamManages
             .AndIF(offlineExamAnalysisPagedRequest.StartTime.IsNotNull(), x => x.StartTime >= offlineExamAnalysisPagedRequest.StartTime)
             .AndIF(offlineExamAnalysisPagedRequest.EndTime.IsNotNull(), x => x.StartTime <= offlineExamAnalysisPagedRequest.EndTime)
             .AndIF(offlineExamAnalysisPagedRequest.Keyword.IsNotEmpty(), x => x.ExamName.Contains(offlineExamAnalysisPagedRequest.Keyword))
-            .AndIF(offlineExamAnalysisPagedRequest.MinScore.IsNotNull(), x => x.Score > offlineExamAnalysisPagedRequest.MinScore)
-            .AndIF(offlineExamAnalysisPagedRequest.MaxScore.IsNotNull(), x => x.Score < offlineExamAnalysisPagedRequest.MaxScore)
+            .AndIF(offlineExamAnalysisPagedRequest.MinScore.IsNotNull(), x => x.Score >= offlineExamAnalysisPagedRequest.MinScore)
+            .AndIF(offlineExamAnalysisPagedRequest.MaxScore.IsNotNull(), x => x.Score <= offlineExamAnalysisPagedRequest.MaxScore)
+            .AndIF(offlineExamAnalysisPagedRequest.MaxScore.IsNotNull() && offlineExamAnalysisPagedRequest.MinScore.IsNull(), x => x.Score <= offlineExamAnalysisPagedRequest.MaxScore || x.Score == null)
             .ToExpression();
 
             return expression;

+ 12 - 1
src/Hotline.Application/OrderApp/OrderApplication.cs

@@ -1413,6 +1413,17 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             _capPublisher.Publish(EventNames.HotlineLeaderSMS, new PublishLeaderSMSDto(order.Id, dic.DicDataName, dic.DicDataValue));
         }
 
+        if (dto.Data.DuplicateId.NotNullOrEmpty())
+        {
+            if (order.DuplicateIds != null)
+            {
+                order.DuplicateIds.Add(dto.Data.DuplicateId);
+            }else
+            {
+                order.DuplicateIds = new List<string>() { dto.Data.DuplicateId };
+            }
+        }
+
         _mapper.Map(dto.Data, order);
 
         if (expiredTimeConfig is not null)
@@ -7488,4 +7499,4 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     }
     #endregion
     #endregion
-}
+}

+ 9 - 6
src/Hotline.Application/OrderApp/OrderDelayApp/OrderDelayApplication.cs

@@ -187,14 +187,17 @@ public class OrderDelayApplication : IOrderDelayApplication, IScopeDependency
         //    .ToListAsync(cancellation);
 
         var apptaskItems = new List<AddApptaskItemRequest>();
-        var req = new OrderDelayReviewWithSessionRequest
-        {
-            SessionContext = CreateFakeSessionContext(_sessionContext),//(FakeSessionContext)_sessionContext,
-            IsPass = request.IsPass,
-            NextWorkflow = request.NextWorkflow
-        };
+        var fakeSessionContext = CreateFakeSessionContext(_sessionContext);
+
         foreach (var delay in request.DelayWithStepIds)
         {
+            var req = new OrderDelayReviewWithSessionRequest
+            {
+                SessionContext = fakeSessionContext,//CreateFakeSessionContext(_sessionContext),//(FakeSessionContext)_sessionContext,
+                IsPass = request.IsPass,
+                NextWorkflow = _mapper.Map<NextWorkflowDto>(request.NextWorkflow)
+            };
+
             req.NextWorkflow.WorkflowId = delay.WorkflowId;
             req.NextWorkflow.StepId = delay.StepId;//request.DelayWithStepIds.First(d => d.DelayId == delay.Id).StepId;
             apptaskItems.Add(new AddApptaskItemRequest

+ 1 - 1
src/Hotline.Repository.SqlSugar/Exam/Repositories/ExamManages/OfflineExamAnalysisRepository.cs

@@ -16,7 +16,7 @@ namespace Hotline.Repository.SqlSugar.Exam.Repositories.ExamManages
     {
         public OfflineExamAnalysisRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder, IServiceProvider serviceProvider) : base(uow, dataPermissionFilterBuilder, serviceProvider)
         {
-            Validator = new OfflineExamAnalysisValidator();
+            Validator = new OfflineExamAnalysisValidator(this);
         }
     }
 }

+ 7 - 2
src/Hotline.Repository.SqlSugar/Exam/Validators/ExamManages/OfflineExamAnalysisValidator.cs

@@ -15,9 +15,9 @@ namespace Hotline.Repository.SqlSugar.Exam.Validators.ExamManages
 {
     public class OfflineExamAnalysisValidator : BaseValidator<ExamOfflineExamAnalysis>
     {
-        private readonly IExamManageRepository _examManageRepository;
+        private readonly IOfflineExamAnalysisRepository _offlineExamAnalysisRepository;
 
-        public OfflineExamAnalysisValidator()
+        public OfflineExamAnalysisValidator(IOfflineExamAnalysisRepository offlineExamAnalysisRepository)
         {
             RuleSet(ValidatorTypeConstants.Create, () =>
             {
@@ -32,6 +32,8 @@ namespace Hotline.Repository.SqlSugar.Exam.Validators.ExamManages
 
                 ValidateRuleWithModify();
             });
+
+            this._offlineExamAnalysisRepository = offlineExamAnalysisRepository;
         }
 
         protected override void BaseValidateRule()
@@ -40,10 +42,13 @@ namespace Hotline.Repository.SqlSugar.Exam.Validators.ExamManages
             RuleFor(m => m.UserName).NotEmpty().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamOfflineExamAnalysis.UserName))));
             RuleFor(m => m.DepartmentName).NotEmpty().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamOfflineExamAnalysis.DepartmentName))));
             RuleFor(m => m.ExamName).NotEmpty().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamOfflineExamAnalysis.ExamName))));
+            RuleFor(m => m.StartTime).Must((c,v)=>v!=DateTime.MinValue).WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamOfflineExamAnalysis.StartTime))));
+            RuleFor(m => m.EndTime).Must((c, v) => v != DateTime.MinValue).WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamOfflineExamAnalysis.EndTime))));
             RuleFor(m => m.TotalScore).NotEmpty().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamOfflineExamAnalysis.TotalScore))));
             RuleFor(m => m.Score).NotEmpty().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamOfflineExamAnalysis.Score))));
             RuleFor(m => m.CutoffScore).NotEmpty().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamOfflineExamAnalysis.CutoffScore))));
             RuleFor(m => m.TotalScore).Must((c, v) => c.Score <= v).WithMessage(x => string.Format(ExamErrorMessage.Greater, x.GetType().GetDescription(nameof(ExamOfflineExamAnalysis.Score)),x.GetType().GetDescription(nameof(ExamOfflineExamAnalysis.TotalScore))));
+            RuleFor(m => m.UserName).Must((c,v)=> !_offlineExamAnalysisRepository.Queryable().Any(x=>x.UserName == v && x.ExamName == c.ExamName && x.StartTime == c.StartTime)).WithMessage(x => string.Format(ExamErrorMessage.IsRepeat, x.GetType().GetDescription(nameof(ExamOfflineExamAnalysis.UserName))));
         }
 
         protected override void ValidateRuleWithAdd()

+ 8 - 0
src/Hotline.Share/Dtos/Order/AddOrderComplementDto.cs

@@ -54,3 +54,11 @@ public class AddComplementDto
     public string Opinion {  set; get; }
 }
 
+public class UpdateComplementDto: AddComplementDto
+{
+    /// <summary>
+    /// 补充Id
+    /// </summary>
+    public string Id { get; set; }
+}
+

+ 86 - 7
src/Hotline.Share/Dtos/Order/ComplementOrderDto.cs

@@ -1,12 +1,91 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Hotline.Share.Dtos.Order
+namespace Hotline.Share.Dtos.Order
 {
     public class ComplementOrderDto
     {
+        public string Id { get; set; }
+
+        public string OrderId { get; set; }
+
+        /// <summary>
+        /// 工单
+        /// </summary>
+        public OrderDto Order { get; set; }
+
+        /// <summary>
+        /// 补充意见
+        /// </summary>
+        public string Opinion { get; set; }
+
+        /// <summary>
+        /// 补充人员
+        /// </summary>
+        public string? SupplyName { get; set; }
+
+        /// <summary>
+        /// 补充时间
+        /// </summary>
+        public DateTime? SupplyTime { get; set; }
+
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        public string? No { get; set; }
+    }
+
+    public class ComplementOrderCopDto : ComplementOrderDto
+    {
+        public string? OperationType { get; set; }
+
+        public string? OperationTypeName => OperationType == "0" ? "编辑" : OperationType == "1" ? "删除" : "";
+    }
+
+    public class ComplementOrderCopyDetailDto
+    {
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        public string? No { get; set; }
+
+        /// <summary>
+        /// 工单标题
+        /// </summary>
+        public string? OrderTitle { get; set; }
+
+        /// <summary>
+        ///姓名
+        /// </summary>
+        public string? UserName { get; set; }
+
+        /// <summary>
+        /// 部门
+        /// </summary>
+        public string? OrgName { get; set; }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        public DateTime? SupplyTime { get; set; }
+
+        /// <summary>
+        /// 补充意见
+        /// </summary>
+        public string Opinion { get; set; }
+
+        /// <summary>
+        /// 操作人
+        /// </summary>
+        public string? OperationName { get; set; }
+
+        /// <summary>
+        /// 操作时间
+        /// </summary>
+        public DateTime? OperationTime { get; set; }
+    }
+
+    public class ComplementOrderCopyDetailListDto
+    {
+        public ComplementOrderCopyDetailDto NewData { get; set; }
+
+        public ComplementOrderCopyDetailDto OldData { get; set; }
     }
 }

+ 34 - 0
src/Hotline.Share/Dtos/Order/ComplementOrderRequestDto.cs

@@ -0,0 +1,34 @@
+using Hotline.Share.Requests;
+
+namespace Hotline.Share.Dtos.Order
+{
+    public record ComplementOrderRequestDto : PagedKeywordRequest
+    {
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        public string? No { get; set; }
+
+        /// <summary>
+        /// 标题
+        /// </summary>
+        public string? Title { get; set; }
+
+        /// <summary>
+        /// 当前节点
+        /// </summary>
+        public string? CurrentStepName { get; set; }
+
+        /// <summary>
+        /// 补充人员
+        /// </summary>
+        public string? SupplyName { get; set; }
+    }
+    public record ComplementOrderCopyRequestDto : ComplementOrderRequestDto
+    {
+        /// <summary>
+        /// 操作类型(0:修改,1:删除)
+        /// </summary>
+        public string? OperationType { get; set; }
+    }
+}

+ 6 - 1
src/Hotline.Share/Dtos/Order/OrderStartFlowDto.cs

@@ -42,6 +42,11 @@ namespace Hotline.Share.Dtos.Order
         /// 是否直派
         /// </summary>
         public bool IsDirect{ get; set; }
+
+        /// <summary>
+        /// 重复订单Id
+        /// </summary>
+        public string? DuplicateId { get; set; }
         
         #region 手动填入办理人信息
 
@@ -345,4 +350,4 @@ namespace Hotline.Share.Dtos.Order
 		/// </summary>
 		public bool IsPass { get; set; }
 	}
-}
+}

+ 5 - 0
src/Hotline.Share/Dtos/Order/QueryOrderHistoryDto.cs

@@ -16,5 +16,10 @@ namespace Hotline.Share.Dtos.Order
         /// 随手拍行业类型
         /// </summary>
         public string? IndustryId { get; set; }
+
+        /// <summary>
+        /// 是否随手拍
+        /// </summary>
+        public bool? IsSnapshot { get; set; }
     }
 }

+ 3 - 3
src/Hotline/Exams/ExamManages/ExamOfflineExamAnalysis.cs

@@ -55,15 +55,15 @@ namespace Hotline.Exams.ExamManages
         /// <summary>
         /// 考试开始时间
         /// </summary>
-        [SugarColumn(ColumnDescription = "考试开始时间")]
-        [Description("考试开始时间")]
+        [SugarColumn(ColumnDescription = "开始时间")]
+        [Description("开始时间")]
         public DateTime StartTime { get; set; }
 
         /// <summary>
         /// 考试结束时间
         /// </summary>
         [SugarColumn(ColumnDescription = "考试结束时间")]
-        [Description("考试结束时间")]
+        [Description("结束时间")]
         public DateTime? EndTime { get; set; }
     }
 }

+ 2 - 2
src/Hotline/Exams/ExamManages/OfflineExamAnalysisExcel.cs

@@ -32,13 +32,13 @@ namespace Hotline.Exams.ExamManages
         /// <summary>
         /// 考试开始时间
         /// </summary>
-        [ExcelColumnName("考试开始时间")]
+        [ExcelColumnName("开始时间")]
         public DateTime StartTime { get; set; }
 
         /// <summary>
         /// 考试结束时间
         /// </summary>
-        [ExcelColumnName("考试结束时间")]
+        [ExcelColumnName("结束时间")]
         public DateTime? EndTime { get; set; }
 
         /// <summary>

+ 6 - 0
src/Hotline/File/File.cs

@@ -97,5 +97,11 @@ namespace Hotline.File
 		/// </summary>
 		[SugarColumn(ColumnDescription ="文件时长(秒)")]
 		public long? Duration { get; set; }
+
+		/// <summary>
+		/// 老系统Id
+		/// </summary>
+		[SugarColumn(ColumnDescription = "老系统Id", IsNullable = true)]
+		public string? OldId { get; set; }
 	}
 }

+ 7 - 1
src/Hotline/Orders/Citizen.cs

@@ -121,5 +121,11 @@ namespace Hotline.Orders
 
 		[Navigate(typeof(CitizenRelationSafetyType), nameof(CitizenRelationSafetyType.CitizenId), nameof(CitizenRelationSafetyType.SafetyTypeId))]
         public List<SafetyType> SafetyTypes { get; set; }
-    }
+
+		/// <summary>
+		/// 老系统Id
+		/// </summary>
+		[SugarColumn(ColumnDescription = "老系统Id", IsNullable = true)]
+		public string? OldId { get; set; }
+	}
 }

+ 65 - 0
src/Hotline/Orders/ComplementOrderService.cs

@@ -0,0 +1,65 @@
+using Hotline.Share.Dtos.Order;
+using SqlSugar;
+using XF.Domain.Authentications;
+using XF.Domain.Dependency;
+using XF.Domain.Repository;
+
+namespace Hotline.Orders
+{
+    public class ComplementOrderService : IComplementOrderService, IScopeDependency
+    {
+        private readonly ISessionContext _sessionContext;
+        private readonly IRepository<OrderComplement> _orderComplementRepository;
+        private readonly IRepository<OrderComplementCopy> _orderComplementCopyRepository;
+
+        public ComplementOrderService(ISessionContext sessionContext,
+           IRepository<OrderComplement> orderComplementRepository,
+           IRepository<OrderComplementCopy> orderComplementCopyRepository)
+        {
+            _sessionContext = sessionContext;
+            _orderComplementRepository = orderComplementRepository;
+            _orderComplementCopyRepository = orderComplementCopyRepository;
+        }
+
+        /// <summary>
+        /// 补充列表查询
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<OrderComplement> GetOrderComplementList(ComplementOrderRequestDto dto)
+        {
+            return _orderComplementRepository.Queryable()
+                  .Includes(p => p.Order)
+                  .WhereIF(_sessionContext.OrgIsCenter == false, p => p.CreatorOrgId.StartsWith(_sessionContext.RequiredOrgId))
+                  .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.Order.No == dto.No)
+                  .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Order.Title == dto.Title)
+                  .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepName), p => p.Order.CurrentStepName == dto.CurrentStepName)
+                  .WhereIF(!string.IsNullOrEmpty(dto.SupplyName), p => p.SupplyName == dto.SupplyName)
+                  .WhereIF(dto.StartTime.HasValue, p => p.SupplyTime >= dto.StartTime)
+                  .WhereIF(dto.EndTime.HasValue, p => p.SupplyTime <= dto.EndTime)
+                  .OrderByDescending(p => p.SupplyTime);
+
+        }
+
+        /// <summary>
+        /// 补充操作记录列表查询
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<OrderComplementCopy> GetOrderComplementCopyList(ComplementOrderCopyRequestDto dto)
+        {
+            return _orderComplementCopyRepository.Queryable()
+                  .Includes(p => p.Order)
+                  .WhereIF(_sessionContext.OrgIsCenter == false, p => p.CreatorOrgId.StartsWith(_sessionContext.RequiredOrgId))
+                  .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.Order.No == dto.No)
+                  .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Order.Title == dto.Title)
+                  .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepName), p => p.Order.CurrentStepName == dto.CurrentStepName)
+                  .WhereIF(!string.IsNullOrEmpty(dto.SupplyName), p => p.CreatorName == dto.SupplyName)
+                  .WhereIF(dto.StartTime.HasValue, p => p.CreationTime >= dto.StartTime)
+                  .WhereIF(dto.EndTime.HasValue, p => p.CreationTime <= dto.EndTime)
+                  .WhereIF(!string.IsNullOrEmpty(dto.OperationType), p => p.OperationType == dto.OperationType)
+                  .OrderByDescending(p => p.CreationTime);
+
+        }
+    }
+}

+ 22 - 0
src/Hotline/Orders/IComplementOrderService.cs

@@ -0,0 +1,22 @@
+using Hotline.Share.Dtos.Order;
+using SqlSugar;
+
+namespace Hotline.Orders
+{
+    public interface IComplementOrderService
+    {
+        /// <summary>
+        /// 补充列表查询
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<OrderComplement> GetOrderComplementList(ComplementOrderRequestDto dto);
+
+        /// <summary>
+        /// 补充操作记录列表查询
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<OrderComplementCopy> GetOrderComplementCopyList(ComplementOrderCopyRequestDto dto);
+    }
+}

+ 5 - 0
src/Hotline/Orders/OrderComplement.cs

@@ -28,6 +28,11 @@ public class OrderComplement : CreationEntity
     /// </summary>
     public string? SupplyName { get; set; }
 
+    /// <summary>
+    /// 补充部门
+    /// </summary>
+    public string? SupplyOrg { get; set; }
+
     /// <summary>
     /// 补充时间
     /// </summary>

+ 18 - 0
src/Hotline/Orders/OrderComplementCopy.cs

@@ -0,0 +1,18 @@
+using SqlSugar;
+
+namespace Hotline.Orders
+{
+    public class OrderComplementCopy : OrderComplement
+    {
+        /// <summary>
+        /// 操作类型(0:修改,1:删除)
+        /// </summary>
+        [SugarColumn(ColumnDescription = "操作类型(0:修改,1:删除)")]
+        public string? OperationType { get; set; }
+
+        /// <summary>
+        /// 补充Id
+        /// </summary>
+        public string? ComplementId { get; set; }
+    }
+}

+ 5 - 0
src/Hotline/Orders/OrderDelay.cs

@@ -152,5 +152,10 @@ namespace Hotline.Orders
         [Navigate(NavigateType.OneToMany, nameof(WorkflowStep.ExternalId))]
         public List<WorkflowStep> WorkflowSteps { get; set; }
 
+		/// <summary>
+		/// 老系统Id
+		/// </summary>
+		[SugarColumn(ColumnDescription = "老系统Id", IsNullable = true)]
+		public string? OldId { get; set; }
     }
 }

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

@@ -179,6 +179,12 @@ public class OrderVisit : CreationEntity
     [SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
     public List<SentenceList>? SentenceList { get; set; }
 
+    /// <summary>
+    /// 老系统Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "老系统Id", IsNullable = true)]
+    public string? OldId { get; set; }
+
     public void AiVisitTime()
     {
         LastVisitTime = DateTime.Now;

+ 5 - 0
src/Hotline/Orders/OrderVisitDetail.cs

@@ -111,5 +111,10 @@ namespace Hotline.Orders
         //[SugarColumn(IsIgnore = true)]
         //public bool? IsShowOperate { get; set; }
 
+		/// <summary>
+		/// 老系统Id
+		/// </summary>
+		[SugarColumn(ColumnDescription = "老系统Id", IsNullable = true)]
+		public string? OldId { get; set; }
     }
 }

+ 2 - 2
src/Hotline/Push/FWMessage/Message.cs

@@ -49,7 +49,7 @@ namespace Hotline.Push.FWMessage
         /// <summary>
         /// 短信内容
         /// </summary>
-        [SugarColumn(ColumnDescription = "短信内容", ColumnDataType = "varchar(255)")]
+        [SugarColumn(ColumnDescription = "短信内容", ColumnDataType = "varchar(500)")]
         public string Content { get; set; }
 
         /// <summary>
@@ -115,7 +115,7 @@ namespace Hotline.Push.FWMessage
         /// <summary>
         /// 短信回复内容
         /// </summary>   
-        [SugarColumn(ColumnDescription = "短信回复内容", ColumnDataType = "varchar(200)", IsNullable = true)]
+        [SugarColumn(ColumnDescription = "短信回复内容", ColumnDataType = "varchar(500)", IsNullable = true)]
         public string? SmsReplyContent { get; set; }
 
         /// <summary>

+ 6 - 0
src/Hotline/Snapshot/CommunityInfo.cs

@@ -51,4 +51,10 @@ public class CommunityInfo : CreationSoftDeleteEntity
     {
         return $"{Id}{Name}{FullName}{ParentCode}".GetMD5();
     }
+
+    /// <summary>
+    /// 老系统Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "老系统Id", IsNullable = true)]
+    public string? OldId { get; set; }
 }

+ 8 - 2
src/Hotline/Snapshot/OrderSnapshot.cs

@@ -56,7 +56,7 @@ public class OrderSnapshot : CreationSoftDeleteEntity
     /// <summary>
     /// 作业类型
     /// </summary>
-    [SugarColumn(ColumnDescription ="作业类型")]
+    [SugarColumn(ColumnDescription = "作业类型")]
     public string? JobTypeName { get; set; }
 
     /// <summary>
@@ -344,7 +344,7 @@ public class OrderSnapshot : CreationSoftDeleteEntity
     /// <summary>
     /// 办理状态 1,7:流转 2:办结 3:退回 4:网格员签收 5:消息推送 6: 超时自动退单
     /// </summary>
-    [SugarColumn(ColumnDescription ="网格员办理状态")]
+    [SugarColumn(ColumnDescription = "网格员办理状态")]
     public EGuiderSystemReplyType? ReplyResultType { get; set; }
 
     #endregion
@@ -394,4 +394,10 @@ public class OrderSnapshot : CreationSoftDeleteEntity
     /// </summary>
     [SugarColumn(ColumnDescription = "12345不使用的扩展字段,第三方系统使用")]
     public string? Attach { get; set; }
+
+    /// <summary>
+    /// 老系统Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "老系统Id", IsNullable = true)]
+    public string? OldId { get; set; }
 }

+ 6 - 0
src/Hotline/Snapshot/RedPackAudit.cs

@@ -158,4 +158,10 @@ public class RedPackAudit : CreationSoftDeleteEntity
     [SugarColumn(ColumnDescription = "积分审核意见")]
     public string? PointsOpinion { get; set; }
     #endregion
+
+    /// <summary>
+    /// 老系统Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "老系统Id", IsNullable = true)]
+    public string? OldId { get; set; }
 }

+ 8 - 2
src/Hotline/Snapshot/RedPackRecord.cs

@@ -42,7 +42,7 @@ public class RedPackRecord : CreationSoftDeleteEntity
     /// 红包金额(单位:元)
     /// </summary>
     [SugarColumn(ColumnDescription = "红包金额(单位:元)")]
-    public double Amount {get;set;}
+    public double Amount { get; set; }
 
     /// <summary>
     /// 用户微信OpenId
@@ -78,7 +78,7 @@ public class RedPackRecord : CreationSoftDeleteEntity
     /// 红包发放状态
     /// </summary>
     [SugarColumn(ColumnDescription = "红包发放状态")]
-    public EReadPackSendStatus DistributionState {get;set;}
+    public EReadPackSendStatus DistributionState { get; set; }
 
     /// <summary>
     /// 红包领取状态
@@ -114,4 +114,10 @@ public class RedPackRecord : CreationSoftDeleteEntity
     /// </summary>
     [SugarColumn(ColumnDescription = "开户行")]
     public string? OpenBank { get; set; }
+
+    /// <summary>
+    /// 老系统Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "老系统Id", IsNullable = true)]
+    public string? OldId { get; set; }
 }

+ 7 - 0
src/Hotline/Snapshot/SnapshotPointsRecord.cs

@@ -1,5 +1,6 @@
 using Hotline.Share.Enums.CallCenter;
 using Hotline.Share.Enums.Snapshot;
+using SqlSugar;
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
@@ -42,4 +43,10 @@ public class SnapshotPointsRecord : CreationEntity
     /// 备注
     /// </summary>
     public string? Remark { get; set; }
+
+    /// <summary>
+    /// 老系统Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "老系统Id", IsNullable = true)]
+    public string? OldId { get; set; }
 }

+ 6 - 0
src/Hotline/ThirdAccountDomainServices/ThirdAccount.cs

@@ -69,4 +69,10 @@ public class ThirdAccount : CreationSoftDeleteEntity
     /// </summary>
     [SugarColumn(ColumnDescription = "应用类型", DefaultValue = "1")]
     public EAppType AppType { get; set; }
+
+    /// <summary>
+    /// 老系统Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "老系统Id", IsNullable = true)]
+    public string? OldId { get; set; }
 }

+ 2 - 0
test/Hotline.Tests/Application/OrderSnapshotApplicationTest.cs

@@ -2,6 +2,7 @@
 using Hotline.Application.Snapshot;
 using Hotline.Application.Snapshot.Contracts;
 using Hotline.Caching.Interfaces;
+using Hotline.Caching.Services;
 using Hotline.FlowEngine.WorkflowModules;
 using Hotline.Identity.Accounts;
 using Hotline.Identity.Roles;
@@ -197,6 +198,7 @@ public class OrderSnapshotApplicationTest : TestBase
     public async Task SnapshotWorkflow_Guider_Test()
     {
         SetSettingCache(SettingConstants.OvertimeBack, "4");
+        SetSettingCache(SettingConstants.SnapshotIntervalMinutes, "0.000001");
         var snapshotLabels = _systemDicDataCacheManager.SnapshotOrderLabel;
         var inputLable = snapshotLabels.Where(m => m.DicDataValue == "bss").ToList();
         var industryCase = await _industryCaseRepository.Queryable().Where(m => m.IsEnable == true).FirstAsync();