using DotNetCore.CAP;
using FluentValidation;
using Hotline.Api.Filter;
using Hotline.Application.CallCenter;
using Hotline.Application.ExportExcel;
using Hotline.Application.FlowEngine;
using Hotline.Application.OrderApp;
using Hotline.Application.Quality;
using Hotline.Application.Snapshot.Contracts;
using Hotline.Application.Systems;
using Hotline.Article;
using Hotline.Authentications;
using Hotline.Caching.Interfaces;
using Hotline.CallCenter.Calls;
using Hotline.Configurations;
using Hotline.ContingencyManagement.Notifies;
using Hotline.EventBus;
using Hotline.File;
using Hotline.FlowEngine.Definitions;
using Hotline.FlowEngine.WorkflowModules;
using Hotline.FlowEngine.Workflows;
using Hotline.Import;
using Hotline.Orders;
using Hotline.Orders.Notifications;
using Hotline.OrderTranspond;
using Hotline.Push.FWMessage;
using Hotline.Push.Notifies;
using Hotline.Repository.SqlSugar.Extensions;
using Hotline.Repository.SqlSugar.Orders;
using Hotline.Repository.SqlSugar.Ts;
using Hotline.SeedData;
using Hotline.Settings;
using Hotline.Settings.Hotspots;
using Hotline.Settings.TimeLimitDomain;
using Hotline.Settings.TimeLimits;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.Article;
using Hotline.Share.Dtos.CallCenter;
using Hotline.Share.Dtos.File;
using Hotline.Share.Dtos.FlowEngine;
using Hotline.Share.Dtos.FlowEngine.Workflow;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Dtos.Order.Detail;
using Hotline.Share.Dtos.Order.Handle;
using Hotline.Share.Dtos.Order.Migration;
using Hotline.Share.Dtos.Order.Publish;
using Hotline.Share.Dtos.Org;
using Hotline.Share.Dtos.Settings;
using Hotline.Share.Dtos.Snapshot;
using Hotline.Share.Enums.Article;
using Hotline.Share.Enums.CallCenter;
using Hotline.Share.Enums.FlowEngine;
using Hotline.Share.Enums.Order;
using Hotline.Share.Enums.Push;
using Hotline.Share.Enums.Settings;
using Hotline.Share.Enums.Snapshot;
using Hotline.Share.Mq;
using Hotline.Share.Requests;
using Hotline.Share.Tools;
using Hotline.Snapshot;
using Hotline.Snapshot.IRepository;
using Hotline.Tools;
using Hotline.Users;
using Hotline.Validators.FlowEngine;
using Hotline.YbEnterprise.Sdk;
using Mapster;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using MiniExcelLibs;
using SqlSugar;
using System.Text;
using System.Text.Json;
using System.Threading;
using XF.Domain.Authentications;
using XF.Domain.Cache;
using XF.Domain.Entities;
using XF.Domain.Exceptions;
using XF.Domain.Repository;
using XF.Utility.EnumExtensions;
using OrderDto = Hotline.Share.Dtos.Order.OrderDto;
using UserInfo = Hotline.Share.Dtos.FlowEngine.UserInfo;
using Hotline.Caching.Services;
using Hotline.Early;
using Hotline.Share.Dtos.Order.OrderDelay;
using MathNet.Numerics.Distributions;

namespace Hotline.Api.Controllers;

/// <summary>
/// 工单
/// </summary>
public class OrderController : BaseController
{
    #region 注入

    private readonly ISystemLogRepository _systemLogRepository;
    private readonly IOrderDomainService _orderDomainService;
    private readonly BaseDataApplication _baseDataApplication;
    private readonly IOrderRepository _orderRepository;
    private readonly IWorkflowApplication _workflowApplication;
    private readonly IWorkflowDomainService _workflowDomainService;
    private readonly IRepository<Hotspot> _hotspotTypeRepository;
    private readonly ISystemOrganizeRepository _organizeRepository;
    private readonly IDefinitionDomainService _definitionDomainService;
    private readonly ISystemDicDataCacheManager _sysDicDataCacheManager;
    private readonly ITypedCache<string> _typeCache;
    private readonly ISessionContext _sessionContext;
    private readonly ISessionContextManager _sessionContextManager;
    private readonly IMapper _mapper;
    private readonly IMediator _mediator;
    private readonly IRepository<OrderPublish> _orderPublishRepository;
    private readonly IRepository<OrderVisit> _orderVisitRepository;
    private readonly IRepository<OrderVisitDetail> _orderVisitedDetailRepository;
    private readonly ICapPublisher _capPublisher;
    private readonly IOrderDelayRepository _orderDelayRepository;
    private readonly ITimeLimitDomainService _timeLimitDomainService;
    private readonly ISystemSettingCacheManager _systemSettingCacheManager;
    private readonly IRepository<OrderRedo> _orderRedoRepository;
    private readonly IRepository<OrderSupervise> _orderSuperviseRepository;
    private readonly IRepository<OrderUrge> _orderUrgeRepository;
    private readonly IFileRepository _fileRepository;
    private readonly IOrderScreenRepository _orderScreenRepository;
    private readonly IRepository<OrderPublishHistory> _orderPublishHistoryRepository;
    private readonly IRepositoryTextSearch<OrderTs> _repositoryts;
    private readonly IQualityApplication _qualityApplication;
    private readonly IRepository<Workflow> _workflowRepository;
    private readonly IRepository<WorkflowStep> _workflowStepRepository;
    private readonly ICitizenRepository _citizenRepository;
    private readonly IRepository<CitizenLabelDetail> _labelDetailRepository;
    private readonly IRepository<RepeatableEvent> _repeatableEventRepository;
    private readonly IRepeatableEventDetailRepository _repeatableEventDetailRepository;
    private readonly IRepository<OrderWord> _orderWrodRepository;
    private readonly IRepository<OrderObserve> _orderObserveRepository;
    private readonly IRepository<OrderVisitApply> _orderVisitApplyRepository;
    private readonly IRepository<OrderFinality> _orderFinalityRepository;
    private readonly IRepository<OrderSendBack> _orderSendBackRepository;
    private readonly IRepository<OrderSpecial> _orderSpecialRepository;
    private readonly IRepository<WorkflowTrace> _workflowTraceRepository;
    private readonly IOrderApplication _orderApplication;
    private readonly IPushDomainService _pushDomainService;
    private readonly ILogger<OrderController> _logger;
    private readonly IRepository<OrderSendBackAudit> _orderSendBackAuditRepository;
    private readonly IRepository<User> _userRepository;
    private readonly IExportApplication _exportApplication;
    private readonly IRepository<TranspondCityRawData> _transpondCityRawDataRepository;
    private readonly IRepository<OrderSpecialDetail> _orderSpecialDetailRepository;
    private readonly IOrderSecondaryHandlingApplication _orderSecondaryHandlingApplication;
    private readonly IRepository<OrderCopy> _orderCopyRepository;
    private readonly IRepository<ExternalCitizens> _externalCitizensRepository;
    private readonly IRepository<OrderModifyingRecords> _orderModifyingRecordsRepository;
    private readonly ICallApplication _callApplication;
    private readonly ICallNativeRepository _callNativeRepository;
    private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
    private readonly IOrderSendBackAuditApplication _orderSendBackAuditApplication;
    private readonly Publisher _publisher;
    private readonly IOrderAnalysisApplication _orderAnalysisApplication;
    private readonly ICalcExpireTime _expireTime;
    private readonly IRepository<OrderPushType> _orderPushTypeRepository;
    private readonly IRepository<OrderRevoke> _orderRevokeRepository;
    private readonly IOrderTerminateRepository _orderTerminateRepository;
    private readonly ISystemLogApplication _systemLogApplication;
    private readonly IRepository<OrderCarboncopy> _orderCarboncopy;
    private readonly IOrderSnapshotRepository _orderSnapshotRepository;
    private readonly IOrderSnapshotApplication _orderSnapshotApplication;
    private readonly IIndustryRepository _industryRepository;
    private readonly IRepository<SystemDicData> _sysDicDataRepository;
    private readonly IRepository<SystemOrganize> _systemOrganizeRepository;
    private readonly IRepository<OrderComplement> _orderComplementRepository;
    private readonly ICircularRecordDomainService _circularRecordDomainService;
    private readonly IRepository<Hotline.Special.SpecialNumber> _specialNumberRepository;
    private readonly IRepository<OrderVisitDetailCopy> _orderVisitDetailCopyRepository;
    private readonly IRepository<OrderEarlyWarning> _orderEarlyWarningRepository;
    private readonly IRepository<EarlyWarningSetting> _earlyWarningSettingRepository;
    private readonly IRepository<OrderTsDetails> _orderTsDetailsRepository;
    private readonly IRedPackAuditRepository _redPackAuditRepository;
    private readonly IRepository<OrderPublishTemp> _orderPublishTempRepository;

    public OrderController(
        IOrderDomainService orderDomainService,
        IOrderRepository orderRepository,
        IWorkflowApplication workflowApplication,
        IWorkflowDomainService workflowDomainService,
        IRepository<Hotspot> hotspotTypeRepository,
        ISystemOrganizeRepository organizeRepository,
        IDefinitionDomainService definitionDomainService,
        ISystemDicDataCacheManager sysDicDataCacheManager,
        ISessionContext sessionContext,
        ISessionContextManager sessionContextManager,
        IMapper mapper,
        IMediator mediator,
        IRepository<OrderPublish> orderPublishRepository,
        IRepository<OrderVisit> orderVisitRepository,
        IRepository<OrderVisitDetail> orderVisitedDetailRepository,
        ICapPublisher capPublisher,
        IOrderDelayRepository orderDelayRepository,
        //ITimeLimitDomainService timeLimitDomainService,
        ISystemSettingCacheManager systemSettingCacheManager,
        IRepository<OrderRedo> orderRedoRepository,
        IRepository<OrderSupervise> orderSuperviseRepository,
        IRepository<OrderUrge> orderUrgeRepository,
        IFileRepository fileRepository,
        IOrderScreenRepository orderScreenRepository,
        IRepository<OrderPublishHistory> orderPublishHistoryRepository,
        IRepositoryTextSearch<OrderTs> repositoryts,
        IQualityApplication qualityApplication,
        IRepository<Workflow> workflowRepository,
        IRepository<WorkflowStep> workflowStepRepository,
        ICitizenRepository citizenRepository,
        IRepository<CitizenLabelDetail> labelDetailRepository,
        IRepository<RepeatableEvent> repeatableEventRepository,
        IRepeatableEventDetailRepository repeatableEventDetailRepository,
        IRepository<OrderWord> orderWrodRepository,
        IRepository<OrderObserve> orderObserveRepository,
        IRepository<OrderFinality> orderFinalityRepository,
        IRepository<OrderVisitApply> orderVisitApplyRepository,
        IRepository<OrderSendBack> orderSendBackRepository,
        IRepository<OrderSpecial> orderSpecialRepository,
        IRepository<WorkflowTrace> workflowTraceRepository,
        IOrderApplication orderApplication,
        IPushDomainService pushDomainService,
        ILogger<OrderController> logger,
        ITypedCache<YbEnterpriseToken> cacheResponse,
        IRepository<OrderSendBackAudit> orderSendBackAuditRepository,
        IRepository<User> userRepository,
        IExportApplication exportApplication,
        IRepository<TranspondCityRawData> transpondCityRawDataRepository,
        IRepository<OrderSpecialDetail> orderSpecialDetailRepository,
        IOrderSecondaryHandlingApplication orderSecondaryHandlingApplication,
        IRepository<OrderCopy> orderCopyRepository,
        IRepository<ExternalCitizens> externalCitizensRepository,
        ICallApplication callApplication,
        IOptionsSnapshot<AppConfiguration> appOptions,
        IRepository<OrderModifyingRecords> orderModifyingRecordsRepository,
        IOrderSendBackAuditApplication orderSendBackAuditApplication,
        Publisher publisher,
        IOrderAnalysisApplication orderAnalysisApplication,
        ICalcExpireTime expireTime,
        IRepository<OrderPushType> orderPushTypeRepository,
        ICallNativeRepository callNativeRepository,
        IRepository<OrderRevoke> orderRevokeRepository,
        BaseDataApplication baseDataApplication,
        IOrderTerminateRepository orderTerminateRepository,
        IRepository<OrderCarboncopy> orderCarboncopy,
        ITypedCache<string> typeCache,
        ISystemLogApplication systemLogApplication,
        IOrderSnapshotRepository orderSnapshotRepository,
        IIndustryRepository industryRepository,
        IOrderSnapshotApplication orderSnapshotApplication,
        IRepository<SystemDicData> sysDicDataRepository,
        IRepository<SystemOrganize> systemOrganizeRepository,
        IRepository<OrderComplement> orderComplementRepository,
        ICircularRecordDomainService circularRecordDomainService,
        IRedPackAuditRepository redPackAuditRepository,
        IRepository<Hotline.Special.SpecialNumber> specialNumberRepository,
        IRepository<OrderVisitDetailCopy> orderVisitDetailCopyRepository,
        IRepository<OrderEarlyWarning> orderEarlyWarningRepository,
        IRepository<EarlyWarningSetting> earlyWarningSettingRepository,
        IRepository<OrderTsDetails> orderTsDetailsRepository,
        ISystemLogRepository systemLogRepository,
        IRepository<OrderPublishTemp> orderPublishTempRepository)
    {
        _orderDomainService = orderDomainService;
        _orderRepository = orderRepository;
        _workflowApplication = workflowApplication;
        _workflowDomainService = workflowDomainService;
        _hotspotTypeRepository = hotspotTypeRepository;
        _organizeRepository = organizeRepository;
        _definitionDomainService = definitionDomainService;
        _sysDicDataCacheManager = sysDicDataCacheManager;
        _sessionContext = sessionContext;
        _sessionContextManager = sessionContextManager;
        _mapper = mapper;
        _mediator = mediator;
        _orderPublishRepository = orderPublishRepository;
        _orderVisitRepository = orderVisitRepository;
        _orderVisitedDetailRepository = orderVisitedDetailRepository;
        _capPublisher = capPublisher;
        _orderDelayRepository = orderDelayRepository;
        //_timeLimitDomainService = timeLimitDomainService;
        _systemSettingCacheManager = systemSettingCacheManager;
        _orderRedoRepository = orderRedoRepository;
        _orderSuperviseRepository = orderSuperviseRepository;
        _orderUrgeRepository = orderUrgeRepository;
        _fileRepository = fileRepository;
        _orderScreenRepository = orderScreenRepository;
        _orderPublishHistoryRepository = orderPublishHistoryRepository;
        _repositoryts = repositoryts;
        _qualityApplication = qualityApplication;
        _workflowRepository = workflowRepository;
        _workflowStepRepository = workflowStepRepository;
        _citizenRepository = citizenRepository;
        _labelDetailRepository = labelDetailRepository;
        _repeatableEventRepository = repeatableEventRepository;
        _repeatableEventDetailRepository = repeatableEventDetailRepository;
        _orderWrodRepository = orderWrodRepository;
        _orderObserveRepository = orderObserveRepository;
        _orderFinalityRepository = orderFinalityRepository;
        _orderVisitApplyRepository = orderVisitApplyRepository;
        _orderSendBackRepository = orderSendBackRepository;
        _orderSpecialRepository = orderSpecialRepository;
        _workflowTraceRepository = workflowTraceRepository;
        _logger = logger;
        _orderApplication = orderApplication;
        _pushDomainService = pushDomainService;
        _orderSendBackAuditRepository = orderSendBackAuditRepository;
        _userRepository = userRepository;
        _exportApplication = exportApplication;
        _transpondCityRawDataRepository = transpondCityRawDataRepository;
        _orderSpecialDetailRepository = orderSpecialDetailRepository;
        _orderSecondaryHandlingApplication = orderSecondaryHandlingApplication;
        _orderCopyRepository = orderCopyRepository;
        _externalCitizensRepository = externalCitizensRepository;
        _orderModifyingRecordsRepository = orderModifyingRecordsRepository;
        _callApplication = callApplication;
        _appOptions = appOptions;
        _orderSendBackAuditApplication = orderSendBackAuditApplication;
        _publisher = publisher;
        _orderAnalysisApplication = orderAnalysisApplication;
        _expireTime = expireTime;
        _orderPushTypeRepository = orderPushTypeRepository;
        _callNativeRepository = callNativeRepository;
        _baseDataApplication = baseDataApplication;
        _orderTerminateRepository = orderTerminateRepository;
        _orderCarboncopy = orderCarboncopy;
        _orderRevokeRepository = orderRevokeRepository;
        _typeCache = typeCache;
        _baseDataApplication = baseDataApplication;
        _systemLogApplication = systemLogApplication;
        _orderSnapshotRepository = orderSnapshotRepository;
        _industryRepository = industryRepository;
        _orderSnapshotApplication = orderSnapshotApplication;
        _sysDicDataRepository = sysDicDataRepository;
        _systemOrganizeRepository = systemOrganizeRepository;
        _orderComplementRepository = orderComplementRepository;
        _circularRecordDomainService = circularRecordDomainService;
        _orderEarlyWarningRepository = orderEarlyWarningRepository;
        _earlyWarningSettingRepository = earlyWarningSettingRepository;
        _orderTsDetailsRepository = orderTsDetailsRepository;
        _redPackAuditRepository = redPackAuditRepository;
        _specialNumberRepository = specialNumberRepository;
        _orderVisitDetailCopyRepository = orderVisitDetailCopyRepository;
        _systemLogRepository = systemLogRepository;
        _orderPublishTempRepository = orderPublishTempRepository;
    }

    #endregion

    #region 工单发布

    /// <summary>
    /// 发布待办(集合)
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("publish/items")]
    public async Task<IReadOnlyList<PublishDto>> GetPublishOrderListAsync([FromQuery] QueryOrderPublishDto dto)
    {
        var orders = await _orderApplication.GetPublishOrderList(dto)
            .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted);

        return _mapper.Map<IReadOnlyList<PublishDto>>(orders);

        //return (await query.ToFixedListAsync(dto.QueryIndex, 200, HttpContext.RequestAborted))
        //    .Adapt<List<PublishDto>>();
    }

    /// <summary>
    /// 发布待办
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("publish/count")]
    public async Task<int> GetPublishOrderCount([FromQuery] QueryOrderPublishDto dto)
    {
        return await _orderApplication.GetPublishOrderList(dto).CountAsync(HttpContext.RequestAborted);
    }

    /// <summary>
    /// 发布待办数据--导出
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("publishorder/export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> ExportPublishOrders([FromBody] ExportExcelDto<QueryOrderPublishDto> dto)
    {
        var query = _orderApplication.GetPublishOrderList(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<PublishDto>>(orders);

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<PublishDto>(dto.ColumnInfos);

        var dtos = orderDtos
            .Select(stu => _mapper.Map(stu, typeof(PublishDto), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);

        return ExcelStreamResult(stream, "发布待办数据");
    }

    /// <summary>
    /// 查询（工单发布）
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("publish")]
    [Obsolete("前端不再调用,择机删除")]
    public async Task<PagedDto<PublishDto>> PublishOrderList([FromQuery] QueryOrderPublishDto dto)
    {
        var (total, items) = await _orderRepository.Queryable()
            .Includes(d => d.OrderTags)
            //.Includes(d => d.OrderPublish)
            .Where(x => x.Status == EOrderStatus.Filed)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword!))
            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No))
            .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title))
            //.WhereIF(dto.PubState == EPubState.Pub, d => d.Status >= EOrderStatus.Published)
            //.WhereIF(dto.PubState == EPubState.NoPub, d => d.Status == EOrderStatus.Filed)
            .WhereIF(!string.IsNullOrEmpty(dto.Channel), d => d.SourceChannelCode == dto.Channel)
            //.WhereIF(!string.IsNullOrEmpty(dto.OrderTag), d => d.OrderTagCode == dto.OrderTag!) //工单标签
            .WhereIF(!string.IsNullOrEmpty(dto.OrderTag), d => d.OrderTags.Any(ot => ot.DicDataValue == dto.OrderTag)) //工单标签
            .WhereIF(!string.IsNullOrEmpty(dto.CenterToOrgHandlerName), d => d.CenterToOrgHandlerName == dto.CenterToOrgHandlerName!) //派单人
            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName == dto.NameOrNo! || d.AcceptorStaffNo == dto.NameOrNo!) //受理人/坐席
            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), d => d.ActualHandleOrgName.Contains(dto.ActualHandleOrgName)) //接办部门（综合查询模糊）
            .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.AcceptTypeCode == dto.AcceptType) //受理类型
            .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.HotspotSpliceName != null && d.HotspotSpliceName.Contains(dto.Hotspot))
            .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.FromPhone == dto.FromPhone) //来电号码
                                                                                              //.WhereIF(!string.IsNullOrEmpty(dto.PubMan),
                                                                                              //    d => d.AcceptorName.Contains(dto.PubMan!) || d.AcceptorStaffNo.Contains(dto.PubMan!))
                                                                                              //.WhereIF(dto.PubRange == EPublicState.Pub, d => d.OrderPublish.PublishState)
                                                                                              //.WhereIF(dto.PubRange == EPublicState.NoPub, d => !d.OrderPublish.PublishState)
            .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true, d => d.Source == ESource.ProvinceStraight)
            .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == false, d => d.Source != ESource.ProvinceStraight)
            .WhereIF(dto.FiledType != null && dto.FiledType == FiledType.CenterFiled, d => d.ProcessType == EProcessType.Zhiban)
            .WhereIF(dto.FiledType != null && dto.FiledType == FiledType.OrgFiled, d => d.ProcessType == EProcessType.Jiaoban)
            .WhereIF(dto.IsCountersign != null && dto.IsCountersign == true, d => d.CounterSignType != null)
            .WhereIF(dto.IsCountersign != null && dto.IsCountersign == false, d => d.CounterSignType == null)
            .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptType))
            .WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.HotspotId))
            //.WhereIF(dto.Resolve.HasValue, d => d.OrderPublish.Resolve == dto.Resolve)
            .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart)
            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd)
            .WhereIF(dto.FiledTimeStart.HasValue, d => d.FiledTime >= dto.FiledTimeStart)
            .WhereIF(dto.FiledTimeEnd.HasValue, d => d.FiledTime <= dto.FiledTimeEnd)
            .WhereIF(dto.QuerySelf.HasValue && dto.QuerySelf.Value, d => d.WaitForPublisherId == _sessionContext.RequiredUserId)
            .WhereIF(dto.IsOverTime == true,
                d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) ||
                     (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //是 超期
            .WhereIF(dto.IsOverTime == false,
                d => (d.ExpiredTime > DateTime.Now && d.Status < EOrderStatus.Filed) ||
                     (d.ExpiredTime > d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //否 超期
            .OrderByDescending(d => d.FiledTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<PublishDto>(total, _mapper.Map<IReadOnlyList<PublishDto>>(items));
    }

    /// <summary>
    /// 批量发布工单
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("batch-publish")]
    public async Task BatchPublishOrder([FromBody] BatchPublishOrderDto dto)
    {
        //任务 127  市州通用-会签件需支持批量发布
        //会签件也需支持批量发布；若会签件要批量发布，就默认不公开，只对实际办理部门进行回访即可
        var hasHuiQian = await _orderRepository.Queryable().AnyAsync(x => dto.Ids.Contains(x.Id) && x.CounterSignType != null);
        //var hasHuiQian = await _orderRepository.Queryable().AnyAsync(x => dto.Ids.Contains(x.Id));
        if (hasHuiQian)
            throw UserFriendlyException.SameMessage("选择的工单中含有会签工单, 不能批量发布. 请排除会签工单.");

        var hasProvince = false;
        //if (hasProvince)
        //    throw UserFriendlyException.SameMessage("选择的工单中含有省工单, 不能批量发布. 请排除省工单.");
        if (_appOptions.Value.IsYiBin || _appOptions.Value.IsZiGong)
        {
            hasProvince = await _orderRepository.Queryable().AnyAsync(x => dto.Ids.Contains(x.Id) && x.IsProvince);
        }
        else
        {
            hasProvince = await _orderRepository.Queryable().AnyAsync(x => dto.Ids.Contains(x.Id) && x.Source == ESource.ProvinceStraight);
        }

        if (hasProvince)
            throw UserFriendlyException.SameMessage("选择的工单中含有省工单, 不能批量发布. 请排除省工单.");

        var orderList = await _orderRepository.Queryable().Where(x => dto.Ids.Contains(x.Id)).ToListAsync();
        foreach (var order in orderList)
        {
            if (order != null && order.Status == EOrderStatus.Filed)
            {
                try
                {
                    await _orderDomainService.OrderPublishAsync(order, HttpContext.RequestAborted);
                }
                catch
                {
                }
            }
        }
    }

    /// <summary>
    /// 发布工单
    /// </summary>
    /// <returns></returns>
    [HttpPost("publish")]
    [LogFilter("发布工单")]
    public async Task PublishOrder([FromBody] PublishOrderDto dto)
    {
        //验证订单
        var order = await _orderRepository.GetAsync(dto.Id, HttpContext.RequestAborted)
                    ?? throw UserFriendlyException.SameMessage("未找到工单，无法发布");

        if (order.Status != EOrderStatus.Filed)
            throw UserFriendlyException.SameMessage("当前状态无法发布");


        if (order.SourceChannelCode == "SZMHD" && order.IsProvince && dto.PublishState && dto.IsOpenReview is null)
        {
            throw UserFriendlyException.SameMessage("公开信件必须选择开展保密审查");
        }


        var enabled = _systemSettingCacheManager.CancelPublishOrderEnabled;
        if (enabled)
        {
            // 获取上一次被取消发布的发布信息
            var publishedDeleted = await _orderPublishRepository.Queryable().Where(m => m.OrderId == dto.Id && m.IsDeleted == true)
                .OrderByDescending(m => m.CreationTime).FirstAsync(HttpContext.RequestAborted);
            if (publishedDeleted != null && _sessionContext.RequiredUserId != publishedDeleted.CreatorId)
            {
                throw UserFriendlyException.SameMessage($"该工单被取消发布过, 之前的发布人是 [{publishedDeleted.CreatorName}], 您不能发布;");
            }
        }

        //新增发布工单
        var orderPublish = _mapper.Map<OrderPublish>(dto);
        orderPublish.OrderId = order.Id;
        orderPublish.No = order.No;

        string id = await _orderPublishRepository.AddAsync(orderPublish);
        order.Publish(orderPublish.PublishState);
        await _orderRepository.UpdateAsync(order);

        //推省上
        var publishPublishOrder = _mapper.Map<PublishPublishOrderDto>(orderPublish);
        publishPublishOrder.Order = _mapper.Map<OrderDto>(order);
        //查询实际办理附件
        if (!string.IsNullOrEmpty(order.ActualHandleStepId))
        {
            var actualHandleStep = await _workflowStepRepository.GetAsync(order.ActualHandleStepId, HttpContext.RequestAborted);
            publishPublishOrder.FileJsons = actualHandleStep?.FileJson;
        }

        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderPublishOrder, publishPublishOrder);

        //推应急管理局
        //是否开启
        var isOpenContingencyManagement = _systemSettingCacheManager.GetSetting(SettingConstants.IsOpenContingencyManagement)?.SettingValue[0];
        if (isOpenContingencyManagement == "true")
            await _publisher.PublishAsync(new ContingencyManagementNotify(order, dto.ArrangeTitle, dto.ArrangeContent, dto.ArrangeOpinion),
                PublishStrategy.ParallelWhenAll, HttpContext.RequestAborted);

        // 取消发布功能开关
        var cancelPublishOrderEnabled = _systemSettingCacheManager.CancelPublishOrderEnabled;
        // 取消发布的工单
        var publishOrder = await _orderPublishRepository.Queryable(includeDeleted: true)
            .Where(m => m.OrderId == order.Id && m.IsDeleted == true)
            .FirstAsync(HttpContext.RequestAborted);

        // 若取消发布的工单，已经被回访过了，没有经过重新办理，再次发布后，自动跳过回访环节，展示取消发布前的回访结果
        if (publishOrder != null && cancelPublishOrderEnabled == true)
        {
            var history = new OrderPublishHistory
            {
                ArrangeTitleBefor = publishOrder.ArrangeTitle,
                ArrangeTitleAfter = dto.ArrangeTitle,
                ArrangeContentBefor = publishOrder.ArrangeContent,
                ArrangeContentAfter = dto.ArrangeContent,
                ArrangeOpinionBefor = publishOrder.ArrangeOpinion,
                ArrangeOpinionAfter = dto.ArrangeOpinion,
                PublishStateBefor = publishOrder.PublishState,
                PublishStateAfter = dto.PublishState,
                No = publishOrder.No,
                OrderId = publishOrder.OrderId,
                OrderPublishId = publishOrder.Id
            };
            await _orderPublishHistoryRepository.AddAsync(history, HttpContext.RequestAborted);
            await _orderPublishRepository.RemoveAsync(publishOrder, false, HttpContext.RequestAborted);
            return;
        }

        var orderVisit = new OrderVisit();
        orderVisit.No = order.No;
        orderVisit.OrderId = order.Id;
        orderVisit.VisitState = EVisitState.WaitForVisit;
        orderVisit.PublishTime = DateTime.Now;
        orderVisit.IsCanHandle = true;
        if (!order.IsProvince)
        {
            orderVisit.EmployeeId = _sessionContext.RequiredUserId;
        }

        var isReturn = false;
        if (_appOptions.Value.IsZiGong)
        {
            orderVisit.EmployeeId = string.Empty;
            //自贡任务  348 语音评价不满意的工单需回访
            var callNative = await _callApplication.GetReplyVoiceOrDefaultByOrderIdAsync(orderVisit.OrderId);
            if (callNative == EVoiceEvaluate.NoSatisfied || callNative == EVoiceEvaluate.VeryNoSatisfied)
                isReturn = true;
        }

        if (isReturn == false)
        {
            //order.FocusOnEvents!="7" 2025年4月29日 10:55:38 刘欣 临时新增，如果是旅游件不自动回访
            if (order is { FileOrgIsCenter: true, CounterSignType: null } && !order.IsProvince && order.FocusOnEvents != "7")
            {
                orderVisit.VisitState = EVisitState.Visited;
                orderVisit.VisitTime = DateTime.Now;
                orderVisit.VisitType = EVisitType.OtherVisit;
                orderVisit.NowEvaluate = new Kv() { Key = "4", Value = "满意" };

                if (_appOptions.Value.IsZiGong)
                {
                    // 根据禅道 自贡需求 Id_361, 第一条, 3小条需求;
                    // 直办件归档后自动回访量需统计在“胡玲”的默认回访量中;
                    orderVisit.EmployeeId = _systemSettingCacheManager.DefaultVisitEmployeeId;
                }
            }

            if (order.CounterSignType != ECounterSignType.Center && order.FocusOnEvents != "7")
            {
                orderVisit.IsCanAiVisit = true;
            }
        }

        string visitId = await _orderVisitRepository.AddAsync(orderVisit);
        await _orderSnapshotApplication.UpdateLabelAsync(order.Id, dto.SnapshotLabels);


        //新增回访信息
        var visitedDetail = new List<OrderVisitDetail>();

        var seatDetail = new OrderVisitDetail();
        seatDetail.VisitId = visitId;
        seatDetail.VisitTarget = EVisitTarget.Seat;
        foreach (var item in dto.IdNames)
        {
            var orgDetail = new OrderVisitDetail();
            orgDetail.VisitId = visitId;
            orgDetail.VisitOrgCode = item.Key;
            orgDetail.VisitOrgName = item.Value;
            orgDetail.VisitTarget = EVisitTarget.Org;
            if (isReturn == false)
            {
                if (order is { CounterSignType: null, FileOrgIsCenter: true })
                {
                    var satisfy = new Kv() { Key = "4", Value = "满意" };
                    orgDetail.OrgProcessingResults = satisfy;
                    //orgDetail.OrgHandledAttitude = satisfy;
                }
            }

            visitedDetail.Add(orgDetail);
        }

        if (isReturn == false)
        {
            //order.FocusOnEvents!="7" 2025年4月29日 10:55:38 刘欣 临时新增，如果是旅游件不自动回访
            if (order is { FileOrgIsCenter: true, CounterSignType: null, IsProvince: false } && order.FocusOnEvents != "7")
            {
                seatDetail.VoiceEvaluate = EVoiceEvaluate.Satisfied;
                seatDetail.SeatEvaluate = ESeatEvaluate.Satisfied;
                order.Visited("4", "满意");
                order.Status = EOrderStatus.Visited;
                await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
            }
        }

        visitedDetail.Add(seatDetail);
        await _orderVisitedDetailRepository.AddRangeAsync(visitedDetail, HttpContext.RequestAborted);

        //handle publish trace
        var acceptor = new UserInfo(orderPublish.CreatorId, orderPublish.CreatorName,
            orderPublish.CreatorOrgId, orderPublish.CreatorOrgName);
        var handler = new UserInfo(orderPublish.CreatorId, orderPublish.CreatorName,
            orderPublish.CreatorOrgId, orderPublish.CreatorOrgName);
        //上面回访人取值当前操作人，所以暂时可取值SessionContext,如需求有变需取值ordervisit中指定的回访人
        var visitAcceptor = string.IsNullOrEmpty(orderVisit.EmployeeId)
            ? new UserInfo()
            : new UserInfo(_sessionContext.UserId, _sessionContext.UserName, _sessionContext.OrgId,
                _sessionContext.OrgName, _sessionContext.OrgIsCenter);
        await _workflowDomainService.HandlePublishTraceAsync(order.WorkflowId, orderPublish.Id, acceptor, handler,
            orderPublish.CreationTime, visitAcceptor, orderVisit.Id, HttpContext.RequestAborted);

        //需求251  某些工单需自动发送短信
        //任何类型的省工单都不需要发送短信

        var isOpenSendEndSms = _systemSettingCacheManager.GetSetting(SettingConstants.IsOpenSendEndSms)?.SettingValue[0];
        if (isOpenSendEndSms == "true")
        {
            try
            {
                if (_appOptions.Value.IsZiGong == false)
                {
                    if (order.Source != ESource.ProvinceStraight && order.FileOrgIsCenter.Value == false)
                    {
                        var isOpenSendVisitSms = _systemSettingCacheManager.GetSetting(SettingConstants.IsOpenSendVisitSms)?.SettingValue[0];

                        var code = "";
                        //受理类型为“投诉、举报”
                        if ((order.AcceptTypeCode == "30" || order.AcceptTypeCode == "35") && orderVisit.VisitState != EVisitState.Visited &&
                            isOpenSendVisitSms == "true")
                        {
                            code = "1017";
                            orderVisit.VisitState = EVisitState.SMSVisiting;
                            await _orderVisitRepository.UpdateAsync(orderVisit);
                        }
                        else
                            code = "1018";

                        var messageDto = new Share.Dtos.Push.MessageDto
                        {
                            PushBusiness = EPushBusiness.SearchSms,
                            ExternalId = visitId,
                            OrderId = order.Id,
                            PushPlatform = EPushPlatform.Sms,
                            Remark = order.Title,
                            Name = order.FromName,
                            TemplateCode = code,
                            Params = new List<string>() { order.No, order.Password },
                            TelNumber = order.Contact,
                        };
                        await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);

                        // 发送短信后推送一个 48小时的延迟消息队列. 当消息队列收到消息时, 判断用户是否回复了, 如果未回复短信就 默认满意
                        var delaySecond = _systemSettingCacheManager.DefaultVisitSmsDelaySecond;
                        await _capPublisher.PublishDelayAsync(
                            TimeSpan.FromSeconds(delaySecond),
                            EventNames.UpdateVisitDelaySms,
                            messageDto,
                            cancellationToken: HttpContext.RequestAborted);
                    }
                }
            }
            catch (Exception)
            {
            }
        }

        if (orderVisit.VisitState == EVisitState.Visited && !order.IsProvince)
        {
            //推省上
            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisited,
                new PublishVisitDto()
                {
                    Order = _mapper.Map<OrderDto>(order),
                    No = orderVisit.No,
                    VisitType = orderVisit.VisitType,
                    VisitName = orderVisit.CreatorName,
                    VisitTime = orderVisit.VisitTime,
                    VisitRemark = orderVisit.NowEvaluate?.Value,
                    AreaCode = order.AreaCode!,
                    SubjectResultSatifyCode = orderVisit.NowEvaluate?.Key,
                    FirstSatisfactionCode = orderVisit.NowEvaluate?.Key,
                    ClientGuid = ""
                }, cancellationToken: HttpContext.RequestAborted);
        }

        //推送回访信息
        //推门户
        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisitedWeb, new PublishVisitAllDto()
        {
            Id = orderVisit.Id,
            Order = _mapper.Map<OrderDto>(order),
            OrderVisitDetails = _mapper.Map<List<VisitDetailDto>>(orderVisit.OrderVisitDetails),
            VisitName = _sessionContext.UserName,
            VisitTime = orderVisit.VisitTime,
            VisitType = orderVisit.VisitType,
            VisitState = orderVisit.VisitState,
            PublishTime = orderVisit.PublishTime,
        }, cancellationToken: HttpContext.RequestAborted);
    }

    /// <summary>
    /// 发布页面基础信息
    /// </summary>
    /// <returns></returns>
    [HttpGet("publish-order-pagebase/{id}")]
    public async Task<PublishOrderPageBaseDto> PublishOrderPageBase(string id)
    {
        var order = await _orderRepository.Queryable()
            .Includes(d => d.OrderExtension)
            .FirstAsync(d => d.Id == id);

        if (order is null)
            throw UserFriendlyException.SameMessage("未知工单，无法发布");

        var res = new PublishOrderPageBaseDto()
        {
            SourceChannel = order.SourceChannel,
            OrderTitle = order.Title,
            Content = order.Content,
            ActualOpinion = order.FileOpinion,
            IsPublic = order.IsPublic,
            IsProvincePublic = (order.SourceChannelCode == "SZMHD" && order.IsProvince == true) ? true : false,
            NetizenEvaluateType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.NetizenEvaluateType)
                .Select(x => new Kv { Key = x.DicDataValue, Value = x.DicDataName }).ToList()
        };
        var (idName, idNames) = await _workflowDomainService.GetHandleOrgsAsync(order.WorkflowId, HttpContext.RequestAborted);
        res.ActualHandleOrgName = new Kv() { Key = order.ActualHandleOrgCode, Value = order.ActualHandleOrgName };
        res.idNames = order.CounterSignType == null
            ? null
            : idNames.Where(d => d.Key != idName.Key).ToList();

        if (_systemSettingCacheManager.Snapshot)
        {
            res.IsSnapshot = await _orderSnapshotRepository.AnyAsync(m => m.Id == order.Id);
            res.SnapshotLabel = _sysDicDataCacheManager.SnapshotOrderLabel;
        }

        return res;
    }

    /// <summary>
    /// 临时待发布(集合)
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("publish/temp/items")]
    public async Task<IReadOnlyList<PublishDto>> GetPublishTempOrderListAsync([FromQuery] QueryOrderPublishDto dto)
    {
        var orders = await _orderApplication.GetPublishTempOrderList(dto)
            .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted);
        return _mapper.Map<IReadOnlyList<PublishDto>>(orders);
    }

    /// <summary>
    /// 临时待发布
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("publish/temp/count")]
    public async Task<int> GetPublishTempOrderCount([FromQuery] QueryOrderPublishDto dto)
    {
        return await _orderApplication.GetPublishTempOrderList(dto).CountAsync(HttpContext.RequestAborted);
    }

    /// <summary>
    /// 临时待发布--导出
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("publishorder/temp/export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> ExportPublishTempOrders([FromBody] ExportExcelDto<QueryOrderPublishDto> dto)
    {
        var query = _orderApplication.GetPublishTempOrderList(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<PublishDto>>(orders);

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<PublishDto>(dto.ColumnInfos);

        var dtos = orderDtos
            .Select(stu => _mapper.Map(stu, typeof(PublishDto), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);

        return ExcelStreamResult(stream, "临时发布待办数据");
    }

    /// <summary>
    /// 临时待发布（发布）
    /// </summary>
    /// <returns></returns>
    [HttpPost("publish/temp")]
    [LogFilter("临时发布")]
    public async Task PublishTempOrder([FromBody] PublishOrderDto dto)
    {
        //验证订单
        var order = await _orderRepository.GetAsync(dto.Id, HttpContext.RequestAborted)
                    ?? throw UserFriendlyException.SameMessage("未找到工单，无法发布");

        if (order.Status != EOrderStatus.Filed)
            throw UserFriendlyException.SameMessage("当前状态无法发布");

        var enabled = _systemSettingCacheManager.CancelPublishOrderEnabled;
        if (enabled)
        {
            // 获取上一次被取消发布的发布信息
            var publishedDeleted = await _orderPublishRepository.Queryable().Where(m => m.OrderId == dto.Id && m.IsDeleted == true)
                .OrderByDescending(m => m.CreationTime).FirstAsync(HttpContext.RequestAborted);
            if (publishedDeleted != null && _sessionContext.RequiredUserId != publishedDeleted.CreatorId)
            {
                throw UserFriendlyException.SameMessage($"该工单被取消发布过, 之前的发布人是 [{publishedDeleted.CreatorName}], 您不能发布;");
            }
        }

        //新增发布工单
        var orderPublish = _mapper.Map<OrderPublishTemp>(dto);
        orderPublish.OrderId = order.Id;
        orderPublish.No = order.No;

        // 新增临时待发布
        string id = await _orderPublishTempRepository.AddAsync(orderPublish);
    }

    /// <summary>
    /// 已发布列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("published")]
    [Obsolete("前端不再调用,择机删除")]
    public async Task<PagedDto<PublishedDto>> PublishedOrderList([FromQuery] PublishedPagedRequest dto)
    {
        var (total, items) = await _orderPublishRepository.Queryable()
            .Includes(x => x.Order)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.StartsWith(dto.Keyword!))
            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.Order.No.Contains(dto.No!))
            .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Order.Title.Contains(dto.Title!))
            .WhereIF(dto.CreationTimeStart.HasValue, d => d.Order.CreationTime >= dto.CreationTimeStart)
            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.Order.CreationTime <= dto.CreationTimeEnd)
            .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.Order.FromPhone == dto.FromPhone) //来电号码
            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName),
                d => d.Order.ActualHandleOrgName.Contains(dto.ActualHandleOrgName)) //接办部门（综合查询模糊）
            .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.Order.AcceptTypeCode == dto.AcceptType) //受理类型
            .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.Order.HotspotSpliceName != null && d.Order.HotspotSpliceName.Contains(dto.Hotspot))
            .WhereIF(!string.IsNullOrEmpty(dto.PublishName), d => d.CreatorName.Contains(dto.PublishName!))
            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo),
                d => d.Order.AcceptorName == dto.NameOrNo! || d.Order.AcceptorStaffNo == dto.NameOrNo!) //受理人/坐席
            .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
            .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
            .WhereIF(dto.Resolve.HasValue, x => x.Resolve == dto.Resolve)
            .WhereIF(dto.IsOverTime == true,
                d => (d.Order.ExpiredTime < DateTime.Now && d.Order.Status < EOrderStatus.Filed) ||
                     (d.Order.ExpiredTime < d.Order.ActualHandleTime && d.Order.Status >= EOrderStatus.Filed)) //是 超期
            .WhereIF(dto.IsOverTime == false,
                d => (d.Order.ExpiredTime > DateTime.Now && d.Order.Status < EOrderStatus.Filed) ||
                     (d.Order.ExpiredTime > d.Order.ActualHandleTime && d.Order.Status >= EOrderStatus.Filed)) //否 超期
            .OrderByDescending(d => d.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<PublishedDto>(total, _mapper.Map<IReadOnlyList<PublishedDto>>(items));
    }

    /// <summary>
    /// 发布列表(集合)
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("published/items")]
    public async Task<IReadOnlyList<PublishedDto>> GetPublishedOrderListAsync([FromQuery] PublishedPagedRequest dto)
    {
        //var query = _orderApplication.GetPublishedOrder(dto);
        //return (await query.ToFixedListAsync(dto.QueryIndex, 200, HttpContext.RequestAborted))
        //.Adapt<List<PublishedDto>>();
        var orderPublishs = await _orderApplication.GetPublishedOrder(dto)
            .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted);

        return _mapper.Map<IReadOnlyList<PublishedDto>>(orderPublishs);
    }

    /// <summary>
    /// 发布列表(总条数)
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("published/count")]
    public async Task<int> GetPublishedOrderCountAsync([FromQuery] PublishedPagedRequest dto)
    {
        return await _orderApplication.GetPublishedOrder(dto).CountAsync();
    }

    /// <summary>
    /// 发布列表数据--导出
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("publishedorder/export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> ExportPublishedOrders([FromBody] ExportExcelDto<PublishedPagedRequest> dto)
    {
        var query = _orderApplication.GetPublishedOrder(dto.QueryDto);
        List<OrderPublish> 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<PublishedDto>>(orders);

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<PublishedDto>(dto.ColumnInfos);

        var dtos = orderDtos
            .Select(stu => _mapper.Map(stu, typeof(PublishedDto), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);

        return ExcelStreamResult(stream, "发布列表数据");
    }

    /// <summary>
    /// 发布详情
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("published-order/{id}")]
    public async Task<PublishedEntityDto> PublishedOrder(string id)
    {
        var publishedOrder = await _orderPublishRepository.GetAsync(id, HttpContext.RequestAborted);

        if (publishedOrder is null)
        {
            throw UserFriendlyException.SameMessage("未知数据!");
        }

        var pubentity = _mapper.Map<PublishedEntityDto>(publishedOrder);
        var visit = await _orderVisitRepository.Queryable().Includes(x => x.OrderVisitDetails)
            .OrderByDescending(x => x.CreationTime)
            .FirstAsync(x => x.OrderId == publishedOrder.OrderId, HttpContext.RequestAborted);
        if (visit != null)
        {
            var details = visit.OrderVisitDetails.Where(x => x.VisitTarget == EVisitTarget.Org).ToList();
            if (details != null && details.Count > 0)
            {
                pubentity.IdNames = new List<Kv>();
                details.ForEach(f => pubentity.IdNames.Add(new Kv() { Key = f.VisitOrgCode, Value = f.VisitOrgName }));
            }
        }

        if (_systemSettingCacheManager.Snapshot)
        {
            await _orderSnapshotRepository.GetAsync(pubentity.OrderId)
                .Then(m => { pubentity.Labels = m.Labels; });
        }

        return pubentity;
    }

    /// <summary>
    /// 修改发布内容
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("published-order-modify")]
    [LogFilter("修改发布内容")]
    public async Task PublishedModify([FromBody] PublishOrderModifyDto dto)
    {
        var publishOrder = await _orderPublishRepository.Queryable()
            .Includes(x => x.Order)
            .Where(x => x.Id == dto.Id)
            .FirstAsync(HttpContext.RequestAborted);

        if (publishOrder is null)
        {
            throw UserFriendlyException.SameMessage("无效数据");
        }

        var history = new OrderPublishHistory();
        history.ArrangeTitleBefor = publishOrder.ArrangeTitle;
        history.ArrangeTitleAfter = dto.ArrangeTitle;
        history.ArrangeContentBefor = publishOrder.ArrangeContent;
        history.ArrangeContentAfter = dto.ArrangeContent;
        history.ArrangeOpinionBefor = publishOrder.ArrangeOpinion;
        history.ArrangeOpinionAfter = dto.ArrangeOpinion;
        history.PublishStateBefor = publishOrder.PublishState;
        history.PublishStateAfter = dto.PublishState;
        history.No = publishOrder.No;
        history.OrderId = publishOrder.OrderId;
        history.OrderPublishId = publishOrder.Id;


        publishOrder.ArrangeTitle = dto.ArrangeTitle;
        publishOrder.ArrangeContent = dto.ArrangeContent;
        publishOrder.ArrangeOpinion = dto.ArrangeOpinion;
        publishOrder.PublishState = dto.PublishState;

        await _orderPublishRepository.UpdateAsync(publishOrder, HttpContext.RequestAborted);
        await _orderPublishHistoryRepository.AddAsync(history, HttpContext.RequestAborted);

        //推省上
        var publishPublishOrder = _mapper.Map<PublishPublishOrderDto>(publishOrder);
        publishPublishOrder.Order = _mapper.Map<OrderDto>(publishOrder.Order);
        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderPublishOrder, publishPublishOrder);
    }

    /// <summary>
    /// 发布修改记录
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("published-history-list/{id}")]
    public async Task<List<OrderPublishHistory>> QueryPublishedHistory(string id)
    {
        return await _orderPublishHistoryRepository.Queryable().Where(x => x.OrderPublishId == id)
            .OrderByDescending(x => x.CreationTime).ToListAsync(HttpContext.RequestAborted);
    }

    /// <summary>
    /// 查询发布平移待办理人
    /// </summary>
    [HttpGet("published/migration")]
    public async Task<IReadOnlyList<OrderMigrationHandler>> PublishMigration()
    {
        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.RolePaiDan);
        var roles = setting?.SettingValue.ToList();
        var users = await _userRepository.Queryable()
            .Includes(d => d.Organization)
            .Includes(d => d.Roles)
            .WhereIF(!_appOptions.Value.IsZiGong && !_appOptions.Value.IsLuZhou, d => d.Roles.Any(x => roles.Contains(x.Name)))
            .WhereIF(_appOptions.Value.IsZiGong || _appOptions.Value.IsLuZhou, d => d.OrgId == OrgSeedData.CenterId)
            .ToListAsync(HttpContext.RequestAborted);
        return users.Select(d => new OrderMigrationHandler
        {
            UserId = d.Id,
            Username = d.Name,
            OrgId = d.OrgId,
            OrgName = d.Organization.Name,
            RoleNames = string.Join(',', d.Roles.Select(x => x.DisplayName).ToList())
        }).ToList();
    }

    /// <summary>
    /// 发布平移
    /// </summary>
    [HttpPost("publish/migration")]
    public async Task PublishMigrationBatch([FromBody] PublishMigrationDto dto)
    {
        var orders = await _orderRepository.Queryable()
            .Where(d => dto.OrderIds.Contains(d.Id) && d.Status == EOrderStatus.Filed)
            .ToListAsync(HttpContext.RequestAborted);
        foreach (var order in orders)
        {
            order.WaitForPublisherId = dto.UserId;
        }

        await _orderRepository.UpdateRangeAsync(orders, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 列表页面基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("publish/base-data")]
    public async Task<object> PublishBaseData()
    {
        var rsp = new
        {
            ChannelOptions = _sysDicDataCacheManager.GetSysDicDataCache(TimeLimitBaseDataConsts.SourceChannel),
            AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType),
            OrderTags = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderTag)
        };
        return rsp;
    }

    /// <summary>
    /// 取消发布
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut("publish/cancel")]
    [LogFilter("取消发布")]
    public async Task<string> PublishCancelAsync([FromBody] PublishCancelInDto dto)
    {
        var enabled = _systemSettingCacheManager.CancelPublishOrderEnabled;
        if (enabled == false) return "取消发布功能已被关闭";

        var publish = await _orderPublishRepository.GetAsync(dto.OrderPublishId)
                      ?? throw UserFriendlyException.SameMessage("发布单不存在");
        publish.IsDeleted = true;
        var order = await _orderRepository.GetAsync(publish.OrderId, HttpContext.RequestAborted) ??
                    throw UserFriendlyException.SameMessage("工单不存在");
        if (order.Status != EOrderStatus.Published && order.Status != EOrderStatus.Visited)
            throw UserFriendlyException.SameMessage("工单状态非[已发布]和[已回访], 不可取消发布.");

        await _orderPublishRepository.UpdateAsync(publish);
        order.Status = EOrderStatus.Filed;
        // 被取消的工单继续由之前发布的用户继续发布;
        order.WaitForPublisherId = publish.CreatorId;
        await _orderRepository.UpdateAsync(order);
        return "取消成功";
    }

    #endregion

    #region 工单回访

    /// <summary>
    /// 获取修改历史记录
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("getordervisitdetailcopy/{id}")]
    public async Task<OrderVisitDetailCopyDto> GetOrderVisitDetailCopy(string id)
    {
        var listCopyData = await _orderVisitDetailCopyRepository.Queryable()
            .Where(p => p.VisitId == id)
            .OrderByDescending(p => p.CreationTime)
            .Take(1)
            .ToListAsync();

        var data = new OrderVisitDetailCopyDto();
        if (listCopyData != null && listCopyData.Any())
        {
            //修改数据
            var list = await _orderVisitDetailCopyRepository.Queryable().Where(p => p.BacthId == listCopyData[0].BacthId).OrderBy(p => p.VisitTarget)
                .ToListAsync();
            if (list != null && list.Any())
            {
                var orderVisitDetailCopyDtos = new List<OrderVisitDetailDto>();
                foreach (var item in list)
                {
                    orderVisitDetailCopyDtos.Add(_mapper.Map<OrderVisitDetailDto>(item));
                }

                data.OrderVisitDetailCopyDtos = orderVisitDetailCopyDtos;
                data.CreatorName = list[0].CreatorName;
                data.CreationTime = list[0].CreationTime;
            }

            //正常数据
            var listData = await _orderVisitedDetailRepository.Queryable().Where(p => p.VisitId == id).OrderBy(p => p.VisitTarget).ToListAsync();
            if (listData != null && listData.Any())
            {
                var orderVisitDetailDtos = new List<OrderVisitDetailDto>();
                foreach (var item in listData)
                {
                    orderVisitDetailDtos.Add(_mapper.Map<OrderVisitDetailDto>(item));
                }

                data.OrderVisitDetailDtos = orderVisitDetailDtos;
            }
        }

        return data;
    }

    /// <summary>
    /// 回访列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("visit")]
    public async Task<PagedDto<OrderVisitDto>> QueryOrderVisitList([FromQuery] QueryOrderVisitDto dto)
    {
        var (total, items) = await _orderApplication.QueryOrderVisitList(dto)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderVisitDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDto>>(items));

        //var orderVisits = await _orderApplication.QueryOrderVisitList(dto)
        //    .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted);
        //return _mapper.Map<>()
    }

    /// <summary>
    /// 回访列表--导出
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("visit/export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> ExportOrderVisit([FromBody] ExportExcelDto<QueryOrderVisitDto> dto)
    {
        var query = _orderApplication.QueryOrderVisitList(dto.QueryDto);
        List<OrderVisit> 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<OrderVisitDto>>(orders);

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderVisitDto>(dto.ColumnInfos);

        var dtos = orderDtos
            .Select(stu => _mapper.Map(stu, typeof(OrderVisitDto), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);
        var excelTitle = dto.QueryDto.VisitStateQuery == EVisitStateQuery.NoVisit ? "回访待办数据" : "回访列表数据";

        return ExcelStreamResult(stream, excelTitle);
    }


    /// <summary>
    /// 发送 回访短信
    /// </summary>
    /// <returns></returns>
    [HttpPost("visit/sms")]
    public async Task VisitPushSMSAsync([FromBody] VisitSmsInDto dto)
        => await _orderApplication.VisitPushSMSAsync(dto, HttpContext.RequestAborted);

    /// <summary>
    /// 回访查询基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("visit/basedata")]
    public Dictionary<string, dynamic> VisitBaseData()
    {
        var voiceEvaluate = EnumExts.GetDescriptions<EVoiceEvaluate>();
        var seatEvaluate = EnumExts.GetDescriptions<ESeatEvaluate>();
        if (_appOptions.Value.IsZiGong == true)
        {
            voiceEvaluate = EnumExtensions.GetEnumKeyValueList<EVoiceEvaluate>();
            seatEvaluate = EnumExtensions.GetEnumKeyValueList<ESeatEvaluate>();
        }

        var visitSatisfaction = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction);
        var visitManner = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitManner);
        if (_appOptions.Value.IsZiGong == false)
        {
            seatEvaluate = seatEvaluate.Where(m => new int[] { -1, 1, 3 }.Contains(m.Key) == false).ToList();
            visitSatisfaction = visitSatisfaction.Where(x => x.DicDataValue != "-1").ToList();
            visitManner = visitManner.Where(x => x.DicDataValue != "-1").ToList();
        }

        return new Dictionary<string, dynamic>
        {
            { "seatEvaluate", seatEvaluate },
            { "visitType", EnumExts.GetDescriptions<EVisitType>() },
            { "voiceEvaluate", voiceEvaluate },
            { "visitSatisfaction", visitSatisfaction },
            { "visitMananer", visitManner },
            { "visitStateQuery", EnumExts.GetDescriptions<EVisitStateQuery>() },
            { "sourceChannel", _sysDicDataCacheManager.SourceChannel },
            { "aiVisitResult", EnumExts.GetDescriptions<EAiVisitResult>() },
            { "orderTags", _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderTag) }
        };
    }

    /// <summary>
    /// 回访详情
    /// </summary>
    /// <returns></returns>
    [HttpGet("visit/{id}")]
    [AllowAnonymous]
    public async Task<object> VisitInfo(string id)
    {
        var orderVisit = await _orderVisitRepository.Queryable()
            .Includes(x => x.Order)
            .Includes(x => x.Employee)
            .Includes(x => x.OrderVisitDetails.OrderBy(d => d.VisitTarget).ToList())
            .FirstAsync(x => x.Id == id, HttpContext.RequestAborted);

        if (orderVisit is null)
        {
            throw UserFriendlyException.SameMessage("未知工单回访");
        }

        int visitCount = await _orderVisitRepository.CountAsync(
            x => x.OrderId == orderVisit.OrderId && x.VisitState == Share.Enums.Order.EVisitState.Visited,
            HttpContext.RequestAborted);
        //int againCount = await _orderVisitRepository.CountAsync(
        //    x => x.OrderId == orderVisit.OrderId && x.AgainState == EAgainState.DoAgain, HttpContext.RequestAborted);
        var voiceEvaluate = EnumExts.GetDescriptions<EVoiceEvaluate>();
        var seatEvaluate = EnumExts.GetDescriptions<ESeatEvaluate>();
        if (_appOptions.Value.IsZiGong == true)
        {
            voiceEvaluate = EnumExtensions.GetEnumKeyValueList<EVoiceEvaluate>();
            seatEvaluate = EnumExtensions.GetEnumKeyValueList<ESeatEvaluate>();
        }

        var visitSatisfaction = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction);
        var visitManner = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitManner);
        if (_appOptions.Value.IsZiGong == false)
        {
            seatEvaluate = seatEvaluate.Where(m => new int[] { -1, 1, 3 }.Contains(m.Key) == false).ToList();
            visitSatisfaction = visitSatisfaction.Where(x => x.DicDataValue != "-1").ToList();
            visitManner = visitManner.Where(x => x.DicDataValue != "-1").ToList();
        }

        var dissatisfiedReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.DissatisfiedReason);
        //var callRecord = await _trCallRecordRepository.GetAsync(x => x.CallAccept == orderVisit.CallId); //由CallAccept改为OtherAccept
        //var callRecord = await _trCallRecordRepository.GetAsync(x => x.OtherAccept == orderVisit.CallId && string.IsNullOrEmpty(x.OtherAccept) == false, HttpContext.RequestAborted);
        var recordingFileUrl = "";
        var recordingBaseAddress = "";
        var recordingAbsolutePath = "";
        var aiVisitVoiceBaseUrl = "";
        if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun)
        {
            var callRecord = await _callApplication.GetTianrunCallAsync(orderVisit.CallId, HttpContext.RequestAborted);
            if (callRecord != null)
            {
                recordingFileUrl = callRecord.RecordingFileUrl;
                recordingBaseAddress = callRecord.RecordingBaseAddress;
                recordingAbsolutePath = callRecord.RecordingAbsolutePath;
            }
        }
        else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang)
        {
            CallNative? call = null;
            if (orderVisit.CallId == null && orderVisit.VisitTime.HasValue)
            {
                call = await _callApplication.GetCallByTimeAndToNoAsync(orderVisit.Order.Contact, orderVisit.VisitTime.Value,
                    HttpContext.RequestAborted);
            }

            call = await _callApplication.GetCallAsync(orderVisit.CallId, HttpContext.RequestAborted);
            if (call is not null)
            {
                if (call.AudioFile.IsNullOrEmpty())
                {
                    call = await _callApplication.GetCallByCallNoAsync(call.CallNo, HttpContext.RequestAborted);
                }

                if (call is not null)
                {
                    recordingFileUrl = call.AudioFile;
                    recordingBaseAddress = call.AudioFile;
                    recordingAbsolutePath = call.AudioFile;
                }
            }
        }

        //获取系统配置智能回访语音URL头
        aiVisitVoiceBaseUrl = _systemSettingCacheManager.GetSetting(SettingConstants.AiVisitVoiceBaseUrl)?.SettingValue[0];

        var histories = new List<OrderVisitDetailHistoryDto>();
        var isCanUpdate = false;
        if (_appOptions.Value.IsZiGong)
        {
            histories = await _orderVisitRepository.Queryable()
                .Includes(m => m.OrderVisitDetails)
                .Where(m => m.OrderId == orderVisit.OrderId)
                .Where(m => m.VisitState == EVisitState.None && m.NowEvaluate != null)
                .Select(m => new OrderVisitDetailHistoryDto
                {
                    VoiceEvaluate = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Seat).Select(s => s.VoiceEvaluate).First(),
                    SeatEvaluate = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Seat).Select(s => s.SeatEvaluate).First(),
                    VisitOrgName = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.VisitOrgName).First(),
                    OrgProcessingResults = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.OrgProcessingResults)
                        .First(),
                    OrgHandledAttitude = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.OrgHandledAttitude).First(),
                    VisitContent = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.VisitContent).First(),
                    VisitTime = m.VisitTime,
                    CallId = m.CallId
                }).ToListAsync();

            if (orderVisit.OrderVisitDetails != null && orderVisit.OrderVisitDetails.Any())
            {
                var seatVisit = orderVisit.OrderVisitDetails.FirstOrDefault(p => p.VisitTarget == EVisitTarget.Seat);
                if (seatVisit != null)
                {
                    if (seatVisit.VoiceEvaluate == null ||
                        seatVisit.VoiceEvaluate.HasValue == false ||
                        seatVisit.VoiceEvaluate == EVoiceEvaluate.NoSatisfied ||
                        seatVisit.VoiceEvaluate == EVoiceEvaluate.VeryNoSatisfied)
                    {
                        isCanUpdate = true;
                    }
                }
            }
        }

        var seat = orderVisit.OrderVisitDetails.FirstOrDefault(m => m.VisitTarget == EVisitTarget.Seat);
        //if (orderVisit.VisitState == EVisitState.WaitForVisit)
        if (seat.VoiceEvaluate == null)
        {
            if (!_appOptions.Value.IsYiBin)
            {
                // 如果是待回访, 就取用户电话评价时评价的内容;
                var callNative = await _callApplication.GetReplyVoiceOrDefaultByOrderIdAsync(orderVisit.OrderId);
                seat.VoiceEvaluate = callNative;
            }
        }

        if (seat.SeatEvaluate is null)
        {
            if (_appOptions.Value.IsYiBin)
            {
                var seatEvaluateTemp = await _callApplication.GetSeatDefaultByOrderIdAsync(orderVisit.OrderId);
                seat.SeatEvaluate = seatEvaluateTemp;
            }
        }

        var rsp = new
        {
            OrderVisitModel = _mapper.Map<OrderVisitDto>(orderVisit),
            VisitCount = visitCount,
            //AgainCount = againCount,
            VisitSatisfaction = visitSatisfaction,
            DissatisfiedReason = dissatisfiedReason,
            VisitManner = visitManner,
            ViceEvaluate = voiceEvaluate,
            SeatEvaluate = seatEvaluate,
            RecordingFileUrl = recordingFileUrl,
            RecordingBaseAddress = recordingBaseAddress,
            RecordingAbsolutePath = recordingAbsolutePath,
            AiVisitVoiceBaseUrl = aiVisitVoiceBaseUrl,
            Histories = histories,
            IsCanUpdate = isCanUpdate
        };
        if (!_sessionContext.OrgIsCenter && rsp.OrderVisitModel.Order.IsSecret)
        {
            if (_appOptions.Value.IsZiGong)
                rsp.OrderVisitModel.Order = rsp.OrderVisitModel.Order.DataMask(true);
            if (_appOptions.Value.IsLuZhou)
            {
                rsp.OrderVisitModel.Order.FromPhone =
                    "****"; //rsp.OrderVisitModel.Order.FromPhone?.Replace(rsp.OrderVisitModel.Order.FromPhone.Substring(3, 4), "****");
                rsp.OrderVisitModel.Order.Contact =
                    "****"; //rsp.OrderVisitModel.Order.Contact?.Replace(rsp.OrderVisitModel.Order.Contact.Substring(3, 4), "****");
            }
        }

        return rsp;
    }

    /// <summary>
    /// 回访明细
    /// </summary>
    /// <returns></returns>
    [HttpGet("visit/detail")]
    public async Task<PagedDto<OrderVisitDetailDto>> VisitDetailList([FromQuery] VisitDetailListDto dto)
    {
        var (total, items) = await _orderVisitedDetailRepository.Queryable()
            .Includes(x => x.OrderVisit, s => s.Order)
            .WhereIF(dto.VisitState == EVisitStateQuery.NoVisit,
                x => x.OrderVisit.VisitState == Share.Enums.Order.EVisitState.WaitForVisit || x.OrderVisit.VisitState ==
                    Share.Enums.Order.EVisitState.NoSatisfiedWaitForVisit)
            .WhereIF(dto.VisitState == EVisitStateQuery.Visited,
                x => x.OrderVisit.VisitState == Share.Enums.Order.EVisitState.Visited)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                d => d.OrderVisit.Order.Title.Contains(dto.Keyword!) || d.OrderVisit.Order.No.Contains(dto.Keyword!))
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<OrderVisitDetailDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDetailDto>>(items));
    }

    /// <summary>
    /// 回访保存
    /// </summary>
    /// <returns></returns>
    [HttpPost("visit")]
    [LogFilterAlpha("工单回访")]
    public async Task Visit([FromBody] VisitDto dto)
    {
        // 发送延迟关联通话记录消息
        dto.CallId = await _callApplication.PublishVisitRelevanceCallIdAsync(dto.Adapt<OrderRelevanceCallIdDto>(), HttpContext.RequestAborted);
        dto.CallId = await _callApplication.GetOrSetCallIdAsync(dto.CallId, HttpContext.RequestAborted);
        await _orderApplication.SaveOrderVisit(dto, HttpContext.RequestAborted);
        if (dto.IsTransact.HasValue && dto.IsTransact.Value)
        {
            await Add(dto.OrderReTransact);
        }
    }

    /// <summary>
    /// 批量保存回访
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("visit/batch")]
    [LogFilter("批量工单回访")]
    public async Task<VisitBatchOutDto> VisitBatch([FromBody] VisitBatchInDto dto)
    {
        var errorMessage = new StringBuilder();
        var outDto = new VisitBatchOutDto();
        var orderIds = dto.Visit.Select(m => m.OrderId).ToList();
        var hasHuiQian = await _orderRepository.Queryable().AnyAsync(x => orderIds.Contains(x.Id) && x.CounterSignType != null);
        if (hasHuiQian)
            throw UserFriendlyException.SameMessage("选择的回访单中含有会签工单, 不能批量回访. 请排除会签工单.");

        var hasProvince = await _orderRepository.Queryable().AnyAsync(x => orderIds.Contains(x.Id) && x.IsProvince == true);
        if (hasProvince)
            throw UserFriendlyException.SameMessage("选择的回访单中含有省工单, 不能批量回访. 请排除省工单.");


        foreach (var visit in dto.Visit)
        {
            try
            {
                var details = await _orderVisitedDetailRepository
                    .Queryable()
                    .Where(m => m.VisitId == visit.VisitId)
                    .ToListAsync();
                var seatDetail = details.First(m => m.VisitTarget == EVisitTarget.Seat);
                var seatDetailDto = new VisitDetailDto()
                {
                    Id = seatDetail.Id,
                    VisitId = visit.VisitId,
                    VisitContent = dto.SeatVisitContent,
                    SeatEvaluate = dto.SeatEvaluate,
                    VisitTarget = EVisitTarget.Seat,
                };
                if (seatDetail.VoiceEvaluate == null)
                    seatDetailDto.VoiceEvaluate = EVoiceEvaluate.DefaultSatisfied;

                var visitDto = new VisitDto
                {
                    Id = visit.VisitId,
                    IsPutThrough = true,
                    IsAgain = false,
                    VisitDetails = new List<VisitDetailDto>()
                };
                visitDto.VisitDetails.Add(seatDetailDto);

                var orgDetails = details.Where(m => m.VisitTarget == EVisitTarget.Org).ToList();
                foreach (var orgDetail in orgDetails)
                {
                    visitDto.VisitDetails.Add(
                        new()
                        {
                            Id = orgDetail.Id,
                            VisitId = visit.VisitId,
                            VisitContent = dto.OrgVisitContent,
                            VisitTarget = EVisitTarget.Org,
                            OrgNoSatisfiedReason = dto.OrgNoSatisfiedReason,
                            OrgProcessingResults = dto.OrgProcessingResults,
                            OrgHandledAttitude = dto.OrgHandledAttitude,
                            VisitOrgName = orgDetail.VisitOrgName,
                            VisitOrgCode = orgDetail.VisitOrgCode,
                        });
                }

                if (visitDto.CallId != null)
                {
                    visitDto.CallId = await _callApplication.GetOrSetCallIdAsync(visitDto.CallId, HttpContext.RequestAborted);
                }

                await _orderApplication.SaveOrderVisit(visitDto, HttpContext.RequestAborted);
                await _orderVisitRepository.Updateable()
                    .Where(m => m.Id == visit.VisitId)
                    .SetColumns(m => m.IsBatchVisit == true)
                    .ExecuteCommandAsync();
                outDto.CompleteCount += 1;
            }
            catch (Exception e)
            {
                outDto.ErrorCount += 1;
                errorMessage.Append($"【{visit.No}】 保存失败.");
                _logger.LogError($"orderVisitId:{visit.VisitId} 保存回访失败, err: {e.Message}");
            }
            finally
            {
                outDto.TotalCount += 1;
            }
        }

        outDto.ErrorMessage = errorMessage.ToString();
        return outDto;
    }

    /// <summary>
    /// 批量保存回访基础数据
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("visit/batch-basedata")]
    public Dictionary<string, dynamic> VisitBatchBaseDat()
    {
        //return _baseDataApplication
        //    .SeatEvaluate()
        //    .DissatisfiedReason()
        //    .VisitSatisfaction()
        //    .VisitManner()
        //    .Build();
        return new Dictionary<string, dynamic>
        {
            { "seatEvaluate", EnumExts.GetDescriptions<ESeatEvaluate>() },
            { "dissatisfiedReason", _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.DissatisfiedReason) },
            { "visitSatisfaction", _sysDicDataCacheManager.GetVisitSatisfaction() },
            { "visitManner", _sysDicDataCacheManager.VisitMananer }
        };
    }

    /// <summary>
    /// 扭转列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("visit/judge-query")]
    public async Task<PagedDto<OrderVisitDto>> VisitJudgeQuery([FromQuery] VisitJudgeQueryReq dto)
    {
        var (total, items) = await _orderRepository.VisitJudgeQuery(dto)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderVisitDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDto>>(items));
    }

    /// <summary>
    /// 扭转列表查询基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("visit/judge-query-basedata")]
    public async Task<object> VisitJudgeQueryBaseData()
    {
        return new
        {
            FiledTypeOptions = EnumExts.GetDescriptions<FiledType>(),
            AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType),
            OrgsOptions = await _organizeRepository.GetOrgJson(),
            CallForwardingOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.CallForwardingSource),
            JudgeStateOptions = EnumExts.GetDescriptions<EJudgeState>()
        };
    }

    /// <summary>
    /// 扭转列表导出
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("visit/judge-query-export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> VisitJudgeQueryExport([FromBody] ExportExcelDto<VisitJudgeQueryReq> dto)
    {
        var query = _orderRepository.VisitJudgeQuery(dto.QueryDto);

        List<OrderVisit> datas;
        if (dto.IsExportAll)
        {
            datas = await query.ToListAsync(HttpContext.RequestAborted);
        }
        else
        {
            var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
            datas = items;
        }

        var orderDtos = _mapper.Map<ICollection<OrderVisitDto>>(datas);
        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderVisitDto>(dto.ColumnInfos);
        var dtos = orderDtos
            .Select(stu => _mapper.Map(stu, typeof(OrderVisitDto), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);
        return ExcelStreamResult(stream, "扭转明细");
    }

    /// <summary>
    /// 扭转满意度
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("visit/judge")]
    [LogFilterAlpha("扭转满意度")]
    public async Task<JudgeVisitRsp> JudgeVisit([FromBody] JudgeVisitReq dto)
    {
        int error = 0;
        var list = await _orderVisitRepository.Queryable().Where(x => dto.Ids.Contains(x.Id) && x.VisitState == EVisitState.Visited)
            .ToListAsync(HttpContext.RequestAborted);
        list.ForEach(visit =>
        {
            visit.JudgeState = dto.IsAgree ? EJudgeState.Agreed : EJudgeState.UnAgreed;
            visit.JudgeUserId = _sessionContext.RequiredUserId;
            visit.JudgeUserName = _sessionContext.UserName;
            visit.JudgeTime = DateTime.Now;
            visit.JudgeContent = dto.JudgeContent;
        });
        await _orderVisitRepository.UpdateRangeAsync(list, HttpContext.RequestAborted);
        return new JudgeVisitRsp() { ErrorCount = error, SuccessCount = dto.Ids.Count - error };
    }

    /// <summary>
    /// 回访平移
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("visit/migration")]
    [LogFilterAlpha("回访平移")]
    public async Task VisitMigrationBatch([FromBody] DistributionVisitDto dto)
    {
        var visits = await _orderVisitRepository.Queryable()
            .Where(d => (d.VisitState == EVisitState.WaitForVisit || d.VisitState == EVisitState.SMSUnsatisfied || d.VisitState == EVisitState.AiVisitWaitForVisit) && dto.Ids.Contains(d.Id))
            .ToListAsync(HttpContext.RequestAborted);

        foreach (var visit in visits)
        {
            visit.EmployeeId = dto.UserId;
        }

        await _orderVisitRepository.UpdateRangeAsync(visits, HttpContext.RequestAborted);
    }


    /// <summary>
    /// 查询回访平移待办理人
    /// </summary>
    [HttpGet("ordervisit/migration")]
    public async Task<IReadOnlyList<OrderMigrationHandler>> VisitMigration()
    {
        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.OrderVisitRole);
        var roles = setting?.SettingValue.ToList();
        var users = await _userRepository.Queryable()
            .Includes(d => d.Organization)
            .Includes(d => d.Roles)
            .WhereIF(!_appOptions.Value.IsZiGong, d => d.Roles.Any(x => roles.Contains(x.Name)))
            .WhereIF(_appOptions.Value.IsZiGong, d => d.OrgId == OrgSeedData.CenterId)
            .ToListAsync(HttpContext.RequestAborted);
        return users.Select(d => new OrderMigrationHandler
        {
            UserId = d.Id,
            Username = d.Name,
            OrgId = d.OrgId,
            OrgName = d.Organization.Name,
            RoleNames = string.Join(',', d.Roles.Select(x => x.DisplayName).ToList())
        }).ToList();
    }


    /// <summary>
    /// 设置未接通
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut("visit/put_through")]
    [LogFilterAlpha("设置未接通")]
    public async Task VisitPutThrough([FromBody] VisitPutThroughDto dto)
    {
        await _orderVisitRepository.Updateable().SetColumns(x => new OrderVisit { IsPutThrough = false }).Where(x => x.Id == dto.id)
            .ExecuteCommandAsync(HttpContext.RequestAborted);
    }

    /// <summary>
    /// 部门满意度明细
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("org-visitdetail-list")]
    public async Task<PagedDto<OrgVisitDetailListResp>> OrgVisitDetailList([FromQuery] OrgVisitDetailListReq dto)
    {
        //特殊需求：管理员账号使用该查询条件查询的数据，与富顺的账号查询的数据一致；
        var isAdmin = _orderDomainService.IsCheckAdmin();
        var orgId = isAdmin ? "001059" : _sessionContext.RequiredOrgId;
        var query = _orderRepository.OrgVisitDetailFiltrationList(dto, orgId);
        var (total, items) = await query.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<OrgVisitDetailListResp>(total, _mapper.Map<IReadOnlyList<OrgVisitDetailListResp>>(items));
    }

    /// <summary>
    /// 部门满意度明细导出
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("org-visitdetail-list-export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> OrgVisitDetailListExport([FromBody] ExportExcelDto<OrgVisitDetailListReq> dto)
    {
        //特殊需求：管理员账号使用该查询条件查询的数据，与富顺的账号查询的数据一致；
        var isAdmin = _orderDomainService.IsCheckAdmin();
        var orgId = isAdmin ? "001059" : _sessionContext.RequiredOrgId;
        var query = _orderRepository.OrgVisitDetailFiltrationList(dto.QueryDto, orgId);

        List<OrgVisitDetailListResp> orders;
        if (dto.IsExportAll)
        {
            orders = await query.ToListAsync(HttpContext.RequestAborted);
        }
        else
        {
            var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
            orders = items;
        }

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrgVisitDetailListResp>(dto.ColumnInfos);
        var dtos = orders
            .Select(stu => _mapper.Map(stu, typeof(OrgVisitDetailListResp), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);
        return ExcelStreamResult(stream, "部门满意度明细");
    }

    #endregion

    #region 二次回访申请

    /// <summary>
    /// 可二次回访申请列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("visitapply/visitagainlist")]
    public async Task<PagedDto<OrderCanVisitAgainDto>> OrderVisitAgainList([FromQuery] OrderVisitAgainListDto dto)
    {
        var (total, items) = await _orderVisitedDetailRepository.Queryable()
            .Includes(x => x.OrderVisit, x => x.Order)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.OrderVisit.Order.No.Contains(dto.Keyword))
            .Where(x => x.OrderVisit.VisitState == EVisitState.Visited &&
                        (x.OrderVisit.VisitType == EVisitType.SmsVisit ||
                         x.OrderVisit.VisitType == EVisitType.ChipVoiceVisit))
            .Where(x => SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "1" ||
                        SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "2")
            .Where(x => x.OrderVisit.IsCanHandle)
            .Where(x => x.VisitTarget == EVisitTarget.Org)
            .OrderByDescending(x => x.OrderVisit.VisitTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderCanVisitAgainDto>(total, _mapper.Map<IReadOnlyList<OrderCanVisitAgainDto>>(items));
    }

    /// <summary>
    /// 二次回访申请
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    /// <exception cref="UserFriendlyException"></exception>
    [HttpPost("visitapply/add")]
    [LogFilter("新增工单二次回访申请")]
    public async Task ApplyOrderVisit([FromBody] AddVisitApplyDto dto)
    {
        var orderVisitApply = _mapper.Map<OrderVisitApply>(dto);
        //验证是否可以申请二次回访

        var isAny = await _orderVisitApplyRepository.AnyAsync(
            x => x.OrderId == orderVisitApply.OrderId && x.VisitApplyState != EVisitApplyState.NoPass,
            HttpContext.RequestAborted);
        if (isAny)
            throw UserFriendlyException.SameMessage("当前状态不能申请二次回访");

        var orderModel =
            await _orderRepository.GetAsync(x => x.Id == orderVisitApply.OrderId, HttpContext.RequestAborted);
        if (orderModel?.CounterSignType != null)
            throw UserFriendlyException.SameMessage("会签件不能申请二次回访");

        var orderVisitModel = await _orderVisitRepository.GetAsync(x => x.Id == dto.OrderVisitId && x.IsCanHandle,
            HttpContext.RequestAborted);
        if (orderVisitModel == null)
            throw UserFriendlyException.SameMessage("当前状态不能进行二次回访");


        orderVisitModel.IsCanHandle = false;
        await _orderVisitRepository.UpdateAsync(orderVisitModel, HttpContext.RequestAborted);

        orderVisitApply.EmployeeId = _sessionContext.RequiredUserId;
        orderVisitApply.VisitApplyState = EVisitApplyState.Examining;
        await _orderVisitApplyRepository.AddAsync(orderVisitApply, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 二次回访审核
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("visitapply/examin")]
    [LogFilter("新增工单二次回访审核")]
    public async Task ExaminOrderVisit([FromBody] ExaminOrderVisitDto dto)
    {
        //获取二次回访申请
        var visitApplyModel = await _orderVisitApplyRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        if (visitApplyModel == null)
            throw UserFriendlyException.SameMessage("无效申请");
        if (visitApplyModel.VisitApplyState != EVisitApplyState.Examining)
            throw UserFriendlyException.SameMessage("当前状态不能审核");

        if (dto.IsPass)
            visitApplyModel.VisitApplyState = EVisitApplyState.Pass;
        else
            visitApplyModel.VisitApplyState = EVisitApplyState.NoPass;
        visitApplyModel.ExaminOpinion = dto.ExaminOpinion;
        visitApplyModel.ExaminManId = _sessionContext.RequiredUserId;
        visitApplyModel.ExaminTime = DateTime.Now;
        await _orderVisitApplyRepository.UpdateAsync(visitApplyModel, HttpContext.RequestAborted);
        //处理通过后的业务
        if (dto.IsPass)
        {
            //处理申请单
            visitApplyModel.VisitApplyState = EVisitApplyState.Pass;
            await _orderVisitApplyRepository.UpdateAsync(visitApplyModel, HttpContext.RequestAborted);
            //处理原回访数据
            var visitModel =
                await _orderVisitRepository.GetAsync(visitApplyModel.OrderVisitId, HttpContext.RequestAborted);
            if (visitModel != null)
            {
                visitModel.VisitState = EVisitState.None;
                await _orderVisitRepository.UpdateAsync(visitModel, HttpContext.RequestAborted);
                //处理新回访数据
                //查询原回访数据子表
                var visitModelNew = _mapper.Map<OrderVisit>(visitModel);
                visitModelNew.InitId();
                visitModelNew.CreationTime = DateTime.Now;
                visitModelNew.CreatorId = string.Empty;
                visitModelNew.CreatorName = string.Empty;
                visitModelNew.CreatorOrgId = string.Empty;
                visitModelNew.CreatorOrgName = string.Empty;
                visitModelNew.CreatorOrgLevel = 0;
                visitModelNew.AreaId = string.Empty;
                visitModelNew.VisitState = EVisitState.WaitForVisit;
                visitModelNew.IsCanHandle = false;

                var id = await _orderVisitRepository.AddAsync(visitModelNew, HttpContext.RequestAborted);
                var visitModelDetail = await _orderVisitedDetailRepository.Queryable()
                    .Where(x => x.VisitId == visitModel.Id).ToListAsync(HttpContext.RequestAborted);
                var visitDetailListNew = new List<OrderVisitDetail>();
                foreach (var item in visitModelDetail)
                {
                    var visitDetail = new OrderVisitDetail();
                    visitDetail.VisitId = id;
                    visitDetail.VisitOrgCode = item.VisitOrgCode;
                    visitDetail.VisitOrgName = item.VisitOrgName;
                    visitDetail.VisitTarget = item.VisitTarget;
                    visitDetailListNew.Add(visitDetail);
                }

                await _orderVisitedDetailRepository.AddRangeAsync(visitDetailListNew, HttpContext.RequestAborted);
            }
        }
        else
        {
            //处理申请单
            visitApplyModel.VisitApplyState = EVisitApplyState.NoPass;
            visitApplyModel.ExaminManId = _sessionContext.RequiredUserId;
            visitApplyModel.ExaminOpinion = dto.ExaminOpinion;
            visitApplyModel.ExaminTime = DateTime.Now;
            await _orderVisitApplyRepository.UpdateAsync(visitApplyModel, HttpContext.RequestAborted);
            var visitModel =
                await _orderVisitRepository.GetAsync(visitApplyModel.OrderVisitId, HttpContext.RequestAborted);
            if (visitModel != null)
            {
                visitModel.IsCanHandle = true;
                await _orderVisitRepository.UpdateAsync(visitModel, HttpContext.RequestAborted);
            }
        }
    }


    /// <summary>
    /// 二次回访申请列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("visitapply/list")]
    public async Task<PagedDto<VisitApplyDto>> VisitApplyList([FromQuery] VisitApplyListDto dto)
    {
        var (total, items) = await _orderVisitApplyRepository.Queryable()
            .Includes(d => d.Order)
            .Includes(d => d.OrderVisit,
                d => d.OrderVisitDetails.Where(x => x.VisitTarget == EVisitTarget.Org).ToList())
            .Includes(d => d.OrderVisit, d => d.Employee)
            .Includes(d => d.Employee)
            .WhereIF(dto.VisitApplyState != null, x => x.VisitApplyState == dto.VisitApplyState)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.OrderNo.Contains(dto.Keyword))
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<VisitApplyDto>(total, _mapper.Map<IReadOnlyList<VisitApplyDto>>(items));
    }

    /// <summary>
    /// 获取二次回访申请
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("visitapply/{id}")]
    public async Task<VisitApplyDto> VisitApplyEntity(string id)
    {
        var model = await _orderVisitApplyRepository.GetExtAsync(x => x.Id == id, x => x.Includes(d => d.Order));

        return _mapper.Map<VisitApplyDto>(model);
    }

    /// <summary>
    /// 页面基础信息
    /// </summary>
    /// <returns></returns>
    [HttpGet("visitapply/basedata")]
    public async Task<object> VisitApplyBaseData()
    {
        var rsp = new
        {
            VisitApplyState = EnumExts.GetDescriptions<EVisitApplyState>()
        };
        return rsp;
    }

    #endregion

    #region 工单重办

    /// <summary>
    /// 重办查询
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("redo")]
    public async Task<PagedDto<OrderRedo>> QueryOrderRedo([FromQuery] QueryOrderRedoRecordDto dto)
    {
        var (total, items) = await _orderRedoRepository.Queryable()
            .Includes(x => x.Order)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<OrderRedo>(total, items);
    }

    /// <summary>
    /// 重办详情
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("redo/{id}")]
    public async Task<OrderRedo> GetOrderRedo(string id)
    {
        return await _orderRedoRepository.Queryable()
            .Includes(x => x.Order)
            .FirstAsync(x => x.Id == id);
    }

    ///// <summary>
    ///// 发起重办
    ///// </summary>
    //[HttpPost("redo")]
    //[LogFilter("新增工单重办")]
    //public async Task<string> AddRedo([FromBody] OrderRedoStartFlowDto dto)
    //{
    //    var redo = _mapper.Map<OrderRedo>(dto.Data);
    //    redo.CreatorName = _sessionContext.UserName ?? string.Empty;
    //    redo.CreatorOrgName = _sessionContext.OrgName ?? string.Empty;
    //    //redo.TimeLimitCount = dto.Workflow.Extension.TimeLimitCount;
    //    //redo.TimeLimitUnit = dto.Workflow.Extension.TimeLimitUnit;
    //    //todo
    //    var handler = dto.Workflow.NextHandlers.First();
    //    redo.RedoOrgCode = handler.Key;
    //    redo.RedoOrgCode = handler.Value;

    //    var id = await _orderRedoRepository.AddAsync(redo, HttpContext.RequestAborted);

    //    try
    //    {
    //        var order = await _orderRepository.GetAsync(dto.Data.OrderId, HttpContext.RequestAborted);
    //        if (order == null)
    //            throw UserFriendlyException.SameMessage("无效工单编号");
    //        if (string.IsNullOrEmpty(order.WorkflowId))
    //            throw UserFriendlyException.SameMessage("无效工单流程编号");

    //        var redoFlowDto = _mapper.Map<RecallDto>(dto.Workflow);
    //        redoFlowDto.WorkflowId = order.WorkflowId;

    //        await _workflowApplication.RedoAsync(redoFlowDto, HttpContext.RequestAborted);
    //        return id;
    //    }
    //    catch (Exception e)
    //    {
    //        await _orderRedoRepository.RemoveAsync(id, cancellationToken: HttpContext.RequestAborted);
    //        throw new UserFriendlyException($"发起重办失败，{e.Message}");
    //    }
    //}

    /// <summary>
    /// 重办基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("base-data-redo")]
    public async Task<dynamic> BaseDataRedo()
    {
        var rsp = new
        {
            OrderRedoReasonOptions = EnumExts.GetDescriptions<EOrderRedoReason>(),
        };
        return rsp;
    }

    #endregion

    #region 工单延期

    /// <summary>
    /// 可申请延期工单
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("candelay")]
    public async Task<PagedDto<OrderDto>> CanDelayOrderList([FromQuery] CanDelayOrderListDto dto)
    {
        var (total, items) = await _orderRepository.Queryable()
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
            .Where(d => d.Status != EOrderStatus.WaitForAccept && d.Status != EOrderStatus.Filed &&
                        SqlFunc.Subqueryable<OrderDelay>()
                            .Where(s => s.OrderId == d.Id && s.DelayState == EDelayState.Examining).NotAny())
            .OrderByDescending(d => d.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
    }

    /// <summary>
    /// 工单延期修改延期时限
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("alter_delay_day")]
    [LogFilter("工单延期修改延期时限")]
    public async Task AlterDelayDay([FromBody] AlterDelayDayDto dto)
    {
        if (dto.DelayNum < 1) throw UserFriendlyException.SameMessage("延期申请天数需大于等于1天!");
        var deday = await _orderDelayRepository.Queryable().Includes(x => x.Order).FirstAsync(x => x.Id == dto.Id, HttpContext.RequestAborted);
        if (_appOptions.Value.IsLuZhou && dto.DelayNum > deday.Order.TimeLimitCount) throw UserFriendlyException.SameMessage("申请天数需小于等于工单办理时限!");
        await _orderDelayRepository.Updateable().SetColumns(x => new OrderDelay { DelayNum = dto.DelayNum }).Where(x => x.Id == dto.Id)
            .ExecuteCommandAsync(HttpContext.RequestAborted);
    }

    /// <summary>
    /// 申请延期
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("delay")]
    [LogFilter("新增工单延期申请")]
    public async Task<string> ApplyDelay([FromBody] StartWorkflowDto<ApplyDelayDto> dto)
    {
        var delaydto = dto.Data;

        if (string.IsNullOrEmpty(dto.Workflow.Opinion))
            throw UserFriendlyException.SameMessage("办理意见不能为空!");

        //验证工单是否可以申请
        var order = await _orderRepository.GetAsync(delaydto.OrderId, HttpContext.RequestAborted);
        if (order is null)
            throw UserFriendlyException.SameMessage("无效工单");
        //验证工单是否在办理中
        if (order.Status == EOrderStatus.WaitForAccept || order.Status >= EOrderStatus.Filed)
            throw UserFriendlyException.SameMessage("当前工单状态不能申请延期");

        bool IsHas = await _orderDelayRepository.AnyAsync(
            x => x.OrderId == delaydto.OrderId && x.DelayState == EDelayState.Examining, HttpContext.RequestAborted);
        if (IsHas)
            throw UserFriendlyException.SameMessage("该存在延期申请正在审核");
        if (DateTime.Now > order.ExpiredTime)
        {
            if (_appOptions.Value.IsZiGong)
            {
                throw UserFriendlyException.SameMessage("已经超期的工单无法发起延期申请!");
            }
            else if (_appOptions.Value.IsLuZhou)
            {
                throw UserFriendlyException.SameMessage("已经超期的工单无法发起延期申请！");
            }
        }

        if (_appOptions.Value.IsLuZhou && delaydto.DelayNum > order.TimeLimitCount) throw UserFriendlyException.SameMessage("申请天数需小于等于工单办理时限!");

        //验证延期次数
        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.DelayNum);
        if (int.Parse(setting?.SettingValue[0]) != 0 && !_sessionContext.OrgIsCenter)
        {
            int count = await _orderDelayRepository.CountAsync(x =>
                x.OrderId == delaydto.OrderId &&
                x.ApplyOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) ==
                _sessionContext.RequiredOrgId.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) &&
                x.DelayState == EDelayState.Pass);
            if (_appOptions.Value.IsZiGong)
            {
                count = await _orderDelayRepository.CountAsync(x =>
                    x.OrderId == delaydto.OrderId && x.ApplyOrgCode == _sessionContext.RequiredOrgId &&
                    (x.DelayState == EDelayState.Pass || x.DelayState == EDelayState.NoPass));
            }

            if (count >= int.Parse(setting?.SettingValue[0]))
                throw UserFriendlyException.SameMessage("延期申请已超过系统预定设置，不能申请");
        }

        var model = _mapper.Map<OrderDelay>(delaydto);
        model.EmployeeId = _sessionContext.RequiredUserId;
        model.EmployeeName = _sessionContext.UserName;
        model.ApplyOrgName = _sessionContext.OrgName;
        model.ApplyOrgCode = _sessionContext.RequiredOrgId;
        model.DelayApplyType = EDelayApplyType.LocalApply;
        model.BeforeDelay = order.ExpiredTime;
        model.DelayState = EDelayState.Examining;
        model.DelayReason = dto.Workflow.Opinion;

        if (model.BeforeDelay != null)
        {
            var expiredTimeBase = DateTime.Now;
            if (_appOptions.Value.IsZiGong)
            {
                expiredTimeBase = order.ExpiredTime.Value;
            }

            //model.AfterDelay = _timeLimitDomainService
            var startTime = DateTime.Now;
            if (order.CenterToOrgTime.HasValue)
            {
                startTime = order.CenterToOrgTime.Value;
            }

            model.AfterDelay = (await _expireTime
                .CalcEndTime(expiredTimeBase, startTime, delaydto.DelayUnit, delaydto.DelayNum, order.AcceptTypeCode))?.EndTime; //todo
        }

        model.ApplyDelayTime = DateTime.Now;
        model.No = order.No;
        model.InitId();
        if (dto.Data.Files.Any())
            model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted);
        await _orderDelayRepository.AddAsync(model, HttpContext.RequestAborted);
        try
        {
            var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
            startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderDelay;
            startDto.Opinion = model.DelayReason;
            startDto.Title = "申请延期流程";
            // string workFlowId = await _workflowApplication.StartWorkflowAsync(startDto, model.Id,
            //     cancellationToken: HttpContext.RequestAborted);
            //model.WorkflowId = workFlowId;
            //await _orderDelayRepository.UpdateAsync(model, HttpContext.RequestAborted);
            // await _workflowDomainService.StartAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
            await _workflowDomainService.StartToFirstStepAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
        }
        catch (Exception ex)
        {
            await _orderDelayRepository.RemoveAsync(model.Id, false, HttpContext.RequestAborted);
            throw new UserFriendlyException($"工单延期流程失败!, {ex.Message}", "工单延期流程失败");
        }

        return model.Id;
    }


    /// <summary>
    /// 工单延期修改后下一步流程
    /// </summary>
    [HttpPost("delay/initial_nextFlow")]
    [LogFilter("开始工单延期流程")]
    public async Task InitialNextFlow([FromBody] DelayNextFlowDto dto)
    {
        var delay = await _orderDelayRepository.GetAsync(dto.Data.Id);
        _mapper.Map(dto.Data, delay);
        if (dto.Data.Files.Any())
            delay.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, delay.Id, "", HttpContext.RequestAborted);
        else
            delay.FileJson = new List<Share.Dtos.File.FileJson>();
        await _orderDelayRepository.UpdateAsync(delay, HttpContext.RequestAborted);
        try
        {
            dto.NextWorkflow.WorkflowId = delay.WorkflowId;
            await _workflowDomainService.NextAsync(dto.NextWorkflow, cancellationToken: HttpContext.RequestAborted);
        }
        catch (Exception e)
        {
            throw new UserFriendlyException($"工单延期下一步流程失败!, {e.Message}", "工单延期下一步流程失败");
        }
    }

    /// <summary>
    /// 批量审批延期
    /// </summary>
    [HttpPost("delay/batch_audit")]
    [LogFilter("批量审批延期")]
    //[LogFilterAlpha("延期审核")]
    public async Task<string> BatchAuditDelay([FromBody] BatchDelayNextFlowDto dto)
    {
        var result = new StringBuilder();
        var fail = 0;
        var success = 0;
        var workflow = dto.NextWorkflow;
        foreach (var item in dto.DelayId)
        {
            try
            {
                //if (workflow.NextHandlers.Any() && workflow.NextHandlers.Count() == 1)
                //{
                //    var handler = workflow.NextHandlers.FirstOrDefault();
                //    if (string.IsNullOrEmpty(handler.UserId))
                //    {
                //        workflow.NextHandlers = new List<StepAssignInfo>();
                //    }
                //}

                var delay = await _orderDelayRepository.Queryable().Includes(x => x.Order).Where(x => x.Id == item)
                    .FirstAsync(HttpContext.RequestAborted);
                workflow.WorkflowId = delay.WorkflowId;
                var workflowEntuty = await _workflowDomainService.GetWorkflowAsync(workflow.WorkflowId, withDefine: true, withSteps: true,
                    cancellationToken: HttpContext.RequestAborted);
                var currentStep = workflowEntuty.Steps.FirstOrDefault(d =>
                    d.Status == EWorkflowStepStatus.WaitForAccept || d.Status == EWorkflowStepStatus.WaitForHandle);

                NextStepsWithOpinionDto<NextStepOption> next = null;

                try
                {
                    next = await _workflowApplication.GetNextStepsAsync(delay.WorkflowId, HttpContext.RequestAborted);
                }
                catch (UserFriendlyException e)
                {
                    if (e.Message.Contains("未找到对应节点"))
                    {
                        result.Append("无权审核:" + delay.No);
                        fail++;
                    }
                    else
                    {
                        throw;
                    }
                }

                if (next == null) continue;

                if (!delay.Order.IsProvince)
                {
                    if (next.Steps.Any(x => x.Value == "省审批"))
                    {
                        next.Steps.Remove(next.Steps.First(x => x.Value == "省审批"));
                    }
                }

                if (!_sessionContext.OrgIsCenter && currentStep.Name != "中心初审")
                {
                    if (next.Steps.Any(x => x.Value == "中心终审"))
                    {
                        next.Steps.Remove(next.Steps.First(x => x.Value == "中心终审"));
                    }
                }

                workflow.StepId = next.StepId;
                workflow.ReviewResult = dto.IsPass ? EReviewResult.Approval : EReviewResult.Failed;

                if (workflow.ReviewResult == EReviewResult.Approval)
                {
                    var isBatch = next.Steps.Where(x => x.Value == workflow.NextStepName).Any();
                    if (isBatch)
                    {
                        var step = next.Steps.Where(x => x.Value == workflow.NextStepName).FirstOrDefault();
                        workflow.NextStepCode = step.Key;
                        workflow.NextStepName = step.Value;
                    }
                    else
                    {
                        result.Append("无权审核:" + delay.No);
                        fail++;
                        continue;
                    }

                    await _workflowDomainService.NextAsync(workflow, cancellationToken: HttpContext.RequestAborted);
                }
                else
                {
                    var reject = workflow.Adapt<RejectDto>();
                    await _workflowApplication.RejectAsync(reject, HttpContext.RequestAborted);
                }

                success++;
            }
            catch (UserFriendlyException e)
            {
                result.Append(e.Message);
                fail++;
            }
        }

        return $"总共: {dto.DelayId.Length}, 成功: {success}, 失败: {fail}, 失败原因: {result.ToString()}";
    }

    //[HttpPost("delay/batch_audit")]
    //[LogFilter("批量审批延期")]
    //public async Task<string> BatchAuditDelay([FromBody] BatchDelayNextFlowDto dto)
    //{
    //    var result = new StringBuilder();
    //    var fail = 0;
    //    var success = 0;
    //    var workflowDto = dto.NextWorkflow;
    //    var delays = await _orderDelayRepository.Queryable()
    //        .Includes(x => x.Order)
    //        .Includes(x => x.Workflow, d => d.WorkflowDefinition)
    //        .Includes(x => x.Workflow, d => d.Steps)
    //        .Includes(x => x.Workflow, d => d.Traces)
    //        .Includes(x => x.Workflow, d => d.Countersigns)
    //        .Where(x => dto.DelayId.Contains(x.Id))
    //        .ToListAsync(HttpContext.RequestAborted);

    //    if (!delays.Any())
    //        return string.Empty;

    //    var currentStep = delays.First().Workflow.Steps.FirstOrDefault(d =>
    //        d.Status == EWorkflowStepStatus.WaitForAccept || d.Status == EWorkflowStepStatus.WaitForHandle);

    //    var updateDelays = new List<OrderDelay>();
    //    var updateOrders = new List<Order>();
    //    foreach (var delay in delays)
    //    {
    //        try
    //        {
    //            NextStepsWithOpinionDto<NextStepOption> next = null;

    //            try
    //            {
    //                next = await _workflowApplication.GetNextStepsAsync(delay.Workflow, HttpContext.RequestAborted);
    //            }
    //            catch (UserFriendlyException e)
    //            {
    //                if (e.Message.Contains("未找到对应节点"))
    //                {
    //                    result.Append("无权审核:" + delay.No);
    //                    fail++;
    //                }
    //                else
    //                {
    //                    throw;
    //                }
    //            }

    //            if (next == null) continue;

    //            if (!delay.Order.IsProvince)
    //            {
    //                if (next.Steps.Any(x => x.Value == "省审批"))
    //                {
    //                    next.Steps.Remove(next.Steps.First(x => x.Value == "省审批"));
    //                }
    //            }

    //            if (!_sessionContext.OrgIsCenter && currentStep.Name != "中心初审")
    //            {
    //                if (next.Steps.Any(x => x.Value == "中心终审"))
    //                {
    //                    next.Steps.Remove(next.Steps.First(x => x.Value == "中心终审"));
    //                }
    //            }

    //            workflowDto.StepId = next.StepId;
    //            workflowDto.ReviewResult = dto.IsPass ? EReviewResult.Approval : EReviewResult.Failed;

    //            if (dto.IsPass)
    //            {
    //                var step = next.Steps.FirstOrDefault(x => x.Value == workflowDto.NextStepName);
    //                if (step is null)
    //                {
    //                    result.Append("无权审核:" + delay.No);
    //                    fail++;
    //                    continue;
    //                }

    //                workflowDto.NextStepCode = step.Key;
    //                workflowDto.NextStepName = step.Value;

    //                //处理工单延期
    //                var order = delay.Order;
    //                var expiredTimeBase = DateTime.Now;
    //                if (_appOptions.Value.IsZiGong)
    //                {
    //                    expiredTimeBase = order.ExpiredTime.Value;
    //                }

    //                var startTime = DateTime.Now;
    //                if (order.CenterToOrgTime.HasValue)
    //                {
    //                    startTime = order.CenterToOrgTime!.Value;
    //                }

    //                var expiredTimeConfig =
    //                    await _expireTime.CalcEndTime(expiredTimeBase, startTime, new TimeConfig(delay.DelayNum, delay.DelayUnit),
    //                        order.AcceptTypeCode);
    //                order.ExpiredTime = expiredTimeConfig.ExpiredTime;
    //                order.NearlyExpiredTime = expiredTimeConfig.NearlyExpiredTime;
    //                order.NearlyExpiredTimeOne = expiredTimeConfig.NearlyExpiredTimeOne;
    //                //TODO发送短信即将超期
    //                if (delay.IsProDelay)
    //                {
    //                    order.ExpiredTimeProvince = expiredTimeConfig.ExpiredTime;
    //                }

    //                updateOrders.Add(order);

    //                await _workflowDomainService.NextAsync(delay.Workflow, workflowDto,
    //                    expiredTime: order.ExpiredTime,
    //                    cancellationToken: HttpContext.RequestAborted);

    //                await _workflowDomainService.UpdateUnhandleExpiredTimeAsync(order.WorkflowId, order.ExpiredTime, HttpContext.RequestAborted);

    //                var orderDto = _mapper.Map<OrderDto>(order);
    //                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
    //                    cancellationToken: HttpContext.RequestAborted);
    //            }
    //            else
    //            {
    //                var reject = workflowDto.Adapt<RejectDto>();
    //                await _workflowApplication.RejectAsync(reject, HttpContext.RequestAborted);
    //            }


    //            delay.DelayState = dto.IsPass ? EDelayState.Pass : EDelayState.NoPass;
    //            updateDelays.Add(delay);

    //            success++;
    //        }
    //        catch (UserFriendlyException e)
    //        {
    //            result.Append(e.Message);
    //            fail++;
    //        }
    //    }


    //    await _orderDelayRepository.Updateable(updateDelays)
    //        .UpdateColumns(d => d.DelayState)
    //        .ExecuteCommandAsync(HttpContext.RequestAborted);

    //    await _orderRepository.Updateable(updateOrders)
    //        .UpdateColumns(d => new
    //        {
    //            d.ExpiredTime,
    //            d.NearlyExpiredTime,
    //            d.NearlyExpiredTimeOne,
    //            d.ExpiredTimeProvince
    //        })
    //        .ExecuteCommandAsync(HttpContext.RequestAborted);

    //    return $"总共: {dto.DelayId.Length}, 成功: {success}, 失败: {fail}, 失败原因: {result}";
    //}



    /// <summary>
    ///  延期查询流程办理下一步可选节点
    /// </summary>
    /// <param name="workflowId"></param>
    /// <returns></returns>
    [HttpGet("delay/{workflowId}/nextsteps")]
    public async Task<object> OrderDelayNextsteps(string workflowId)
    {
        //var workflow = await _workflowRepository.GetAsync(workflowId, HttpContext.RequestAborted);
        var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withDefine: true, withSteps: true,
            cancellationToken: HttpContext.RequestAborted);
        var currentStep =
            workflow.Steps.FirstOrDefault(d => d.Status == EWorkflowStepStatus.WaitForAccept || d.Status == EWorkflowStepStatus.WaitForHandle);
        if (workflow != null)
        {
            var orderDelay = await _orderDelayRepository.Queryable().Includes(x => x.Order).Where(x => x.Id == workflow.ExternalId)
                .FirstAsync(HttpContext.RequestAborted);
            if (orderDelay != null)
            {
                var result = await _workflowApplication.GetNextStepsAsync(workflowId, HttpContext.RequestAborted);
                if (!orderDelay.Order.IsProvince)
                {
                    if (result.Steps.Any(x => x.Value == "省审批"))
                    {
                        result.Steps.Remove(result.Steps.First(x => x.Value == "省审批"));
                    }
                }

                if (!_sessionContext.OrgIsCenter && currentStep.Name != "中心初审")
                {
                    if (result.Steps.Any(x => x.Value == "中心终审"))
                    {
                        result.Steps.Remove(result.Steps.First(x => x.Value == "中心终审"));
                    }
                }

                result.IsAlterDay = _appOptions.Value.IsLuZhou && currentStep.Name == "班长审批";
                return result;
            }
        }

        return null;
    }


    /// <summary>
    /// 取消工单延期
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpPost("delay/cancel")]
    [LogFilter("取消工单延期")]
    public async Task CancelDelay([FromBody] CancelDelayDto dto)
    {
        var orderDelay =
            await _orderDelayRepository.GetAsync(x => x.OrderId == dto.Id && x.DelayState == EDelayState.Examining, HttpContext.RequestAborted);
        if (orderDelay != null)
        {
            if (orderDelay.DelayApplyType == EDelayApplyType.ProvinceApply)
            {
                throw UserFriendlyException.SameMessage("当前处于【省平台】审批，无法取消");
            }

            await _workflowDomainService.TerminateAsync(new TerminateDto() { WorkflowId = orderDelay.WorkflowId, Opinion = "" },
                HttpContext.RequestAborted);
            orderDelay.DelayState = EDelayState.Withdraw;
            await _orderDelayRepository.UpdateAsync(orderDelay, HttpContext.RequestAborted);
        }
        else
        {
            throw UserFriendlyException.SameMessage("无效数据");
        }
    }


    /// <summary>
    /// 延期列表
    /// </summary>
    /// <returns></returns>
    [HttpGet("delay")]
    public async Task<PagedDto<OrderDelayDto>> DelayList([FromQuery] DelayListDto dto)
    {
        var (total, items) = await _orderApplication.DelayList(dto)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<OrderDelayDto>(total, _mapper.Map<IReadOnlyList<OrderDelayDto>>(items));
    }

    /// <summary>
    /// 延期列表--导出
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("delay/export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> ExportDelayList([FromBody] ExportExcelDto<DelayListDto> dto)
    {
        var query = _orderApplication.DelayList(dto.QueryDto);
        List<OrderDelay> 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<OrderDelayDto>>(orders);

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderDelayDto>(dto.ColumnInfos);

        var dtos = orderDtos
            .Select(stu => _mapper.Map(stu, typeof(OrderDelayDto), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);
        var excelTitle = "延期列表数据";

        return ExcelStreamResult(stream, excelTitle);
    }

    /// <summary>
    /// 延期待审批
    /// </summary>
    /// <returns></returns>
    [HttpGet("wait_delay")]
    public async Task<PagedDto<OrderDelayDto>> WaitDelayList([FromQuery] DelayListDto dto)
    {
        var (total, items) = await _orderApplication.WaitDelayList(dto)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<OrderDelayDto>(total, _mapper.Map<IReadOnlyList<OrderDelayDto>>(items));
    }

    /// <summary>
    /// 延期待审批--导出
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("wait_delay/export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> ExportWaitDelayList([FromBody] ExportExcelDto<DelayListDto> dto)
    {
        var query = _orderApplication.WaitDelayList(dto.QueryDto);
        List<OrderDelay> 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<OrderDelayDto>>(orders);

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderDelayDto>(dto.ColumnInfos);

        var dtos = orderDtos
            .Select(stu => _mapper.Map(stu, typeof(OrderDelayDto), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);
        var excelTitle = "延期待审批数据";

        return ExcelStreamResult(stream, excelTitle);
    }

    /// <summary>
    /// 延期详情
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("delay/{id}")]
    public async Task<OrderDelayDto> DelayEntity(string id)
    {
        var model = await _orderDelayRepository.Queryable()
            .Includes(d => d.Order)
            .Includes(d => d.Workflow, x => x.Steps)
            .FirstAsync(d => d.Id == id);
        var rspModel = _mapper.Map<OrderDelayDto>(model);
        //rspModel.IsCanHandle = model.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
        rspModel.IsCanHandle = model.Workflow?.IsCanHandle(
            _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles) ?? false;
        rspModel.Handle = false;
        if (!string.IsNullOrEmpty(rspModel.WorkflowId))
        {
            rspModel.Handle = await _workflowDomainService.CheckCurrentIsStartStepAsync(rspModel.WorkflowId, _sessionContext.RequiredUserId,
                _sessionContext.RequiredOrgId, HttpContext.RequestAborted);
        }

        if (rspModel.FileJson != null && rspModel.FileJson.Any())
        {
            var ids = rspModel.FileJson.Select(x => x.Id).ToList();
            rspModel.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
        }

        return rspModel;
    }

    /// <summary>
    /// 计算期满时间
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("delay/calc-endtime")]
    public async Task<TimeResult?> DelayCalcEndTime([FromBody] DelayCalcEndTimeDto dto)
    {
        if (dto.BeginTime.HasValue)
        {
            // return _timeLimitDomainService.CalcEndTime(dto.BeginTime.Value, dto.DelayUnit, dto.DelayNum, 0, 0);
            return await _expireTime.CalcEndTime(dto.BeginTime.Value, dto.BeginTime.Value, dto.DelayUnit, dto.DelayNum, 0, 0);
        }

        return null;
    }

    /// <summary>
    /// 查询工单延期流程开启参数
    /// </summary>
    /// <returns></returns>
    [HttpGet("delay/startflow")]
    public async Task<NextStepsDto> GetDelayFlowStartOptions()
    {
        var result = await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.OrderDelay,
            HttpContext.RequestAborted);
        if (_sessionContext.OrgIsCenter)
        {
            if (result.Steps.Any(x => x.Value == "中心初审"))
            {
                result.Steps.Remove(result.Steps.First(x => x.Value == "中心初审"));
            }
        }
        else
        {
            if (result.Steps.Any(x => x.Value == "中心终审"))
            {
                result.Steps.Remove(result.Steps.First(x => x.Value == "中心终审"));
            }
        }

        return result;
    }

    /// <summary>
    /// 延期页面基础信息
    /// </summary>
    /// <returns></returns>
    [HttpGet("delay/basedata")]
    public async Task<object> DelayBaseData()
    {
        var delayStatisticalNodes = _systemSettingCacheManager.GetSetting(SettingConstants.DelayStatisticalNodes).SettingValue;
        var delayStatisticalNodesList = new List<Kv>();
        if (delayStatisticalNodes != null && delayStatisticalNodes.Any())
        {
            foreach (var item in delayStatisticalNodes)
            {
                delayStatisticalNodesList.Add(new Kv
                {
                    Key = item,
                    Value = item
                });
            }
        }
        var rsp = new
        {
            DelayStatisticalNodes = delayStatisticalNodesList,
            DelayState = EnumExts.GetDescriptions<EDelayState>(),
            QueryDelayState = EnumExts.GetDescriptions<EQueryDelayState>(),
            TimeType = EnumExts.GetDescriptions<ETimeType>(),
            AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType),
            ChannelOptions = _sysDicDataCacheManager.GetSysDicDataCache(TimeLimitBaseDataConsts.SourceChannel),
        };
        return rsp;
    }

    /// <summary>
    /// 自动延期写入
    /// </summary>
    /// <returns></returns>
    [HttpPost("delay/automatic")]
    [AllowAnonymous]
    public async Task OrderDelayAutomatic()
    {

        await _orderApplication.OrderDelayAutomatic();

        await _orderApplication.OrderDelayAutomaticHandle(EOrderDelayAutomaticType.Automatic);

        await _orderApplication.OrderDelayAutomaticHandle(EOrderDelayAutomaticType.Sms);
    }

    ///// <summary>
    ///// 延期短信执行
    ///// </summary>
    ///// <param name="type"></param>
    ///// <returns></returns>
    //[HttpPost("delay/automatic/handle/sms")]
    //[AllowAnonymous]
    //public async Task OrderDelayAutomaticHandleSms()
    //{
    //	await _orderApplication.OrderDelayAutomaticHandle(EOrderDelayAutomaticType.Sms);
    //}
    ///// <summary>
    ///// 自动延期执行
    ///// </summary>
    ///// <param name="type"></param>
    ///// <returns></returns>
    //[HttpPost("delay/automatic/handle")]
    //[AllowAnonymous]
    //public async Task OrderDelayAutomaticHandleAutomatic()
    //{
    //	await _orderApplication.OrderDelayAutomaticHandle(EOrderDelayAutomaticType.Automatic);
    //}


    #endregion

    #region 工单甄别

    /// <summary>
    /// 工单甄别待申请列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("mayscreen")]
    public async Task<PagedDto<OrderVisitDetailDto>> MayScreenList([FromQuery] MayScreenListDto dto)
    {
        if (_appOptions.Value.IsYiBin) dto.ScreenType = EOrderScreenType.Org;

        dto.CreationTimeEnd = DateTime.Now;
        dto.CreationTimeStart = DateTime.Now;
        if (dto.IsHomePage != null && dto.IsHomePage == true)
        {
            // dto.CreationTimeStart = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5);
            dto.CreationTimeStart = await _expireTime.CalcWorkTimeReduce(DateTime.Now, 5);
        }

        var (total, items) = await _orderApplication.MayScreenList(dto)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        var data = _mapper.Map<List<OrderVisitDetailDto>>(items);
        var isAdmin = _orderDomainService.IsCheckAdmin();
        data.ForEach(d => d.IsShowOperate = (dto.ScreenType == EOrderScreenType.Org && d.VisitOrgCode == _sessionContext.OrgId)
                                            || isAdmin == true || (dto.ScreenType == EOrderScreenType.Seat));
        return new PagedDto<OrderVisitDetailDto>(total, data);
    }

    /// <summary>
    /// 工单甄别待申请列表导出
    /// </summary>
    /// <returns></returns>
    [HttpPost("mayscreen/_export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> ScreenListExport([FromBody] ExportExcelDto<MayScreenListDto> dto)
    {
        if (_appOptions.Value.IsYiBin) dto.QueryDto.ScreenType = EOrderScreenType.Org;

        dto.QueryDto.CreationTimeEnd = DateTime.Now;
        dto.QueryDto.CreationTimeStart = DateTime.Now;
        if (dto.QueryDto.IsHomePage != null && dto.QueryDto.IsHomePage == true)
        {
            // dto.CreationTimeStart = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5);
            dto.QueryDto.CreationTimeStart = await _expireTime.CalcWorkTimeReduce(DateTime.Now, 5);
        }

        var query = _orderApplication.MayScreenList(dto.QueryDto);
        List<OrderVisitDetail> 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<OrderVisitDetailDto>>(data);

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderVisitDetailDto>(dto.ColumnInfos);

        var dtos = dataDtos
            .Select(stu => _mapper.Map(stu, typeof(OrderVisitDetailDto), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);

        return ExcelStreamResult(stream, "工单甄别待申请列表数据");
    }


    /// <summary>
    /// 工单甄别列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("screen")]
    public async Task<PagedDto<OrderScreenListDto>> ScreenList([FromQuery] ScreenListDto dto)
    {
        var (total, items) = await _orderApplication.OrderScreenList(dto)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderScreenListDto>(total, _mapper.Map<IReadOnlyList<OrderScreenListDto>>(items));
    }


    /// <summary>
    /// 工单甄别列表导出
    /// </summary>
    /// <returns></returns>
    [HttpPost("screen_list/_export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> ScreenListExport([FromBody] ExportExcelDto<ScreenListDto> dto)
    {
        var query = _orderApplication.OrderScreenList(dto.QueryDto);
        List<OrderScreen> 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<OrderScreenListDto>>(data);

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderScreenListDto>(dto.ColumnInfos);

        var dtos = dataDtos
            .Select(stu => _mapper.Map(stu, typeof(OrderScreenListDto), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);

        return ExcelStreamResult(stream, "工单甄别数据");
    }


    /// <summary>
    /// 开始工单甄别流程
    /// </summary>
    [HttpPost("screen/startflow")]
    [LogFilter("开始工单甄别流程")]
    public async Task StartFlow([FromBody] StartWorkflowDto<OrderScreenDto> dto)
    {
        var screenAny = await _orderScreenRepository.AnyAsync(x =>
            x.VisitDetailId == dto.Data.VisitDetailId && x.ScreenType == dto.Data.ScreenType &&
            (x.Status == EScreenStatus.Apply || x.Status == EScreenStatus.Approval));
        if (screenAny)
            throw UserFriendlyException.SameMessage("该工单已提起甄别申请，正在审批过程中，不能申请");

        var isNoPass = await _orderScreenRepository.AnyAsync(x =>
            x.Status == EScreenStatus.Refuse && x.ScreenType == dto.Data.ScreenType && x.VisitDetailId == dto.Data.VisitDetailId);
        if (isNoPass)
            throw UserFriendlyException.SameMessage("该工单已被拒绝过甄别申请，不能再次申请");

        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.ScreenApplyNum);
        int count = await _orderScreenRepository.CountAsync(x =>
            x.OrderId == dto.Data.OrderId && x.Status == EScreenStatus.Refuse && x.ScreenType == dto.Data.ScreenType &&
            x.VisitDetailId == dto.Data.VisitDetailId);
        if (count > int.Parse(setting?.SettingValue[0]) && int.Parse(setting?.SettingValue[0]) > -1)
            throw UserFriendlyException.SameMessage("甄别申请已超过系统预定设置，不能申请");

        var visit = await _orderVisitRepository.GetAsync(dto.Data.VisitId, HttpContext.RequestAborted);
        setting = _systemSettingCacheManager.GetSetting(SettingConstants.ScreenApplyEndTime);
        if (int.Parse(setting?.SettingValue[0]) > 0)
        {
            var visitDetail = await _orderVisitedDetailRepository.GetAsync(dto.Data.VisitDetailId, HttpContext.RequestAborted);
            if (visitDetail.ScreenByEndTime.HasValue)
            {
                if (DateTime.Now > visitDetail.ScreenByEndTime && !_sessionContext.OrgIsCenter)
                {
                    var mes = "超过截至甄别时间不能申请甄别！";
                    mes = _appOptions.Value.IsLuZhou ? "回访完成的次月第一个工作日后不能再申请甄别！" : mes;
                    throw UserFriendlyException.SameMessage(mes);
                }
            }
        }

        var order = await _orderRepository.GetAsync(dto.Data.OrderId, HttpContext.RequestAborted);
        if (order.IsProvince)
        {
            var orderAny = await _orderScreenRepository.AnyAsync(x =>
                x.OrderId == dto.Data.OrderId &&
                (x.Status == EScreenStatus.Apply || x.Status == EScreenStatus.Approval));
            if (orderAny)
            {
                throw UserFriendlyException.SameMessage("当前工单为省工单,已发起甄别申请,请等待省上返回结果！");
            }
        }

        var model = _mapper.Map<OrderScreen>(dto.Data);
        model.Status = EScreenStatus.Approval;
        //model.ApplyEndTime = endTime;
        // model.TimeConsuming = _timeLimitDomainService.CalcWorkTimeToDecimal(visit.VisitTime.Value, DateTime.Now, false);
        model.TimeConsuming = await _expireTime.CalcWorkTimeToDecimal(visit.VisitTime.Value, DateTime.Now, false);
        model.InitId();
        if (dto.Data.Files.Any())
            model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted);
        else
            model.FileJson = new List<Share.Dtos.File.FileJson>();
        await _orderScreenRepository.AddAsync(model, HttpContext.RequestAborted);

        var workflowId = string.Empty;
        try
        {
            //二次回访会改写数据
            //await _orderRepository.OrderScreenRevisionVisit(visit.Id, false, HttpContext.RequestAborted);
            var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
            startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderScreen;
            startDto.Opinion = dto.Data.Content;
            startDto.Title = "申请甄别流程";
            //workflowId = await _workflowApplication.StartWorkflowAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
            //await _workflowDomainService.StartAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
            await _workflowDomainService.StartToFirstStepAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
        }
        catch (Exception e)
        {
            await _orderScreenRepository.RemoveAsync(model.Id);
            model.Id = string.Empty;
            throw new UserFriendlyException($"工单开启甄别流程失败!, {e.Message}", "工单开启甄别流程失败");
        }
    }


    /// <summary>
    /// 工单甄别修改后下一步流程
    /// </summary>
    [HttpPost("screen/initial_nextFlow")]
    [LogFilter("办理工单甄别流程")]
    public async Task InitialNextFlow([FromBody] ScreenNextFlowDto dto)
    {
        var screen = await _orderScreenRepository.GetAsync(dto.Data.Id);
        var visitDetail = await _orderVisitedDetailRepository.GetAsync(screen.VisitDetailId, HttpContext.RequestAborted);
        if (_appOptions.Value.IsZiGong && visitDetail.ScreenByEndTime.HasValue)
        {
            if (DateTime.Now > visitDetail.ScreenByEndTime && !_sessionContext.OrgIsCenter)
            {
                throw UserFriendlyException.SameMessage("超过2个工作日不能申请甄别，不能申请");
            }
        }


        if (dto.Data.Files.Any())
            screen.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, screen.Id, "", HttpContext.RequestAborted);
        else
            screen.FileJson = new List<Share.Dtos.File.FileJson>();

        screen.Content = dto.Data.Content;
        screen.TypeDicId = dto.Data.TypeDicId;
        screen.TypeDicName = dto.Data.TypeDicName;
        screen.SendBackApply = false;
        screen.SendBackApplyNum++;
        await _orderScreenRepository.UpdateAsync(screen, HttpContext.RequestAborted);
        try
        {
            dto.NextWorkflow.WorkflowId = screen.WorkflowId;
            //await _workflowApplication.NextAsync(dto.NextWorkflow, cancellationToken: HttpContext.RequestAborted);
            await _workflowDomainService.NextAsync(dto.NextWorkflow, cancellationToken: HttpContext.RequestAborted);
        }
        catch (Exception e)
        {
            throw new UserFriendlyException($"工单甄别下一步流程失败!, {e.Message}", "工单甄别下一步流程失败");
        }
    }

    /// <summary>
    /// 查询工单甄别流程开启参数
    /// </summary>
    /// <returns></returns>
    [HttpGet("screen/startflow")]
    public async Task<NextStepsDto> GetScreenFlowStartOptionsAsync()
    {
        //return await _workflowApplication.GetStartOptionsAsync(WorkflowModuleConsts.OrderScreen,
        //    HttpContext.RequestAborted);
        var result = await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.OrderScreen,
            HttpContext.RequestAborted);
        if (_sessionContext.OrgIsCenter)
        {
            if (result.Steps.Any(x => x.Value == "中心初审"))
            {
                result.Steps.Remove(result.Steps.First(x => x.Value == "中心初审"));
            }
        }
        else
        {
            if (result.Steps.Any(x => x.Value == "中心班长"))
            {
                result.Steps.Remove(result.Steps.First(x => x.Value == "中心班长"));
            }
        }

        return result;
    }

    /// <summary>
    /// 查询工单甄别流程参数
    /// </summary>
    /// <returns></returns>
    [HttpGet("screen/workflow/{id}")]
    public async Task<string> GetScreenWorkFlowAsync(string id)
    {
        var workflow = await _workflowRepository.Queryable().FirstAsync(x => x.ExternalId == id);
        return workflow.Id;
    }

    /// <summary>
    ///  甄别查询流程办理下一步可选节点
    /// </summary>
    /// <param name="workflowId"></param>
    /// <returns></returns>
    [HttpGet("screen/{workflowId}/nextsteps")]
    public async Task<NextStepsDto> OrderScreenNextsteps(string workflowId)
    {
        var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withDefine: true, withSteps: true,
            cancellationToken: HttpContext.RequestAborted);
        var currentStep =
            workflow.Steps.FirstOrDefault(d => d.Status == EWorkflowStepStatus.WaitForAccept || d.Status == EWorkflowStepStatus.WaitForHandle);
        if (workflow != null)
        {
            var orderScreen = await _orderScreenRepository.Queryable().Includes(x => x.Order).Where(x => x.Id == workflow.ExternalId)
                .FirstAsync(HttpContext.RequestAborted);
            if (orderScreen != null)
            {
                var result = await _workflowApplication.GetNextStepsAsync(workflowId, HttpContext.RequestAborted);
                if (!orderScreen.Order.IsProvince)
                {
                    if (result.Steps.Any(x => x.Value == "省审批"))
                    {
                        result.Steps.Remove(result.Steps.First(x => x.Value == "省审批"));
                    }
                }

                if (!_sessionContext.OrgIsCenter)
                {
                    if (result.Steps.Any(x => x.Value == "中心班长"))
                    {
                        result.Steps.Remove(result.Steps.First(x => x.Value == "中心班长"));
                    }
                }

                result.IsPickFile = _appOptions.Value.IsYiBin && currentStep.Name == "中心领导";
                return result;
            }
        }

        return null;
    }

    /// <summary>
    /// 列表页面基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("screen/base")]
    public async Task<object> ScreenBaseData()
    {
        var screenStatisticalNodes = _systemSettingCacheManager.GetSetting(SettingConstants.ScreenStatisticalNodes).SettingValue;
        var screenStatisticalNodesList = new List<Kv>();
        if (screenStatisticalNodes != null && screenStatisticalNodes.Any())
        {
            foreach (var item in screenStatisticalNodes)
            {
                screenStatisticalNodesList.Add(new Kv
                {
                    Key = item,
                    Value = item
                });
            }
        }

        var rsp = new
        {
            ScreenStatus = EnumExts.GetDescriptions<EScreenStatus>(),
            OrderScreenType = EnumExts.GetDescriptions<EOrderScreenType>(),
            QueryScreenType = EnumExts.GetDescriptions<EQueryOrderScreenType>(),
            ScreenType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ScreenType),
            CounterSignType = EnumExts.GetDescriptions<ECounterSignType>(),
            AcceptType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType),
            SourceChannel = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SourceChannel),
            VisitSatisfaction = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction),
            DissatisfiedReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.DissatisfiedReason),
            ScreenStatisticalNodes = screenStatisticalNodesList,
        };
        return rsp;
    }

    /// <summary>
    /// 甄别详情
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("screen/{id}")]
    public async Task<OrderScreenListDto> ScreenEntity(string id)
    {
        var model = await _orderScreenRepository.Queryable(canView: false)
            .Includes(x => x.Order)
            .Includes(x => x.VisitDetail)
            .Includes(x => x.Workflow, d => d.Steps)
            .Includes(x => x.Visit, d => d.Order)
            .FirstAsync(x => x.Id == id);
        var rspModel = _mapper.Map<OrderScreenListDto>(model);
        //rspModel.IsCanHandle = model.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
        rspModel.IsCanHandle = model.Workflow?.IsCanHandle(
            _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles) ?? false;
        if (model.Status == EScreenStatus.SendBack && model.SendBackApply)
            rspModel.IsCanHandle = false;
        rspModel.Handle = false;
        if (!string.IsNullOrEmpty(rspModel.WorkflowId))
        {
            rspModel.Handle = await _workflowDomainService.CheckCurrentIsStartStepAsync(rspModel.WorkflowId, _sessionContext.RequiredUserId,
                _sessionContext.RequiredOrgId, HttpContext.RequestAborted);
        }

        if (rspModel.FileJson != null && rspModel.FileJson.Any())
        {
            var ids = rspModel.FileJson.Select(x => x.Id).ToList();
            rspModel.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
        }

        return rspModel;
    }

    /// <summary>
    /// 甄别详情
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("screen/visitdetail/{id}")]
    public async Task<OrderScreenListDto> VisitDetailScreenEntity(string id)
    {
        var model = await _orderScreenRepository.Queryable(canView: false)
            .Includes(x => x.Order)
            .Includes(x => x.Workflow, d => d.Steps)
            .Includes(x => x.Visit, d => d.Order)
            .FirstAsync(x => x.VisitDetailId == id);
        var rspModel = _mapper.Map<OrderScreenListDto>(model);
        //rspModel.IsCanHandle = model.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
        rspModel.IsCanHandle = model.Workflow?.IsCanHandle(
            _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles) ?? false;
        if (model.Status == EScreenStatus.SendBack && model.SendBackApply)
            rspModel.IsCanHandle = false;
        rspModel.Handle = false;
        if (!string.IsNullOrEmpty(rspModel.WorkflowId))
        {
            rspModel.Handle = await _workflowDomainService.CheckCurrentIsStartStepAsync(rspModel.WorkflowId, _sessionContext.RequiredUserId,
                _sessionContext.RequiredOrgId, HttpContext.RequestAborted);
        }

        if (rspModel.FileJson != null && rspModel.FileJson.Any())
        {
            var ids = rspModel.FileJson.Select(x => x.Id).ToList();
            rspModel.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
        }

        return rspModel;
    }

    /// <summary>
    /// 更新甄别提起截至时限
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut("order_screen_endtime")]
    [LogFilter("更新甄别提起截至时限")]
    public async Task Update([FromBody] OrderScreenEndTimeDto dto)
    {
        await _orderVisitedDetailRepository.Updateable().SetColumns(x => new OrderVisitDetail { ScreenByEndTime = dto.ScreenByEndTime })
            .Where(x => x.Id == dto.Id).ExecuteCommandAsync();
    }

    /// <summary>
    /// 更新甄别信息
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut("order_screen_alter")]
    [LogFilter("更新甄别信息")]
    public async Task Update([FromBody] OrderScreenAlterDto dto)
    {
        var screen = await _orderScreenRepository.GetAsync(dto.ScreenId);
        //var FileJson = new List<Share.Dtos.File.FileJson>();
        //      if (dto.Files.Any())
        //          FileJson = await _fileRepository.AddFileAsync(dto.Files, dto.ScreenId, "", HttpContext.RequestAborted);
        //      else
        //          FileJson = screen.FileJson;
        dto.Content = string.IsNullOrEmpty(dto.Content) ? screen.Content : dto.Content;
        await _orderScreenRepository.Updateable().SetColumns(x => new OrderScreen { Content = dto.Content })
            .Where(x => x.Id == dto.ScreenId).ExecuteCommandAsync();
    }

    /// <summary>
    /// 获取工单甄别所有文件
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("screen/all_file/{id}")]
    public async Task<List<FileDto>> GetOrderScreenAllFile(string id)
    {
        var screen = await _orderScreenRepository.GetAsync(id);
        var steps = await _workflowStepRepository.Queryable().Where(x => x.WorkflowId == screen.WorkflowId).ToListAsync();
        var allFiles = new List<FileDto>();
        //if (screen != null)
        //{
        //    var ids = screen.FileJson.Select(x => x.Id).ToList();
        //    allFiles = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
        //}
        foreach (var step in steps)
        {
            if (step.FileJson != null && step.FileJson.Any())
            {
                var ids = step.FileJson.Select(x => x.Id).ToList();
                var stepFiles = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
                allFiles.AddRange(stepFiles);
            }
        }

        return allFiles;
    }

    /// <summary>
    /// 甄别审批办理
    /// </summary>
    [HttpPost("screen/next")]
    [LogFilterAlpha("甄别审批办理")]
    public async Task Next([FromBody] OrderScreenNextWorkflowDto dto)
    {
        if (dto.ProvinceFiles.Any())
        {
            var fileJson = await _fileRepository.AddFileAsync(dto.ProvinceFiles, dto.ScreenId, HttpContext.RequestAborted);
            await _orderScreenRepository.Updateable().SetColumns(x => new OrderScreen { ProvinceFileJson = fileJson })
                .Where(x => x.Id == dto.ScreenId).ExecuteCommandAsync(HttpContext.RequestAborted);
        }

        await _workflowDomainService.NextAsync(dto, cancellationToken: HttpContext.RequestAborted);
    }

    /// <summary>
    /// 甄别审批退回（返回前一节点）
    /// </summary>
    [HttpPost("screen/previous")]
    [LogFilterAlpha("甄别审批退回")]
    public async Task Previous([FromBody] PreviousWorkflowDto dto)
    {
        /*
         *甄别退回到最开始节点到部门 todo 重构放在调用处判断
           if (workflow.FlowType == EFlowType.Review && workflow.ModuleCode == WorkflowModuleConsts.OrderScreen)
           {
            newPrevStep.FlowAssignType = newPrevStep.StepType == EStepType.Start ? EFlowAssignType.Org : prevStep.FlowAssignType;
           }
         */

        if (_appOptions.Value.IsZiGong)
        {
            //退回至申请人
            if (dto.IsRecallToStartStep)
            {
                await _workflowDomainService.RecallToStartStepAsync(dto.WorkflowId, dto.Opinion, null, false, EHandleMode.Previous, EFlowAssignType.Org,
                    cancellationToken: HttpContext.RequestAborted);

                var orderScreen = await _orderScreenRepository.GetAsync(p => p.WorkflowId == dto.WorkflowId, cancellationToken: HttpContext.RequestAborted);
                if (orderScreen != null)
                {
                    orderScreen.Status = EScreenStatus.SendBack;
                    orderScreen.SendBackApply = true;
                    await _orderScreenRepository.UpdateAsync(orderScreen, cancellationToken: HttpContext.RequestAborted);

                    //自贡任务 220 修改甄别截止申请日期的计算方式
                    //甄别截止申请日期=回访时间+2个工作日  ，若退回到申请人节点，甄别截止申请日期=退回时间+2个工作日
                    var orderVisitDetail = await _orderVisitedDetailRepository.GetAsync(p => p.Id == orderScreen.VisitDetailId, cancellationToken: HttpContext.RequestAborted);
                    if (orderVisitDetail != null)
                    {
                        orderVisitDetail.ScreenByEndTime = (await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, ETimeType.WorkDay, 2, 0, 0)).EndTime;
                        await _orderVisitedDetailRepository.UpdateAsync(orderVisitDetail, cancellationToken: HttpContext.RequestAborted);
                    }
                }
            }
            else
            {
                await _workflowDomainService.PreviousAsync(dto,
                    newStepConfig: (workflow, currentStep, prevStepDefine, prevStep, newPrevStep) =>
                    {
                        if (prevStepDefine.BusinessType is EBusinessType.Department)
                        {
                            newPrevStep.FlowAssignType = EFlowAssignType.Org;
                        }
                        else if (prevStepDefine.HandlerType is EHandlerType.Role)
                        {
                            newPrevStep.Assign(
                                new StepAssignInfo
                                {
                                    FlowAssignType = EFlowAssignType.Role,
                                    RoleId = prevStepDefine.HandlerTypeItems[0].Key,
                                    RoleName = prevStepDefine.HandlerTypeItems[0].Value
                                });
                        }
                        else
                        {
                            newPrevStep.FlowAssignType = prevStep.FlowAssignType;
                        }
                    },
                    cancellationToken: HttpContext.RequestAborted);
            }
        }
        else
        {
            await _workflowDomainService.PreviousAsync(dto,
                newStepConfig: (workflow, currentStep, prevStepDefine, prevStep, newPrevStep) =>
                {
                    newPrevStep.FlowAssignType = prevStepDefine.BusinessType is EBusinessType.Department
                        ? EFlowAssignType.Org
                        : prevStep.FlowAssignType;
                },
                cancellationToken: HttpContext.RequestAborted);
        }
    }

    #endregion

    #region 工单督办

    /// <summary>
    /// 工单督办列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("supervise")]
    public async Task<PagedDto<SuperviseOrderDto>> SuperviseList([FromQuery] SuperviseListDto dto)
    {
        var (total, items) = await _orderSuperviseRepository.Queryable()
            .Includes(x => x.Order)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Order.Title.Contains(dto.Keyword!) || x.Order.No.Contains(dto.Keyword!))
            .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.Order.No.Contains(dto.No))                                //工单编号
            .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, x => x.Order.IsProvince == true)   //是否省工单
            .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == false, x => x.Order.IsProvince == false)
            .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Order.Title.Contains(dto.Title))                       //工单标题
            .WhereIF(!string.IsNullOrEmpty(dto.Channel), x => x.Order.SourceChannelCode == dto.Channel)              //来源渠道
            .WhereIF(dto.Status.HasValue, x => x.Order.Status == dto.Status)                                         //工单状态
            .WhereIF(!string.IsNullOrEmpty(dto.AcceptTypeCode), x => x.Order.AcceptTypeCode == dto.AcceptTypeCode)   //受理类型
            .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), x => x.Order.HotspotSpliceName != null && x.Order.HotspotSpliceName.Contains(dto.Hotspot)) //热点
            .WhereIF(!string.IsNullOrEmpty(dto.AcceptorName), x => x.Order.AcceptorName == dto.AcceptorName!)        //受理人
            .WhereIF(!string.IsNullOrEmpty(dto.CurrentHandleOrgName), x => x.Order.CurrentHandleOrgName.Contains(dto.CurrentHandleOrgName)) //接办部门
            .WhereIF(dto.ExpiredTimeStart.HasValue, x => x.Order.ExpiredTime >= dto.ExpiredTimeStart)                //期满时间Start
            .WhereIF(dto.ExpiredTimeEnd.HasValue, x => x.Order.ExpiredTime <= dto.ExpiredTimeEnd)                    //期满时间End
            .WhereIF(dto.SuperviseTimeStart.HasValue, x => x.CreationTime >= dto.SuperviseTimeStart)                 //督办时间Start
            .WhereIF(dto.SuperviseTimeEnd.HasValue, x => x.CreationTime <= dto.SuperviseTimeEnd)                     //督办时间End
            .WhereIF(dto.ReplyLimitTimeStart.HasValue, x => x.ReplyLimitTime >= dto.ReplyLimitTimeStart)             //督办回复时限Start
            .WhereIF(dto.ReplyLimitTimeEnd.HasValue, x => x.ReplyLimitTime <= dto.ReplyLimitTimeEnd)                 //督办回复时限End
            .WhereIF(!string.IsNullOrEmpty(dto.CrUser), x => x.CrUser.Contains(dto.CrUser))                          //督办人
            .WhereIF(!string.IsNullOrEmpty(dto.LaunchOrgName), x => x.LaunchOrgName.Contains(dto.LaunchOrgName))     //督办部门
            .WhereIF(!string.IsNullOrEmpty(dto.ApplyContent), x => x.ApplyContent.Contains(dto.ApplyContent))        //督办意见
            .WhereIF(dto.SuperviseState > -1, x => x.State == dto.SuperviseState)                                    //督办状态
            .WhereIF(dto.CreationTimeStart.HasValue, x => x.Order.CreationTime >= dto.CreationTimeStart)             //受理时间Start
            .WhereIF(dto.CreationTimeEnd.HasValue, x => x.Order.CreationTime <= dto.CreationTimeEnd)                 //受理时间End
            .WhereIF(dto.ReplyTimeStart.HasValue, x => x.ReplyTime >= dto.ReplyTimeStart)                            //督办回复时间Start
            .WhereIF(dto.ReplyTimeEnd.HasValue, x => x.ReplyTime <= dto.ReplyTimeEnd)                                //督办回复时间End
            .WhereIF(!string.IsNullOrEmpty(dto.ReplyContent), x => x.ReplyContent.Contains(dto.ReplyContent))        //督办回复内容
            .WhereIF(dto.SignTimeStart.HasValue, x => x.SignTime >= dto.SignTimeStart)                               //督办签收时间Start
            .WhereIF(dto.SignTimeEnd.HasValue, x => x.SignTime <= dto.SignTimeEnd)                                   //督办签收时间End
            .Where(x => x.OrgId == _sessionContext.OrgId)
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<SuperviseOrderDto>(total, _mapper.Map<IReadOnlyList<SuperviseOrderDto>>(items));
    }

    /// <summary>
    /// 督办查询部门经办人手机号
    /// </summary>
    /// <param name="orgCode"></param>
    /// <returns></returns>
    [HttpGet("supervise/geturgetel/{orgCode}")]
    public async Task<Kv> GetUrgeTel(string orgCode)
    {
        Kv k = new Kv();
        var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
        //查询部门所有账号
        var userlist = await _userRepository.Queryable().Where(x =>
            x.OrgId == orgCode && !string.IsNullOrEmpty(x.PhoneNo)).ToListAsync();
        if (userlist != null && userlist.Count > 0)
        {
            k.Key = userlist[0].Name;
            k.Value = userlist[0].PhoneNo;
        }

        return k;
    }

    /// <summary>
    /// 旅游列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("supervise/travel")]
    public async Task<IReadOnlyList<OrderDto>> QueryTravel([FromQuery] QueryOrderDto dto)
    {
        var orders = await _orderApplication.QueryTravel(dto)
            .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted);

        orders.ForEach(x =>
        {
            if (x.OrderVisits != null && x.OrderVisits.Count > 0)
            {
                x.OrgProcessingResults = x.OrderVisits[0].NowEvaluate;
            }
            else
            {
                x.OrgProcessingResults = null;
            }
        });

        var list = _mapper.Map<IReadOnlyList<OrderDto>>(orders);
        if (_appOptions.Value.IsLuZhou && !_sessionContext.OrgIsCenter)
            list = list.Select(p => p.DataMask(false)).ToList();

        return list;
    }

    /// <summary>
    /// 旅游列表查询总数
    /// </summary>
    [HttpGet("supervise/travel/count")]
    public async Task<int> QueryTravelCount([FromQuery] QueryOrderDto dto)
    {
        var query = _orderApplication.QueryTravel(dto);
        return await query.CountAsync(HttpContext.RequestAborted);
    }

    [HttpPost("supervise/travel/export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> ExportTravel([FromBody] ExportExcelDto<QueryOrderDto> dto)
    {
        var query = _orderApplication.QueryTravel(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;
        }

        orders.ForEach(x =>
        {
            if (x.OrderVisits != null && x.OrderVisits.Count > 0)
            {
                x.OrgProcessingResults = x.OrderVisits[0].NowEvaluate;
            }
            else
            {
                x.OrgProcessingResults = null;
            }
        });

        var orderDtos = _mapper.Map<ICollection<OrderDto>>(orders);

        if (_appOptions.Value.IsLuZhou)
            orderDtos = orderDtos.Select(p => p.DataMask(false)).ToList();

        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>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("supervise/apply")]
    [LogFilter("新增工单督办")]
    public async Task ApplySupervise([FromBody] ApplyOrderSuperviseDto dto)
    {
        if (!dto.SuperviseOrgDtos.Any())
            throw UserFriendlyException.SameMessage("请选择被督办部门");
        //验证工单是否可以申请
        var order = await _orderRepository.GetAsync(dto.OrderId, HttpContext.RequestAborted);
        if (order is null)
            throw UserFriendlyException.SameMessage("无效工单");

        foreach (var item in dto.SuperviseOrgDtos)
        {
            var model = _mapper.Map<OrderSupervise>(dto);
            model.OrgId = item.OrgId;
            model.OrgName = item.OrgName;
            model.LaunchOrgName = _sessionContext.OrgName;
            model.CrUser = _sessionContext.UserName;
            model.State = 0;
            model.InitId();
            if (dto.Files.Any())
                model.FileJson =
                    await _fileRepository.AddFileAsync(dto.Files, model.Id, "", HttpContext.RequestAborted);
            await _orderSuperviseRepository.AddAsync(model, HttpContext.RequestAborted);

            if (dto.AcceptSms)
            {
                //发送短信
                try
                {
                    if (string.IsNullOrEmpty(dto.PhoneNo))
                    {
                        #region 普通督办短信内容

                        var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
                        //查询部门所有账号
                        var userlist = await _userRepository.Queryable().Where(x =>
                            x.OrgId == model.OrgId && !string.IsNullOrEmpty(x.PhoneNo) &&
                            x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
                        //发送短信
                        foreach (var user in userlist)
                        {
                            var messageDto = new Share.Dtos.Push.MessageDto
                            {
                                PushBusiness = EPushBusiness.OrderSupervise,
                                ExternalId = order.Id,
                                OrderId = order.Id,
                                PushPlatform = EPushPlatform.Sms,
                                Remark = order.Title,
                                Name = user.Name,
                                TemplateCode = "1003",
                                Params = new List<string>() { order.No },
                                TelNumber = user.PhoneNo,
                            };
                            await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
                        }

                        #endregion
                    }
                    else
                    {
                        #region 旅游督办短信内容

                        //var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
                        //查询部门所有账号
                        //var userlist = await _userRepository.Queryable().Where(x =>
                        //    x.OrgId == model.OrgId && x.PhoneNo == dto.PhoneNo &&
                        //    x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();

                        var Contact = !string.IsNullOrEmpty(order.FromPhone) ? order.FromPhone : order.Contact;

                        //发送短信
                        var messageDto = new Share.Dtos.Push.MessageDto
                        {
                            PushBusiness = EPushBusiness.OrderSupervise,
                            ExternalId = order.Id,
                            OrderId = order.Id,
                            PushPlatform = EPushPlatform.Sms,
                            Remark = order.Title,
                            Name = dto.PhoneNo,//userlist[0].Name,
                            TemplateCode = "1022",
                            Params = new List<string>() { dto.ApplyContent, order.No, Contact, order.Content },
                            TelNumber = dto.PhoneNo,
                        };
                        await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);

                        #endregion
                    }
                }
                catch
                {
                }
            }

            var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0];
            CityBaseConfiguration cityBase = JsonSerializer.Deserialize<CityBaseConfiguration>(setting);
            //推省上
            if (!string.IsNullOrEmpty(model.Id) &&
                (cityBase.CityProvince.OrgId.Equals(model.OrgId) || cityBase.CityProvinceAssign.OrgId.Equals(model.OrgId)))
            {
                var orderDto = _mapper.Map<OrderDto>(order);
                var supervise = await _orderSuperviseRepository.GetAsync(x => x.Id == model.Id);
                if (supervise != null)
                {
                    var superviseDto = _mapper.Map<SuperviseOrderDto>(supervise);
                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderUrgeInform, new PublishUrgeDto()
                    {
                        Order = orderDto,
                        Urge = _mapper.Map<UrgeOrderDto>(superviseDto),
                        ClientGuid = ""
                    });
                    //try
                    //{
                    //    await _provinceService.SendSuperviseProcessInfo(new PublishSuperviseDto()
                    //    {
                    //        Order = orderDto,
                    //        Supervise = superviseDto,
                    //        ClientGuid = ""
                    //    }, HttpContext.RequestAborted);
                    //}
                    //catch (Exception e)
                    //{
                    //    _logger.LogError("_provinceService.SendSuperviseProcessInfo throw exception: {ex}", e.Message);
                    //}
                }
            }
        }
    }

    /// <summary>
    /// 回复督办
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("supervise/reply")]
    [LogFilter("回复工单督办")]
    public async Task ReplySupervise([FromBody] ReplyOrderSuperviseDto dto)
    {
        //验证是否存在督办
        var supervise = await _orderSuperviseRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        if (supervise is null)
            throw UserFriendlyException.SameMessage("无效督办");
        if (supervise.State > 0)
            throw UserFriendlyException.SameMessage("督办已回复,请勿重复回复");
        _mapper.Map(dto, supervise);
        supervise.ReplyId = _sessionContext.UserId;
        supervise.ReUser = _sessionContext.UserName;
        supervise.ReplyTime = DateTime.Now;
        supervise.State = 1;
        if (dto.Files.Any())
            supervise.ReplyFileJson =
                await _fileRepository.AddFileAsync(dto.Files, supervise.Id, "", HttpContext.RequestAborted);
        await _orderSuperviseRepository.UpdateAsync(supervise, HttpContext.RequestAborted);
        var order = await _orderRepository.GetAsync(supervise.OrderId, HttpContext.RequestAborted);
        //推省上
        if (supervise.Province.HasValue && supervise.Province.Value)
        {
            var orderDto = _mapper.Map<OrderDto>(order);
            var superviseDto = _mapper.Map<SuperviseOrderDto>(supervise);
            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderSuperviseResult, new PublishSuperviseDto()
            {
                Order = orderDto,
                Supervise = superviseDto,
                ClientGuid = ""
            }, cancellationToken: HttpContext.RequestAborted);
            //try
            //{
            //    await _provinceService.SendSuperviseProcessInfo(new PublishSuperviseDto()
            //    {
            //        Order = orderDto,
            //        Supervise = superviseDto,
            //        ClientGuid = ""
            //    }, HttpContext.RequestAborted);
            //}
            //catch (Exception e)
            //{
            //    _logger.LogError("_provinceService.SendSuperviseProcessInfo throw exception: {ex}", e.Message);
            //}
        }
    }

    /// <summary>
    /// 签收督办
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("supervise/sign")]
    [LogFilter("签收工单督办")]
    public async Task SignSupervise([FromBody] SignOrderSuperviseDto dto)
    {
        //验证是否存在督办
        var supervise = await _orderSuperviseRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        if (supervise is null)
            throw UserFriendlyException.SameMessage("无效督办");
        //supervise.State = 2;
        supervise.SignTime = DateTime.Now;
        supervise.SignUser = _sessionContext.UserName;
        await _orderSuperviseRepository.UpdateAsync(supervise, HttpContext.RequestAborted);
        var order = await _orderRepository.GetAsync(supervise.OrderId, HttpContext.RequestAborted);
        //推省上
        if (supervise.Province.HasValue && supervise.Province.Value)
        {
            var orderDto = _mapper.Map<OrderDto>(order);
            var superviseDto = _mapper.Map<SuperviseOrderDto>(supervise);
            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderSuperviseCourse, new PublishSuperviseDto()
            {
                Order = orderDto,
                Supervise = superviseDto,
                ClientGuid = ""
            }, cancellationToken: HttpContext.RequestAborted);
            //try
            //{
            //    await _provinceService.SendSuperviseProcessInfo(new PublishSuperviseDto()
            //    {
            //        Order = orderDto,
            //        Supervise = superviseDto,
            //        ClientGuid = ""
            //    }, HttpContext.RequestAborted);
            //}
            //catch (Exception e)
            //{
            //    _logger.LogError("_provinceService.SendSuperviseProcessInfo throw exception: {ex}", e.Message);
            //}
        }
    }


    /// <summary>
    /// 督办详情
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("supervise/{id}")]
    public async Task<OrderSuperviseDto> SuperviseEntity(string id)
    {
        var orderSupervise = await _orderSuperviseRepository.Queryable()
            .Includes(x => x.Order)
            .FirstAsync(x => x.Id == id);
        var orderSuperviseDto = new OrderSuperviseDto();
        if (orderSupervise != null)
        {
            orderSuperviseDto = _mapper.Map<OrderSuperviseDto>(orderSupervise);
            if (orderSuperviseDto.FileJson != null && orderSuperviseDto.FileJson.Any())
            {
                var ids = orderSuperviseDto.FileJson.Select(x => x.Id).ToList();
                var files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
                orderSuperviseDto.Files = files.Where(x => x.Classify == "督办申请").ToList();
                orderSuperviseDto.ReplyFiles = files.Where(x => x.Classify == "督办回复").ToList();
            }
        }

        return orderSuperviseDto;
    }

    #endregion

    #region 工单催办

    /// <summary>
    /// 工单催办列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("waiturge")]
    public async Task<PagedDto<UrgeOrderDto>> WaitUrgeList([FromQuery] UrgeListDto dto)
    {
        //如果角色为空，则说明催办的是部门，根据部门查询
        //如果角色不为空，则说明催办的是角色，则根据部门和角色一起查
        var (total, items) = await _orderUrgeRepository.Queryable()
            .Includes(x => x.Order)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Order.Title.Contains(dto.Keyword!) || x.Order.No.Contains(dto.Keyword!))
            .WhereIF(dto.UrgeState > -1, x => x.State == dto.UrgeState)
            .WhereIF(_sessionContext.OrgIsCenter == false, d =>
                (SqlFunc.IsNullOrEmpty(d.RoleId) == true && d.OrgId.StartsWith(_sessionContext.RequiredOrgId)) ||
                (SqlFunc.IsNullOrEmpty(d.RoleId) == false && d.OrgId.StartsWith(_sessionContext.RequiredOrgId) &&
                 _sessionContext.Roles.Contains(d.RoleId))
            )
            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), x => x.Order.ActualHandleOrgName.Contains(dto.ActualHandleOrgName)) //接办部门（综合查询模糊）
            .WhereIF(!string.IsNullOrEmpty(dto.OrgLevelOneName), x => x.Order.OrgLevelOneName.Contains(dto.OrgLevelOneName)) //一级部门
            .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepName), x => x.Order.CurrentStepName == dto.CurrentStepName) //当前办理节点
            .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.Order.No.Contains(dto.No))                                //工单编号
            .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, x => x.Order.IsProvince == true)   //是否省工单
            .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == false, x => x.Order.IsProvince == false)
            .WhereIF(!string.IsNullOrEmpty(dto.Channel), x => x.Order.SourceChannelCode == dto.Channel)              //来源渠道
            .WhereIF(dto.ExpiredTimeStart.HasValue, x => x.Order.ExpiredTime >= dto.ExpiredTimeStart)                //期满时间Start
            .WhereIF(dto.ExpiredTimeEnd.HasValue, x => x.Order.ExpiredTime <= dto.ExpiredTimeEnd)                    //期满时间End
            .WhereIF(dto.CreationTimeStart.HasValue, x => x.Order.CreationTime >= dto.CreationTimeStart)             //受理时间Start
            .WhereIF(dto.CreationTimeEnd.HasValue, x => x.Order.CreationTime <= dto.CreationTimeEnd)                 //受理时间End
            .WhereIF(dto.Status.HasValue, x => x.Order.Status == dto.Status)                                         //工单状态
            .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Order.Title.Contains(dto.Title))                       //工单标题
            .WhereIF(!string.IsNullOrEmpty(dto.CurrentHandleOrgName), x => x.Order.ActualHandleOrgName.Contains(dto.CurrentHandleOrgName)) //接办部门
            .WhereIF(dto.CurrentHandleTimeStart.HasValue, x => x.Order.CurrentHandleTime >= dto.CurrentHandleTimeStart)//接办时间Start
            .WhereIF(dto.CurrentHandleTimeEnd.HasValue, x => x.Order.CurrentHandleTime <= dto.CurrentHandleTimeEnd)    //接办时间End
            .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), x => x.Order.HotspotSpliceName != null && x.Order.HotspotSpliceName.Contains(dto.Hotspot)) //热点
            .WhereIF(!string.IsNullOrEmpty(dto.AcceptTypeCode), x => x.Order.AcceptTypeCode == dto.AcceptTypeCode)   //受理类型
            .WhereIF(!string.IsNullOrEmpty(dto.CrUser), x => x.CrUser.Contains(dto.CrUser))                          //催办人
            .WhereIF(!string.IsNullOrEmpty(dto.CreatorOrgName), x => x.CreatorOrgName.Contains(dto.CreatorOrgName))  //催办部门
            .WhereIF(dto.CrTimeStart.HasValue, x => x.CreationTime >= dto.CrTimeStart)                               //催办时间Start
            .WhereIF(dto.CrTimeEnd.HasValue, x => x.CreationTime <= dto.CrTimeEnd)                                   //催办时间End
            .WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.OrgName.Contains(dto.OrgName))                       //催办部门
            .WhereIF(!string.IsNullOrEmpty(dto.ApplyContent), x => x.ApplyContent.Contains(dto.ApplyContent))        //催办内容

            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<UrgeOrderDto>(total, _mapper.Map<IReadOnlyList<UrgeOrderDto>>(items));
    }

    /// <summary>
    /// 工单催办列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("urge")]
    public async Task<PagedDto<UrgeOrderDto>> UrgeList([FromQuery] UrgeListDto dto)
    {
        var (total, items) = await _orderUrgeRepository.Queryable()
            .Includes(x => x.Order)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Order.Title.Contains(dto.Keyword!) || x.Order.No.Contains(dto.Keyword!))
            .WhereIF(dto.UrgeState > -1, x => x.State == dto.UrgeState)
            .WhereIF(_sessionContext.OrgIsCenter == false, x => x.OrgId.StartsWith(_sessionContext.OrgId))
            .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.Order.No.Contains(dto.No))                                //工单编号
            .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, x => x.Order.IsProvince == true)   //是否省工单
            .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == false, x => x.Order.IsProvince == false)
            .WhereIF(!string.IsNullOrEmpty(dto.Channel), x => x.Order.SourceChannelCode == dto.Channel)              //来源渠道
            .WhereIF(dto.ExpiredTimeStart.HasValue, x => x.Order.ExpiredTime >= dto.ExpiredTimeStart)                //期满时间Start
            .WhereIF(dto.ExpiredTimeEnd.HasValue, x => x.Order.ExpiredTime <= dto.ExpiredTimeEnd)                    //期满时间End
            .WhereIF(dto.CreationTimeStart.HasValue, x => x.Order.CreationTime >= dto.CreationTimeStart)             //受理时间Start
            .WhereIF(dto.CreationTimeEnd.HasValue, x => x.Order.CreationTime <= dto.CreationTimeEnd)                 //受理时间End
            .WhereIF(dto.Status.HasValue, x => x.Order.Status == dto.Status)                                         //工单状态
            .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Order.Title.Contains(dto.Title))                       //工单标题
            .WhereIF(!string.IsNullOrEmpty(dto.CurrentHandleOrgName), x => x.Order.ActualHandleOrgName.Contains(dto.CurrentHandleOrgName)) //接办部门
            .WhereIF(dto.CurrentHandleTimeStart.HasValue, x => x.Order.CurrentHandleTime >= dto.CurrentHandleTimeStart)//接办时间Start
            .WhereIF(dto.CurrentHandleTimeEnd.HasValue, x => x.Order.CurrentHandleTime <= dto.CurrentHandleTimeEnd)    //接办时间End
            .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), x => x.Order.HotspotSpliceName != null && x.Order.HotspotSpliceName.Contains(dto.Hotspot)) //热点
            .WhereIF(!string.IsNullOrEmpty(dto.AcceptTypeCode), x => x.Order.AcceptTypeCode == dto.AcceptTypeCode)   //受理类型
            .WhereIF(!string.IsNullOrEmpty(dto.CrUser), x => x.CrUser.Contains(dto.CrUser))                          //催办人
            .WhereIF(!string.IsNullOrEmpty(dto.CreatorOrgName), x => x.CreatorOrgName.Contains(dto.CreatorOrgName))  //催办部门
            .WhereIF(dto.CrTimeStart.HasValue, x => x.CreationTime >= dto.CrTimeStart)                               //催办时间Start
            .WhereIF(dto.CrTimeEnd.HasValue, x => x.CreationTime <= dto.CrTimeEnd)                                   //催办时间End
            .WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.OrgName.Contains(dto.OrgName))                       //催办部门
            .WhereIF(!string.IsNullOrEmpty(dto.ApplyContent), x => x.ApplyContent.Contains(dto.ApplyContent))        //催办内容
            .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepName), x => x.Order.CurrentStepName == dto.CurrentStepName) //当前办理节点
            .WhereIF(dto.CrState.HasValue, x => x.State == dto.CrState)
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<UrgeOrderDto>(total, _mapper.Map<IReadOnlyList<UrgeOrderDto>>(items));
    }

    /// <summary>
    /// 批量催办
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("urge/add")]
    [LogFilter("批量催办工单")]
    public async Task UrgeAdd([FromBody] OrderUrgeAddDto dto)
    {
        if (dto is null)
            throw UserFriendlyException.SameMessage("参数错误");

        if (dto.OrderIds == null || dto.OrderIds.Count == 0)
            throw UserFriendlyException.SameMessage("请选择要催办的工单");

        if (string.IsNullOrEmpty(dto.UrgeContent))
            throw UserFriendlyException.SameMessage("请填写催办内容");

        foreach (var item in dto.OrderIds)
        {
            var order = await _orderRepository.GetAsync(item, HttpContext.RequestAborted);
            if (order != null)
            {
                var work = await _workflowStepRepository.GetAsync(p => p.Id == order.ActualHandleStepId, HttpContext.RequestAborted);
                if (work != null)
                {
                    var workflowStepHandler = work.GetWorkflowStepHandler();

                    var model = new OrderUrge
                    {
                        OrderId = order.Id,
                        OrgId = workflowStepHandler.OrgId,
                        OrgName = workflowStepHandler.OrgName,
                        RoleId = workflowStepHandler.RoleId,
                        ActualHandleStepId = work.Id,
                        CreatorOrgName = _sessionContext.OrgName,
                        CrUser = _sessionContext.UserName,
                        State = 0,
                        ApplyContent = dto.UrgeContent
                    };
                    model.InitId();

                    //中心催办
                    if (_sessionContext.OrgIsCenter)
                    {
                        //泸州任务 303 当前节点处于承办部门，不管是几级部门，催办对象都是当前接办部门所属的一级部门的所有部门经办人
                        if (_appOptions.Value.IsLuZhou && !string.IsNullOrEmpty(order.OrgLevelOneCode) && order.OrgLevelOneCode != "001")
                        {
                            model.OrgId = order.OrgLevelOneCode;
                            model.OrgName = order.OrgLevelOneName;
                        }

                        if (dto.AcceptSms)
                        {
                            try
                            {
                                var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
                                //查询部门所有账号
                                var userlist = await _userRepository.Queryable().Where(x =>
                                    x.OrgId == model.OrgId && !string.IsNullOrEmpty(x.PhoneNo) &&
                                    x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
                                foreach (var user in userlist)
                                {
                                    //发送短信
                                    var messageDto = new Share.Dtos.Push.MessageDto
                                    {
                                        PushBusiness = EPushBusiness.OrderUrge,
                                        ExternalId = order.Id,
                                        OrderId = order.Id,
                                        PushPlatform = EPushPlatform.Sms,
                                        Remark = order.Title,
                                        Name = user.Name,
                                        TemplateCode = "1002",
                                        Params = new List<string>() { order.No },
                                        TelNumber = user.PhoneNo,
                                    };
                                    await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
                                }
                            }
                            catch
                            {
                            }
                        }
                    }
                    //部门催办
                    else
                    {
                        if (dto.AcceptSms)
                        {
                            try
                            {
                                //查询部门所有账号
                                var userlist = work.FlowAssignType == EFlowAssignType.User || work.FlowAssignType == EFlowAssignType.Role
                                    ? await _userRepository.Queryable().Where(x => x.Id == workflowStepHandler.UserId).ToListAsync()
                                    : await _userRepository.Queryable().Where(x => x.OrgId == workflowStepHandler.OrgId).ToListAsync();
                                foreach (var user in userlist)
                                {
                                    //发送短信
                                    var messageDto = new Share.Dtos.Push.MessageDto
                                    {
                                        PushBusiness = EPushBusiness.OrderUrge,
                                        ExternalId = order.Id,
                                        OrderId = order.Id,
                                        PushPlatform = EPushPlatform.Sms,
                                        Remark = order.Title,
                                        Name = user.Name,
                                        TemplateCode = "1002",
                                        Params = new List<string>() { order.No },
                                        TelNumber = user.PhoneNo,
                                    };
                                    await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
                                }
                            }
                            catch
                            {
                            }
                        }
                    }

                    await _orderUrgeRepository.AddAsync(model, HttpContext.RequestAborted);
                }
            }
        }
    }

    /// <summary>
    /// 申请催办
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("urge/apply")]
    [LogFilter("新增工单催办")]
    public async Task ApplyUrge([FromBody] ApplyOrderUrgeDto dto)
    {
        if (!dto.UrgeOrgDtos.Any())
            throw UserFriendlyException.SameMessage("请选择被催办部门");
        //验证工单是否可以申请
        var order = await _orderRepository.GetAsync(dto.OrderId, HttpContext.RequestAborted);
        if (order is null)
            throw UserFriendlyException.SameMessage("无效工单");
        var work = await _workflowStepRepository.GetAsync(p => p.Id == order.ActualHandleStepId, HttpContext.RequestAborted);
        var workflowStepHandler = work.GetWorkflowStepHandler();
        foreach (var item in dto.UrgeOrgDtos)
        {
            var model = _mapper.Map<OrderUrge>(dto);
            model.OrgId = item.OrgId;
            model.OrgName = item.OrgName;
            model.CreatorOrgName = _sessionContext.OrgName;
            model.CrUser = _sessionContext.UserName;
            model.State = 0;
            model.InitId();
            if (dto.Files.Any())
                model.FileJson =
                    await _fileRepository.AddFileAsync(dto.Files, model.Id, "", HttpContext.RequestAborted);
            //泸州任务 303 当前节点处于承办部门，不管是几级部门，催办对象都是当前接办部门所属的一级部门的所有部门经办人
            if (_appOptions.Value.IsLuZhou && !string.IsNullOrEmpty(order.OrgLevelOneCode) && order.OrgLevelOneCode != "001")
            {
                model.OrgId = order.OrgLevelOneCode;
                model.OrgName = order.OrgLevelOneName;
            }

            await _orderUrgeRepository.AddAsync(model, HttpContext.RequestAborted);
            if (_sessionContext.OrgIsCenter)
            {
                if (dto.AcceptSms)
                {
                    try
                    {
                        var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
                        //查询部门所有账号
                        var userlist = await _userRepository.Queryable().Where(x =>
                            x.OrgId == model.OrgId && !string.IsNullOrEmpty(x.PhoneNo) &&
                            x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
                        foreach (var user in userlist)
                        {
                            //发送短信
                            var messageDto = new Share.Dtos.Push.MessageDto
                            {
                                PushBusiness = EPushBusiness.OrderUrge,
                                ExternalId = order.Id,
                                OrderId = order.Id,
                                PushPlatform = EPushPlatform.Sms,
                                Remark = order.Title,
                                Name = user.Name,
                                TemplateCode = "1002",
                                Params = new List<string>() { order.No },
                                TelNumber = user.PhoneNo,
                            };
                            await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
                        }
                    }
                    catch
                    {
                    }
                }
            }
            else
            {
                if (dto.AcceptSms)
                {
                    try
                    {
                        //查询部门所有账号
                        var userlist = work.FlowAssignType == EFlowAssignType.User || work.FlowAssignType == EFlowAssignType.Role
                            ? await _userRepository.Queryable().Where(x => x.Id == workflowStepHandler.UserId).ToListAsync()
                            : await _userRepository.Queryable().Where(x => x.OrgId == workflowStepHandler.OrgId).ToListAsync();
                        foreach (var user in userlist)
                        {
                            //发送短信
                            var messageDto = new Share.Dtos.Push.MessageDto
                            {
                                PushBusiness = EPushBusiness.OrderUrge,
                                ExternalId = order.Id,
                                OrderId = order.Id,
                                PushPlatform = EPushPlatform.Sms,
                                Remark = order.Title,
                                Name = user.Name,
                                TemplateCode = "1002",
                                Params = new List<string>() { order.No },
                                TelNumber = user.PhoneNo,
                            };
                            await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
                        }
                    }
                    catch
                    {
                    }
                }
            }

            var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0];
            CityBaseConfiguration cityBase = JsonSerializer.Deserialize<CityBaseConfiguration>(setting);
            //推省上
            if (!string.IsNullOrEmpty(model.Id) &&
                (cityBase.CityProvince.OrgId.Equals(model.OrgId) || cityBase.CityProvinceAssign.OrgId.Equals(model.OrgId)))
            {
                var orderDto = _mapper.Map<OrderDto>(order);
                var urge = await _orderUrgeRepository.GetAsync(x => x.Id == model.Id);
                if (urge != null)
                {
                    var urgeDto = _mapper.Map<UrgeOrderDto>(urge);
                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderUrgeInform, new PublishUrgeDto()
                    {
                        Order = orderDto,
                        Urge = urgeDto,
                        ClientGuid = ""
                    });
                }
            }
        }
    }

    /// <summary>
    /// 回复催办
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("urge/reply")]
    [LogFilter("回复工单催办")]
    public async Task ReplyUrge([FromBody] ReplyOrderUrgeDto dto)
    {
        //验证是否存在催办
        var urge = await _orderUrgeRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        if (urge is null)
            throw UserFriendlyException.SameMessage("无效催办");
        if (urge.State > 0)
            throw UserFriendlyException.SameMessage("督办已回复,请勿重复回复");

        _mapper.Map(dto, urge);
        urge.ReplyId = _sessionContext.UserId;
        urge.ReUser = _sessionContext.UserName;
        urge.ReplyContent = dto.ReplyContent;
        urge.ReplyTime = DateTime.Now;
        urge.State = 1;
        if (dto.Files.Any())
            urge.ReplyFileJson = await _fileRepository.AddFileAsync(dto.Files, urge.Id, "", HttpContext.RequestAborted);
        else
            urge.ReplyFileJson = new List<Share.Dtos.File.FileJson>();
        await _orderUrgeRepository.UpdateAsync(urge, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 签收催办
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("urge/sign")]
    [LogFilter("签收工单催办")]
    public async Task SignUrge([FromBody] SignOrderUrgeDto dto)
    {
        //验证是否存在催办
        var urge = await _orderUrgeRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        if (urge is null)
            throw UserFriendlyException.SameMessage("无效催办");
        urge.State = 2;
        urge.SignUser = _sessionContext.UserName;
        urge.SignTime = DateTime.Now;
        await _orderUrgeRepository.UpdateAsync(urge, HttpContext.RequestAborted);
    }


    /// <summary>
    /// 催办详情
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("urge/{id}")]
    public async Task<OrderUrgeDto> UrgeEntity(string id)
    {
        var orderUrge = await _orderUrgeRepository.Queryable()
            .Includes(x => x.Order)
            .FirstAsync(x => x.Id == id);
        var orderUrgeDto = new OrderUrgeDto();
        if (orderUrge != null)
        {
            orderUrgeDto = _mapper.Map<OrderUrgeDto>(orderUrge);
            if (orderUrgeDto.FileJson != null && orderUrgeDto.FileJson.Any())
            {
                var ids = orderUrgeDto.FileJson.Select(x => x.Id).ToList();
                orderUrgeDto.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
            }
        }

        return orderUrgeDto;
    }

    /// <summary>
    /// 列表页面基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("basedata")]
    public async Task<object> BaseDataRange()
    {
        // 催办查询 催办状态
        List<Kv> kvCrState = new()
        {
            new Kv { Key = "0", Value = "待办未读" },
            new Kv { Key = "1", Value = "已回复" },
            new Kv { Key = "3", Value = "签收已读" }
        };

        //延期申请单位
        List<Kv> ETimeType = new()
        {
            new Kv { Key = "1", Value = "小时" },
            new Kv { Key = "2", Value = "工作日" },
            new Kv { Key = "3", Value = "自然日" }
        };

        var wfModule = await _workflowApplication.GetWorkflowModuleAsync(WorkflowModuleConsts.OrderHandle, HttpContext.RequestAborted);
        var definition = wfModule.Definition;
        var rsp = new
        {
            ChannelOptions = _sysDicDataCacheManager.GetSysDicDataCache(TimeLimitBaseDataConsts.SourceChannel),
            AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType),
            OrderStatusOptions = EnumExts.GetDescriptions<EOrderStatus>(),
            CurrentStepOptions = definition?.Steps.Select(x => new Kv(x.Code, x.Name)),
            CrState = kvCrState,
            DelayUnitOptions = ETimeType
        };
        return rsp;
    }


    #endregion

    #region 工单办理

    /// <summary>
    /// 工单列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet]
    public async Task<IReadOnlyList<OrderDto>> Query([FromQuery] QueryOrderDto dto)
    {
        //var query = _orderApplication.QueryOrders(dto);
        //var (total, items) = await query.ToPagedListAsync(dto, HttpContext.RequestAborted);
        //return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
        var orders = await _orderApplication.QueryOrders(dto)
            .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted);
        var list = _mapper.Map<IReadOnlyList<OrderDto>>(orders);
        if ((_appOptions.Value.IsLuZhou || _appOptions.Value.IsZiGong) && !_sessionContext.OrgIsCenter)
            list = list.Select(p => p.DataMask(_appOptions.Value.IsZiGong)).ToList();
        return list;
    }

    /// <summary>
    /// 查询工单(固定数据量)
    /// </summary>
    [HttpGet("fixed")]
    public async Task<IReadOnlyList<OrderDto>> QueryFixed([FromQuery] QueryOrderFixedDto dto)
    {
        var hasSetting = Int32.TryParse(
            _systemSettingCacheManager.GetSetting(SettingConstants.FixedQueryCount)?.SettingValue[0], out var queryCount);
        var query = _orderApplication.QueryOrders(dto);
        var orders = await query.ToFixedListAsync(dto.QueryIndex, hasSetting ? queryCount : null, HttpContext.RequestAborted);
        return _mapper.Map<IReadOnlyList<OrderDto>>(orders);
    }

    /// <summary>
    /// 查询总数
    /// </summary>
    [HttpGet("count")]
    public async Task<int> Count([FromQuery] QueryOrderDto dto)
    {
        var query = _orderApplication.QueryOrders(dto);
        return await query.CountAsync(HttpContext.RequestAborted);
    }

    [HttpPost("order/export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> ExportOrders([FromBody] ExportExcelDto<QueryOrderDto> dto)
    {
        var query = _orderApplication.QueryOrders(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);

        if (_appOptions.Value.IsLuZhou)
            orderDtos = orderDtos.Select(p => p.DataMask(false)).ToList();

        if (_appOptions.Value.IsZiGong && !_sessionContext.OrgIsCenter)
            orderDtos = orderDtos.Select(p => p.DataMask(_appOptions.Value.IsZiGong)).ToList();

        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>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("history")]
    public async Task<PagedDto<OrderHistoryOutDto>> Query([FromQuery] QueryOrderHistoryDto dto)
    {
        if (dto.PhoneNo.Equals("信息保密"))
        {
            return new PagedDto<OrderHistoryOutDto>() { };
        }

        var query = _orderRepository.Queryable();

        if (_appOptions.Value.IsLuZhou && !_sessionContext.OrgIsCenter)
        {
            query.Where(d => d.WorkflowSteps
                .Any(step =>
                    ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) &&
                      step.HandlerId == _sessionContext.RequiredUserId) ||
                     (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) &&
                      step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
                     (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) &&
                      _sessionContext.Roles.Contains(step.RoleId)) ||
                     (step.FlowAssignType == EFlowAssignType.OrgAndRole && !string.IsNullOrEmpty(step.RoleId) &&
                      _sessionContext.Roles.Contains(step.RoleId)
                      && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId))
                    && step.Status == EWorkflowStepStatus.Handled));
        }

        var (total, items) = await query
            .Includes(d => d.OrderScreens)
            .Includes(d => d.OrderTerminates)
            .Where(d => d.Contact == dto.PhoneNo)
            .WhereIF(_sessionContext.OrgIsCenter == false && (_appOptions.Value.IsYiBin == true || _appOptions.Value.IsLuZhou == true),
                d => d.IsSecret == false)
            .WhereIF(!string.IsNullOrEmpty(dto.OrderId) && _appOptions.Value.IsLuZhou == false, d => d.Id != dto.OrderId)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
            .Select(d => new OrderHistoryOutDto
            {
                Id = d.Id,
                Title = d.Title,
                No = d.No,
                CurrentStepName = d.CurrentStepName,
                CreationTime = d.CreationTime,
                ActualHandleOrgName = d.ActualHandleOrgName,
                Status = d.Status,
                IsScreen = d.OrderScreens.Any(x => x.Status == EScreenStatus.End),
                IsTerminate = d.OrderTerminates.Any(p => p.Status == ETerminateStatus.End),
                //TerminateStatus = SqlFunc.Subqueryable<OrderTerminate>().Where(s => s.OrderId == d.Id).OrderByDesc(s => s.CreationTime).Select(s => s.Status)
            })
            .MergeTable()
            .OrderByIF(_appOptions.Value.IsZiGong, d => d.IsTerminate, OrderByType.Desc)
            .OrderByDescending(d => d.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderHistoryOutDto>(total, _mapper.Map<IReadOnlyList<OrderHistoryOutDto>>(items));
    }

    /// <summary>
    /// 历史工单(全量)
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("history_all")]
    public async Task<PagedDto<OrderDto>> QueryAll([FromQuery] QueryOrderHistoryDto dto)
    {
        var query = _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!));

        //随手拍
        if (_systemSettingCacheManager.Snapshot && !string.IsNullOrEmpty(dto.IndustryId))
        {
            query.Where(d => d.OrderSnapshot.IndustryId == dto.IndustryId);
        }

        //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);

        return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
    }

    /// <summary>
    /// 查询重复工单
    /// </summary>
    [HttpGet("duplicate")]
    public async Task<PagedDto<OrderDto>> Query([FromQuery] QueryOrderDuplicateDto dto)
    {
        if (!dto.OrderIds.Any())
            return new PagedDto<OrderDto>(0, new List<OrderDto>());

        var (total, items) = await _orderRepository.Queryable()
            .Where(d => dto.OrderIds.Contains(d.Id))
            .OrderByDescending(d => d.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
    }

    /// <summary>
    /// 查询工单详情
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("{id}")]
    public async Task<OrderDto> Get(string id)
    {

        var order = await _orderRepository.Queryable()
            .Includes(d => d.OrderExtension)
            .Includes(d => d.OrderDelays)
            .Includes(d => d.OrderPublish)
            .Includes(d => d.OrderPushTypes)
            .Includes(d => d.OrderComplements)
            .Includes(d => d.OrderTags)
            //.Includes(d => d.OrderScreens)
            .Includes(d => d.OrderVisits.Where(x => x.VisitState == EVisitState.Visited).ToList(), x => x.OrderVisitDetails)
            .Includes(d => d.OrderVisits.Where(x => x.VisitState == EVisitState.Visited).ToList(), x => x.Employee)
            .FirstAsync(d => d.Id == id);
        if (order == null) return new();

        var dto = _mapper.Map<OrderDto>(order);
        //处理中心意见
        dto.CenterOpinion = order.CenterToOrgOpinion;
        //班长代办--  判断不是会签件  流程判断业务类型
        //var setting = _systemSettingCacheManager.GetSetting(SettingConstants.SeatsMonitor);
        //var settingStr = setting?.SettingValue;
        //var roles = _sessionContext.Roles;
        //foreach (var item in settingStr)
        //{
        //	if (roles != null && roles.Contains(item)) dto.CanHandle = true;
        //}
        if (!string.IsNullOrEmpty(order.WorkflowId))
        {
            bool canInsteadHandle = false;
            //班长代办
            var settingEnable = _systemSettingCacheManager.GetSetting(SettingConstants.ChargeDAffaires);
            var isEnable = settingEnable != null && settingEnable.SettingValue.Any() ? int.Parse(settingEnable?.SettingValue[0]) : 0;
            if (isEnable > 0)
            {
                var setting = _systemSettingCacheManager.GetSetting(SettingConstants.SeatsMonitor);
                var settingStr = setting?.SettingValue;
                var roles = _sessionContext.Roles;
                if ((settingStr?.Any() ?? false) && roles.Any())
                {
                    var intersectRoles = settingStr.Intersect(roles);
                    canInsteadHandle = intersectRoles.Any();
                }

                if (canInsteadHandle)
                {
                    var unhandleSteps =
                        await _workflowDomainService.GetUnhandleStepsByOthersAsync(order.WorkflowId, HttpContext.RequestAborted);
                    // 会签多节点 不允许班长代办  归档没有待办节点
                    if (unhandleSteps.Count != 1)
                        canInsteadHandle = false;
                    if (isEnable < 3 && unhandleSteps.Count == 1)
                    {
                        var type = isEnable - 1;
                        var step = unhandleSteps.FirstOrDefault(d => d.BusinessType == (EBusinessType)type);
                        canInsteadHandle = step != null && !string.IsNullOrEmpty(step.Id);
                        if (canInsteadHandle && step.IsInCountersign())
                            canInsteadHandle = false;
                    }
                }
            }

            var result = await _workflowDomainService.GetWorkflowHandlePermissionAsync(
                order.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles,
                cancellationToken: HttpContext.RequestAborted);
            dto.Workflow = _mapper.Map<WorkflowDto>(result.Workflow);
            dto.CountersignId = result.CountersignId;
            dto.CanHandle = result.CanHandle;
            dto.CanPrevious = result.CanPrevious;
            dto.CanInsteadHandle = !dto.CanHandle && canInsteadHandle;
            if (result.Trace is not null)
            {
                dto.PreviousOpinion = result.Trace!.Opinion;
                var sendBack = await _orderSendBackAuditRepository.Queryable().Where(x => x.OrderId == dto.Id && x.TraceId == result.Trace.Id)
                    .OrderByDescending(x => x.CreationTime).FirstAsync();
                if (sendBack is { Id: not null })
                {
                    //dto.SendBackOpinion = !string.IsNullOrEmpty(sendBack.Content) ? sendBack.Content : string.Empty;
                    if (sendBack.State == ESendBackAuditState.Refuse)
                    {
                        dto.SendBackRefuseOpinion = sendBack.AuditContent;
                        dto.SendBackAuditTime = sendBack.AuditTime;
                    }
                }
            }

            //
            // order.CurrentStepAcceptTime = DateTime.Now;
            // await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
            //
            // result.Workflow.UpdateCurrentStepAcceptTime(order.CurrentStepAcceptTime.Value);
            // await _mediator.Publish(new GetOrderDetailNotify(result.Workflow,
            //     _sessionContext.RequiredUserId, _sessionContext.UserName,
            //     _sessionContext.RequiredOrgId, _sessionContext.OrgName,
            //     _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName));
            if (result.CanHandle)
            {
                var acceptTime = await _workflowDomainService.AcceptAsync(result.Workflow,
                    _sessionContext.RequiredUserId, _sessionContext.UserName,
                    _sessionContext.RequiredOrgId, _sessionContext.OrgName,
                    _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
                    HttpContext.RequestAborted);
                if (acceptTime != null)
                {
                    order.ActualHandleStepAcceptTime = acceptTime;
                    order.CurrentStepAcceptTime = acceptTime;
                    await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
                }
            }
        }

        dto.IsRed = string.IsNullOrEmpty(dto.SignerId) || !order.ActualHandleStepAcceptTime.HasValue;

        //var dto = _mapper.Map<OrderDto>(order!);
        //dto.CountersignId = countersignId;
        //dto.CanHandle = order.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
        dto.IsCanDelay = !order.OrderDelays.Any(x => x.DelayState == EDelayState.Examining);
        if (order.OrderDelays.Any(x => x.DelayState == EDelayState.Examining && x.ApplyOrgCode == _sessionContext.RequiredOrgId))
        {
            dto.CanHandle = false;
        }

        dto.SpecialNum = await _orderSpecialRepository.CountAsync(x => x.OrderId == order.Id);

        dto.IsCanCancelDelay = order.OrderDelays.Any(x => x.DelayState == EDelayState.Examining && x.ApplyOrgCode == _sessionContext.RequiredOrgId);

        var delayModel = order.OrderDelays.MaxBy(x => x.CreationTime);
        if (delayModel != null)
        {
            if (delayModel.IsProDelay)
            {
                dto.ProvinceDelayString = "该工单已向省平台发送延期申请！延期状态：" + delayModel.DelayState.GetDescription();
            }

            var workFlow = await _workflowRepository.GetAsync(delayModel.WorkflowId);
            switch (delayModel.DelayState)
            {
                case EDelayState.Examining:
                    dto.DelayString = "延期状态：审批中  当前节点：" + workFlow?.ActualHandleStepName;
                    break;
                case EDelayState.Pass:
                    dto.DelayString = "已延期" + delayModel?.DelayNum + "个" + delayModel?.DelayUnit.GetDescription();
                    break;
                case EDelayState.NoPass:
                    dto.DelayString = "延期状态：拒绝 当前节点：" + workFlow?.ActualHandleStepName;
                    break;
                case EDelayState.Withdraw:
                    dto.DelayString = "延期状态：撤销 当前节点：" + workFlow?.ActualHandleStepName;
                    break;
                default:
                    break;
            }
        }
        else
        {
            dto.DelayString = "";
            dto.ProvinceDelayString = "";
        }

        //dto.CanPrevious = canPrevious;

        if (order.OrderPublish != null)
        {
            dto.PublishState = order.OrderPublish.PublishState;
        }

        if (dto.FileJson != null && dto.FileJson.Any())
        {
            var ids = order.FileJson.Select(x => x.Id).ToList();
            var files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
            //x.Classify == "办理上传" &&
            dto.Files = files.Where(x => string.IsNullOrEmpty(x.FlowKey)).ToList();
        }

        //var call = await _trCallRecordRepository.Queryable().Where(x => x.CallAccept == order.CallId).FirstAsync();//由CallAccept改为OtherAccept
        //var call = await _trCallRecordRepository.Queryable().Where(x => x.OtherAccept == order.CallId).FirstAsync();
        //if (call != null)
        //{
        //    dto.RecordingBaseAddress = call.RecordingBaseAddress;
        //    dto.RecordingAbsolutePath = call.RecordingAbsolutePath;
        //}

        if (!string.IsNullOrEmpty(order.CallId))
        {
            if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun)
            {
                var callRecord = await _callApplication.GetTianrunCallAsync(order.CallId, HttpContext.RequestAborted);
                if (callRecord != null)
                {
                    dto.RecordingBaseAddress = callRecord.RecordingBaseAddress;
                    dto.RecordingAbsolutePath = callRecord.RecordingAbsolutePath;
                }
            }
            else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang)
            {
                var call = await _callApplication.GetCallAsync(order.CallId, HttpContext.RequestAborted);
                if (call is not null)
                {
                    dto.RecordingBaseAddress = call.AudioFile;
                    dto.RecordingAbsolutePath = call.AudioFile;
                }
            }
        }

        var repeatablesMap = await _repeatableEventDetailRepository.Queryable()
            .Includes(x => x.Order)
            .Where(x => x.OrderId == id).Distinct().ToListAsync();
        var repeatables = _mapper.Map<List<RepeatableEventDetailOpDto>>(repeatablesMap);
        dto.RepeatableEventDetails = repeatables;
        if (!string.IsNullOrEmpty(dto.WorkflowId))
        {
            var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true, withTraces: true,
                cancellationToken: HttpContext.RequestAborted);

            List<OrderRemarksDto> remarks = workflow.Steps.Where(x => !string.IsNullOrEmpty(x.Remark)).Select(x => new OrderRemarksDto
            { Remark = x.Remark, RemarkTime = x.HandleTime, RemarkUser = x.HandlerName }).ToList();
            dto.OrderRemarks = remarks;
            //退回
            if (order.Status == EOrderStatus.SendBack || order.Status == EOrderStatus.BackToUnAccept)
            {
                var backTrace = workflow.Traces.Where(x => x.Status == EWorkflowStepStatus.Handled).OrderByDescending(x => x.CreationTime).First();
                // backTrace.Opinion = backTrace.Opinion.Replace("流程归档", "");
                dto.SendBackOpinion = string.IsNullOrEmpty(backTrace.Opinion)
                    ? string.Empty
                    : "【" + backTrace.HandlerOrgName + "】" + backTrace.Opinion;
                //var sendBack = await _orderSendBackAuditRepository.Queryable().Where(x => x.OrderId == dto.Id).OrderByDescending(x => x.CreationTime).FirstAsync();
                //dto.SendBackOpinion = sendBack is { Id: not null } && !string.IsNullOrEmpty(sendBack.Content) ? sendBack.Content : string.Empty;
            }

            //重办
            if (order.Status == EOrderStatus.Special || order.Status == EOrderStatus.SpecialToUnAccept)
            {
                var reTransactTrace = workflow.Traces.Where(x => x.Status == EWorkflowStepStatus.Handled).OrderByDescending(x => x.CreationTime)
                    .First();
                dto.ReTransactOpinion = string.IsNullOrEmpty(reTransactTrace.Opinion)
                    ? string.Empty
                    : "【" + reTransactTrace.HandlerOrgName + "】" + reTransactTrace.Opinion;
            }
        }

        //工单是否在退回审批中
        if (await _orderSendBackAuditRepository.AnyAsync(x => x.OrderId == order.Id && x.State == ESendBackAuditState.Apply,
                HttpContext.RequestAborted))
        {
            dto.IsReturnUnderApproval = true;
        }

        //省退回
        var orderSendback = await _orderSendBackRepository.Queryable().Where(x => x.OrderId == order.Id).OrderByDescending(x => x.AuditTime)
            .FirstAsync();
        if (orderSendback is not null)
        {
            string stateStr = "";
            // 0  待审核  1 审核通过  2 审核不通过
            switch (orderSendback.State)
            {
                case 0:
                    stateStr = "待审核";
                    break;
                case 1:
                    stateStr = "审核通过";
                    break;
                case 2:
                    stateStr = "审核不通过";
                    break;
                default:
                    stateStr = "未知";
                    break;
            }

            dto.ProvinceSendBackString = "该工单已向省平台发送退回申请！退回状态：" + stateStr;
        }

        var isProvinceorderRevoke = await _orderRevokeRepository.Queryable().AnyAsync(x => x.OrderId == order.Id && x.IsProRevoke == true);
        if (isProvinceorderRevoke)
        {
            dto.ProvinceRevokeString = "该工单已由省平台发送撤单！请直接归档办理！";
        }

        //省甄别
        var orderScreen = await _orderScreenRepository.Queryable().Where(x => x.OrderId == order.Id && x.IsProScreen == true)
            .OrderByDescending(x => x.CreationTime)
            .FirstAsync();
        if (orderScreen != null)
        {
            dto.ProvinceScreenString = "该工单已向省平台发送甄别申请！甄别状态：" + orderScreen.Status.GetDescription();
        }

        //终止
        var orderTerminateList = await _orderTerminateRepository.Queryable().Where(x => x.OrderId == order.Id).ToListAsync();
        dto.OrderTerminateStatus = orderTerminateList.Any(x => x.Status == ETerminateStatus.End) ? "同意" :
            orderTerminateList.Any(x => x.Status == ETerminateStatus.Refuse) ? "不同意" :
            orderTerminateList.Any(x => x.Status == ETerminateStatus.Approval || x.Status == ETerminateStatus.SendBack) ? "审批中" : null;

        if (_systemSettingCacheManager.Snapshot)
        {
            await _orderSnapshotRepository.Queryable()
                .LeftJoin<IndustryCase>((snapshot, industryCase) => snapshot.IndustryCase == industryCase.Id)
                .Where((snapshot, industryCase) => snapshot.Id == order.Id)
                .Select((snapshot, industryCase) => new
                {
                    snapshot.IndustryId,
                    snapshot.IndustryName,
                    industryCase.Name,
                    snapshot.IsRectifyDepartment,
                    snapshot.IsDangerDepartment,
                    snapshot.IsSafetyDepartment,
                    snapshot.SignRemark,
                    snapshot.SignUserId,
                    snapshot.SignUserName,
                    snapshot.SignTime
                })
                .FirstAsync(HttpContext.RequestAborted)
                .Then(async snapshot =>
                {
                    dto.IndustryName = snapshot.IndustryName + " " + snapshot.Name;
                    dto.IndustryId = snapshot.IndustryId;
                    dto.IsRectifyDepartment = snapshot.IsRectifyDepartment;
                    dto.IsDangerDepartment = snapshot.IsDangerDepartment;
                    dto.IsSafetyDepartment = snapshot.IsSafetyDepartment;
                    dto.SignUserId = snapshot.SignUserId;
                    dto.SignUserName = snapshot.SignUserName;
                    dto.SignTime = snapshot.SignTime;
                    dto.SignRemark = snapshot.SignRemark;
                });
        }

        //处理回访录音
        if (dto.OrderVisits != null && dto.OrderVisits.Count > 0)
        {
            foreach (var item in dto.OrderVisits)
            {
                //var recordingFileUrl = "";
                //var recordingBaseAddress = "";
                //var recordingAbsolutePath = "";
                //var aiVisitVoiceBaseUrl = "";
                if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun)
                {
                    var callRecord = await _callApplication.GetTianrunCallAsync(item.CallId, HttpContext.RequestAborted);
                    if (callRecord != null)
                    {
                        item.RecordingFileUrl = callRecord.RecordingFileUrl;
                        item.RecordingBaseAddress = callRecord.RecordingBaseAddress;
                        item.RecordingAbsolutePath = callRecord.RecordingAbsolutePath;
                    }
                }
                else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang)
                {
                    CallNative? call = null;
                    if (item.CallId == null && item.VisitTime.HasValue)
                    {
                        call = await _callApplication.GetCallByTimeAndToNoAsync(dto.Contact, item.VisitTime.Value,
                            HttpContext.RequestAborted);
                    }

                    call = await _callApplication.GetCallAsync(item.CallId, HttpContext.RequestAborted);
                    if (call is not null)
                    {
                        if (call.AudioFile.IsNullOrEmpty())
                        {
                            call = await _callApplication.GetCallByCallNoAsync(call.CallNo, HttpContext.RequestAborted);
                        }

                        if (call is not null)
                        {
                            item.RecordingFileUrl = call.AudioFile;
                            item.RecordingBaseAddress = call.AudioFile;
                            item.RecordingAbsolutePath = call.AudioFile;
                        }
                    }
                }
            }
        }

        return _sessionContext.OrgIsCenter ? dto : dto.DataMask(_appOptions.Value.IsZiGong);
    }

    /// <summary>
    /// 查询工单预警信息
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("orderearly/{id}")]
    public async Task<object> GetOrderEarly(string id)
    {
        var now = DateTime.Now;
        var order = await _orderRepository.GetAsync(id, HttpContext.RequestAborted);

        var query = _orderRepository.Queryable()
         .Where(x => x.CreationTime <= now && x.CreationTime >= SqlFunc.DateAdd(now, -30) && x.Sensitive != null);
        var exp = Expressionable.Create<Order>();
        foreach (var item in order!.Sensitive!)
        {
            exp = exp.Or(x => SqlFunc.JsonArrayAny(x.Sensitive, item));
        }
        var orderList = await query.Where(exp.ToExpression()).ToListAsync();

        var orderEarlyList = new List<OrderEarlyInfo>();
        foreach (var item in order!.Sensitive!)
        {
            var model = new OrderEarlyInfo();
            model.KeyWord = item;
            model.WeekNum = orderList.Where(x => x.Sensitive!.Contains(item) && x.CreationTime <= now && x.CreationTime >= now.AddDays(-7)).Count();
            model.MonthNum = orderList.Where(x => x.Sensitive!.Contains(item)).Count();
            orderEarlyList.Add(model);
        }
        var orderEarly = await _orderEarlyWarningRepository.Queryable().FirstAsync(x => x.OrderId == id);

        return new
        {
            OrderEarlyInfo = orderEarlyList,
            OrderEarly = orderEarly,
        };
    }

    /// <summary>
    /// 新增工单
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost]
    [LogFilterAlpha("新增工单")]
    public async Task<object> Add([FromBody] AddOrderDto dto)
    {
        dto.InitAddress();

        //工单保存特殊身份验证
        var specialIdentityVerification =
            bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.SpecialIdentityVerification).SettingValue[0]);
        if (specialIdentityVerification && !string.IsNullOrEmpty(dto.FromPhone))
        {
            var specialNumber = await _specialNumberRepository.GetAsync(p => p.PhoneNumber == dto.FromPhone, HttpContext.RequestAborted);
            if (specialNumber != null)
            {
                if (specialNumber.PoliticalIdentityValue == "1")
                {
                    if (dto.OrderPushTypes == null || dto.OrderPushTypes.Count() == 0 || dto.OrderPushTypes.Exists(p => p.PushTypeCode == "9") == false)
                        throw UserFriendlyException.SameMessage("人大代表来电，请选择推送分类人大代表意见快办！");
                }
                dto.PoliticalIdentityValue = specialNumber.PoliticalIdentityValue;
                dto.PoliticalIdentityName = specialNumber.PoliticalIdentityName;
            }
            else
            {
                dto.PoliticalIdentityValue = string.Empty;
                dto.PoliticalIdentityName = string.Empty;
            }
        }

        //泸州任务 311 投诉件需限制受理内容的字数等需求
        if (_appOptions.Value.IsLuZhou && dto.AcceptTypeCode == "35")
        {
            if (dto.SourceChannelCode != "S12345" && dto.SourceChannelCode != "SZMHD" && dto.SourceChannelCode != "XCX" &&
                dto.SourceChannelCode != "JCeT")
            {
                if (dto.Content.Length < 25)
                    throw UserFriendlyException.SameMessage("保存失败，投诉类型受理内容字数需要至少25个字!");

                if (dto.Title.Contains("咨询") || dto.Title.Contains("建议") || dto.Title.Contains("求助") || dto.Title.Contains("举报")
                    || dto.Content.Contains("咨询") || dto.Content.Contains("建议") || dto.Content.Contains("求助") || dto.Content.Contains("举报"))
                    throw UserFriendlyException.SameMessage("保存失败！投诉类型标题和受理内容不能出现'咨询、建议、求助、举报'");
            }
        }

        //todo dto validation
        //交通工单校验
        var valid = await _orderDomainService.OrderValidation(dto, HttpContext.RequestAborted);
        if (valid.Validation)
            throw UserFriendlyException.SameMessage(valid.Result);

        if (!string.IsNullOrEmpty(dto.CallId))
        {
            dto.CallId = await _callApplication.GetOrSetCallIdAsync(dto.CallId, HttpContext.RequestAborted);
            var exists = await _orderRepository.AnyAsync(d => d.CallId == dto.CallId, HttpContext.RequestAborted);
            if (exists)
                throw new UserFriendlyException($"来电已保存工单, phone:{dto.FromPhone}, callId: {dto.CallId}", "来电已保存工单");
            exists = await _systemLogApplication.HasByIpUrlAsync(dto.CallId);
            if (exists)
            {
                // IpUrl 里面存的是 callId, 用来判断是工单的 CallId 是否已经被修复过了.
                // 存入的地方是 Hotline.Application.CallCenter.OrderRelateCallHandlerAsync
                throw new UserFriendlyException($"来电已保存工单, phone:{dto.FromPhone}, callId: {dto.CallId} !", "来电已保存工单!");
            }
        }

        var order = _mapper.Map<Orders.Order>(dto);
        order.SignerId = _sessionContext.UserId;
        order.SignerName = _sessionContext.UserName;

        order.InitId();
        if (dto.Files.Any())
            order.FileJson = await _fileRepository.AddFileAsync(dto.Files, order.Id, "", HttpContext.RequestAborted);
        // 工单推送分类
        if (dto.OrderPushTypes.Any())
        {
            var pushTypeAny = await _orderPushTypeRepository.AnyAsync(x => x.OrderId == order.Id);
            if (pushTypeAny)
                await _orderPushTypeRepository.RemoveAsync(x => x.OrderId == order.Id);
            dto.OrderPushTypes.ForEach(x => x.OrderId = order.Id);
            var orderPushTypes = _mapper.Map<List<OrderPushType>>(dto.OrderPushTypes);
            await _orderPushTypeRepository.AddRangeAsync(orderPushTypes);
            var pushTypes = dto.OrderPushTypes.Select(x => x.PushType);
            var pushTypeCode = dto.OrderPushTypes.Select(x => x.PushTypeCode);
            order.PushTypeCode = string.Join(",", pushTypeCode);
            order.PushType = string.Join(",", pushTypes);
        }

        if (dto.Tags != null && dto.Tags.Any())
        {
            var orderTags = new List<SystemDicData>();
            foreach (var item in dto.Tags)
            {
                orderTags.Add(new SystemDicData() { Id = item });
            }

            order.OrderTags = orderTags;
            var dicData = await _sysDicDataRepository.Queryable().Where(p => dto.Tags.Contains(p.Id)).Select(p => p.DicDataValue).ToListAsync();
            if (dicData != null && dicData.Any())
            {
                order.OrderTagCode = String.Join(", ", dicData);
            }
        }

        if (_appOptions.Value.IsLuZhou)
        {
            //期满时间
            var expiredTimeConfig =
                await _expireTime.CalcExpiredTime(DateTime.Now, DateTime.Now, EFlowDirection.CenterToCenter, order.Adapt<OrderTimeClacInfo>());
            _mapper.Map(expiredTimeConfig, order);
        }

        await _orderDomainService.AddAsync(order, true, HttpContext.RequestAborted);

        if (_systemSettingCacheManager.Snapshot && dto.IndustryId.NotNullOrEmpty() && dto.IndustryName.NotNullOrEmpty())
        {
            var snapshot = new OrderSnapshot
            {
                Id = order.Id,
                IndustryId = dto.IndustryId,
                IndustryName = dto.IndustryName
            };
            await _orderSnapshotRepository.AddAsync(snapshot, HttpContext.RequestAborted);
            order.Latitude = 29.33924;
            order.Longitude = 104.779307;
            await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
        }

        //订阅此事件的内部处理工单数据只能更新各自业务的字段，不能全部更新
        //新增工单其他处理事件  （受理短信）
        if (!string.IsNullOrEmpty(order.Contact) && order.Contact.Length == 11)
        {
            await _publisher.PublishAsync(new AddOrderNotify(order), PublishStrategy.ParallelWhenAll, HttpContext.RequestAborted);
        }

        //if (dto.Tags.Any()) await _repositoryts.AddVectorAsync(orderId, DateTime.Now, dto.Tags, HttpContext.RequestAborted);
        if (dto.RepeatableEventDetails?.Any() ?? false)
        {
            dto.RepeatableEventDetails.ForEach(x => x.OrderId = order.Id);
            List<RepeatableEventDetail> repeatables =
                _mapper.Map<List<RepeatableEventDetail>>(dto.RepeatableEventDetails);
            await _repeatableEventDetailRepository.AddRangeAsync(repeatables, HttpContext.RequestAborted);
        }


        //工单ID跟通话记录相关联
        //var callRecord = await _trCallRecordRepository.GetAsync(p => p.CallAccept == order.CallId, HttpContext.RequestAborted);//由CallAccept改为OtherAccept
        //var callRecord = await _trCallRecordRepository.GetAsync(p => p.OtherAccept == order.CallId && string.IsNullOrEmpty(p.OtherAccept) == false, HttpContext.RequestAborted);
        //if (callRecord != null && string.IsNullOrEmpty(callRecord.ExternalId))
        //{
        //    callRecord.ExternalId = order.Id;
        //    callRecord.CallOrderType = Share.Enums.CallCenter.ECallOrderType.Order;
        //    await _trCallRecordRepository.UpdateAsync(callRecord, HttpContext.RequestAborted);
        //}

        if (!string.IsNullOrEmpty(order.CallId))
            await _callApplication.RelateTianrunCallWithOrderAsync(order.CallId, order.Id, HttpContext.RequestAborted);

        //内容分词
        await _orderApplication.OrderParticiple(dto.Content, order.Id, order.No, order.Title, order.CreationTime, HttpContext.RequestAborted);
        //敏感分词
        await _orderApplication.OrderSensitiveParticiple(dto.Content, order.Id, HttpContext.RequestAborted);
        //知识库引用
        await _orderApplication.AddKnowledgeQuote(order.Id, order.Title, order.No, order.KnowledgeQuote, HttpContext.RequestAborted);
        ////sms
        //try
        //{
        //    if (order.AcceptSms)
        //    {
        //        _logger.LogInformation($"推送短信: orderNo: {order.No}");

        //        var messageDto = new Share.Dtos.Push.MessageDto
        //        {
        //            PushBusiness = EPushBusiness.OrderAccept,
        //            ExternalId = order.Id,
        //            OrderId = order.Id,
        //            PushPlatform = EPushPlatform.Sms,
        //            //Content =
        //            //  $"温馨提示：您的来电已受理（流水号：{order.No}；提取码：{order.Password}，可通过网站（http://hotline.12345lm.cn）进行查询，谢谢。【宜宾12345热线平台】）",
        //            Remark = order.Title,
        //            Name = order.FromName,
        //            TemplateCode = "1005",
        //            Params = new List<string>() { order.No, order.Password },
        //            TelNumber = order.Contact,
        //        };
        //        await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
        //        //await _pushDomainService.PushAsync(MessageDto, HttpContext.RequestAborted);

        //        order.SmsSended = true;
        //        await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
        //    }
        //}
        //catch (Exception e)
        //{
        //    _logger.LogError("新增工单发送短信失败，Error：{err}", e.Message);
        //}

        //2024-10-09 取消新增保存副本工单业务
        //// 副本工单
        //var copy = new OrderCopy();
        //_mapper.Map(order, copy);
        //copy.OrderId = order.Id;
        //copy.AuditTime = DateTime.Now;
        //copy.AuditUserId = _sessionContext.UserId;
        //copy.AuditUserName = _sessionContext.UserName;
        //copy.InitId();
        //await _orderCopyRepository.AddAsync(copy, HttpContext.RequestAborted);
        return new { Id = order.Id, No = order.No, Password = order.Password, CallId = order.CallId };
    }

    /// <summary>
    /// 提供ds调用
    /// </summary>
    [HttpPost("add-anonymous")]
    [AllowAnonymous]
    [LogFilter("省平台调用记录")]
    public async Task<AddOrderResponse> AddAnonymous([FromBody] AddOrderDto dto)
    {
        return await _orderApplication.ReceiveOrderFromExternalAsync(dto, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 提供ds调用--获取当天催办数量
    /// </summary>
    [HttpGet("get-orderurge-count")]
    [AllowAnonymous]
    public async Task<SubmitCaseTotalnfo> GetOrderUrgeCount()
    {
        var totle = await _orderUrgeRepository.Queryable()
            .Where(p => p.CreationTime >= Convert.ToDateTime(DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd 00:00:00")))
            .Where(p => p.CreationTime <= Convert.ToDateTime(DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd 23:59:59")))
            .CountAsync();
        return new SubmitCaseTotalnfo()
        {
            Totle = totle
        };
    }

    /// <summary>
    /// 提供ds调用
    /// </summary>
    [HttpPost("update-orderfiles")]
    [AllowAnonymous]
    public async Task UpdateOrderFilesAnonymous([FromBody] UpdateOrderFilesDto dto)
    {
        await _orderApplication.UpdateOrderFilesAnonymousAsync(dto, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 删除工单
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpDelete("{id}")]
    [LogFilter("删除工单")]
    public async Task Remove(string id)
    {
        var order = await _orderRepository.GetAsync(id, HttpContext.RequestAborted);
        if (order == null) return;
        if (order.Status != EOrderStatus.WaitForAccept)
            throw UserFriendlyException.SameMessage("非草稿工单不可删除");
        await _orderRepository.RemoveAsync(order);
    }

    /// <summary>
    /// 更新工单信息
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut]
    [LogFilter("更新工单")]
    public async Task<object> Update([FromBody] UpdateOrderDto dto)
    {
        dto.InitAddress();

        //工单保存特殊身份验证
        var specialIdentityVerification =
            bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.SpecialIdentityVerification).SettingValue[0]);

        if (specialIdentityVerification && !string.IsNullOrEmpty(dto.FromPhone))
        {
            var specialNumber = await _specialNumberRepository.GetAsync(p => p.PhoneNumber == dto.FromPhone, HttpContext.RequestAborted);
            if (specialNumber != null)
            {
                if (specialNumber.PoliticalIdentityValue == "1")
                {
                    if (dto.OrderPushTypes == null || dto.OrderPushTypes.Count() == 0 || dto.OrderPushTypes.Exists(p => p.PushTypeCode == "9") == false)
                        throw UserFriendlyException.SameMessage("人大代表来电，请选择推送分类人大代表意见快办！");
                }
                dto.PoliticalIdentityValue = specialNumber.PoliticalIdentityValue;
                dto.PoliticalIdentityName = specialNumber.PoliticalIdentityName;
            }
            else
            {
                dto.PoliticalIdentityValue = string.Empty;
                dto.PoliticalIdentityName = string.Empty;
            }
        }

        //泸州任务 311 投诉件需限制受理内容的字数等需求
        if (_appOptions.Value.IsLuZhou && dto.AcceptTypeCode == "35")
        {
            if (dto.SourceChannelCode != "S12345" && dto.SourceChannelCode != "SZMHD" && dto.SourceChannelCode != "XCX" &&
                dto.SourceChannelCode != "JCeT")
            {
                if (dto.Content.Length < 25)
                    throw UserFriendlyException.SameMessage("保存失败，投诉类型受理内容字数需要至少25个字!");

                if (dto.Title.Contains("咨询") || dto.Title.Contains("建议") || dto.Title.Contains("求助") || dto.Title.Contains("举报")
                    || dto.Content.Contains("咨询") || dto.Content.Contains("建议") || dto.Content.Contains("求助") || dto.Content.Contains("举报"))
                    throw UserFriendlyException.SameMessage("保存失败！投诉类型标题和受理内容不能出现'咨询、建议、求助、举报'");
            }
        }

        //交通工单校验
        var valid = await _orderDomainService.OrderValidation(dto, HttpContext.RequestAborted);
        if (valid.Validation)
            throw UserFriendlyException.SameMessage(valid.Result);

        var order = await _orderRepository.Queryable()
            .FirstAsync(d => d.Id == dto.Id);
        if (order == null)
            throw UserFriendlyException.SameMessage("无效工单编号");
        if (_appOptions.Value.IsZiGong != true)
        {
            if (dto.IsEdit != true && order.Status > EOrderStatus.HandOverToUnAccept)
                throw UserFriendlyException.SameMessage("工单已发起流程，不可编辑");
        }
        await _orderSnapshotApplication.UpdateOrderAsync(dto, HttpContext.RequestAborted);

        // 副本工单
        var copy = new OrderCopy();
        _mapper.Map(order, copy);
        copy.OrderId = order.Id;
        copy.AuditTime = DateTime.Now;
        copy.AuditUserId = _sessionContext.UserId;
        copy.AuditUserName = _sessionContext.UserName;
        copy.AuditSource = dto.IsEdit ? EOrderUpdateSource.Alter : EOrderUpdateSource.Accepted;
        copy.InitId();
        await _orderCopyRepository.AddAsync(copy, HttpContext.RequestAborted);

        if (order.Content != dto.Content)
            await _orderApplication.OrderParticiple(dto.Content, dto.Id, order.No, order.Title, order.CreationTime, HttpContext.RequestAborted);
        if (dto.RepeatableEventDetails?.Any() ?? false)
        {
            var reAdds = dto.RepeatableEventDetails.Where(x => string.IsNullOrEmpty(x.OrderId) && !x.IsDeleted)
                .ToList();
            var reDeletes = dto.RepeatableEventDetails.Where(x => !string.IsNullOrEmpty(x.OrderId) && x.IsDeleted)
                .ToList();
            reAdds.ForEach(x => x.OrderId = dto.Id);
            List<RepeatableEventDetail> repeatables = _mapper.Map<List<RepeatableEventDetail>>(reAdds);
            await _repeatableEventDetailRepository.AddRangeAsync(repeatables, HttpContext.RequestAborted);
            if (reDeletes?.Any() ?? false)
            {
                await _repeatableEventDetailRepository.DeleteAsync(reDeletes, HttpContext.RequestAborted);
            }
        }

        string acceptTypeCode = order.AcceptTypeCode;
        _mapper.Map(dto, order);
        if (order.SourceChannelCode != AppDefaults.SourceChannel.DianHua)
            order.CallId = null;

        if (dto.IsEdit && !string.IsNullOrEmpty(dto.CenterOpinion) && order.CenterToOrgOpinion != dto.CenterOpinion)
            order.CenterToOrgOpinion = dto.CenterOpinion;
        if (dto.IsEdit && !string.IsNullOrEmpty(dto.FileOpinion) && order.FileOpinion != dto.FileOpinion)
            order.FileOpinion = dto.FileOpinion;

        if (dto.Files.Any())
            order.FileJson = await _fileRepository.AddFileAsync(dto.Files, order.Id, "", HttpContext.RequestAborted);
        else
            order.FileJson = new List<Share.Dtos.File.FileJson>();

        var pushTypeAny = await _orderPushTypeRepository.AnyAsync(x => x.OrderId == order.Id);
        if (pushTypeAny)
        {
            await _orderPushTypeRepository.RemoveAsync(x => x.OrderId == order.Id);
            order.PushType = string.Empty;
            order.PushTypeCode = string.Empty;
        }

        // 工单推送分类
        if (dto.OrderPushTypes.Any())
        {
            dto.OrderPushTypes.ForEach(x => x.OrderId = order.Id);
            var orderPushTypes = _mapper.Map<List<OrderPushType>>(dto.OrderPushTypes);
            await _orderPushTypeRepository.AddRangeAsync(orderPushTypes);
            var pushTypes = dto.OrderPushTypes.Select(x => x.PushType);
            var pushTypeCode = dto.OrderPushTypes.Select(x => x.PushTypeCode);
            order.PushTypeCode = string.Join(",", pushTypeCode);
            order.PushType = string.Join(",", pushTypes);
        }

        order.OrderTags = new List<SystemDicData>();
        if (dto.Tags != null && dto.Tags.Any())
        {
            var orderTags = new List<SystemDicData>();
            foreach (var item in dto.Tags)
            {
                orderTags.Add(new SystemDicData() { Id = item });
            }

            order.OrderTags = orderTags;
            var dicData = await _sysDicDataRepository.Queryable().Where(p => dto.Tags.Contains(p.Id)).Select(p => p.DicDataValue).ToListAsync();
            if (dicData != null && dicData.Any())
            {
                order.OrderTagCode = String.Join(", ", dicData);
            }
        }
        else order.OrderTagCode = string.Empty;

        //处理工单的期满时间
        //首先是工单编辑页面提交的、流程已经开启、工单未归档的工单才能修改期满时间
        var isUpdateExpiredTime = false;
        if (dto.IsEdit && !string.IsNullOrEmpty(order.WorkflowId) && order.Status < EOrderStatus.Filed && dto.AcceptTypeCode != acceptTypeCode)
        {
            //查询当前工单的实际办理节点，如果在热线中心不处理，如果在部门需要更新期满时间
            var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, withTraces: true,
                cancellationToken: HttpContext.RequestAborted);
            var nowWorkflow = workflow.Steps.Where(p =>
                    p.Id == order.ActualHandleStepId && p.BusinessType >= EBusinessType.Department &&
                    p.BusinessType <= EBusinessType.DepartmentLeader)
                .FirstOrDefault();
            //在部门、中心到部门的交办时间不为空
            if (nowWorkflow != null && order.CenterToOrgTime.HasValue)
            {
                //计算期满时间
                ExpiredTimeWithConfig expiredTimeConfig = await _expireTime.CalcExpiredTime(order.CenterToOrgTime.Value, order.CenterToOrgTime.Value,
                    EFlowDirection.CenterToOrg,
                    order.Adapt<OrderTimeClacInfo>());
                if (expiredTimeConfig is not null && expiredTimeConfig.ExpiredTime > order.ExpiredTime)
                {
                    isUpdateExpiredTime = true;
                    order.ExpiredTime = expiredTimeConfig.ExpiredTime;
                    order.NearlyExpiredTime = expiredTimeConfig.NearlyExpiredTime;
                    order.NearlyExpiredTimeOne = expiredTimeConfig.NearlyExpiredTimeOne;
                }

                order.TimeLimit = expiredTimeConfig.TimeText;
                order.TimeLimitCount = expiredTimeConfig.Count;
                order.TimeLimitUnit = expiredTimeConfig.TimeType;
            }
        }

        var updateNavRootOptions = isUpdateExpiredTime
            ? new UpdateNavRootOptions { IgnoreColumns = ["CallId"] }
            : new UpdateNavRootOptions { IgnoreColumns = ["CallId", "ExpiredTime", "NearlyExpiredTime", "NearlyExpiredTimeOne"] };

        await _orderRepository.UpdateNav(order, updateNavRootOptions)
            .Include(d => d.OrderExtension)
            .Include(d => d.OrderTags).ExecuteCommandAsync();

        //订阅此事件的内部处理工单数据只能更新各自业务的字段，不能全部更新
        //修改工单其他处理事件  （受理短信）
        await _publisher.PublishAsync(new UpdateOrderNotify(order), PublishStrategy.ParallelWhenAll, HttpContext.RequestAborted);

        //敏感分词
        await _orderApplication.OrderSensitiveParticiple(dto.Content, order.Id, HttpContext.RequestAborted);
        //知识库引用
        await _orderApplication.AddKnowledgeQuote(order.Id, order.Title, order.No, order.KnowledgeQuote, HttpContext.RequestAborted);

        return new { Id = order.Id, No = order.No, Password = order.Password, CallId = order.CallId };
    }

    /// <summary>
    /// 开始工单办理流程
    /// </summary>
    [HttpPost("startflow")]
    public async Task StartFlow([FromBody] StartWorkflowDto<OrderHandleFlowDto> dto)
    {
        var validator = new BasicWorkflowDtoValidator();
        var validResult = validator.Validate(dto.Workflow);
        if (!validResult.IsValid)
            throw new UserFriendlyException(
                $"非法参数, {string.Join(',', validResult.Errors.Select(d => d.ErrorMessage))}");
        var order = await _orderDomainService.GetOrderAsync(dto.Data.OrderId, withExtension: true, cancellationToken: HttpContext.RequestAborted);
        if (!string.IsNullOrEmpty(order.WorkflowId))
            throw new UserFriendlyException($"该工单已开启办理流程, No:{order.No}", "该工单已开启办理流程");

        //交通工单校验
        //      UpdateOrderDto upOrder = _mapper.Map<UpdateOrderDto>(order);
        //var valid = await _orderDomainService.OrderValidation(upOrder, HttpContext.RequestAborted);
        //if (valid.Validation)
        //	throw UserFriendlyException.SameMessage(valid.Result);

        ExpiredTimeWithConfig expiredTimeConfig;
        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0];
        CityBaseConfiguration cityBase = JsonSerializer.Deserialize<CityBaseConfiguration>(setting);
        if (dto.Workflow.NextHandlers.Any(d => d.Key == cityBase.CityProvince.OrgId || d.Key == cityBase.CityProvinceAssign.OrgId))
        {
            if (dto.Workflow.NextHandlers.Any(d => d.Key == cityBase.CityProvince.OrgId) && order.OrderExtension is null)
            {
                throw UserFriendlyException.SameMessage("该工单不存在拓展信息,不能推送至全国12315平台!");
            }

            var timeResult = await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, ETimeType.WorkDay, 45, 80, 50);
            expiredTimeConfig = new ExpiredTimeWithConfig
            {
                Count = 45,
                TimeType = ETimeType.WorkDay,
                TimeText = "45个工作日",
                ExpiredTime = timeResult.EndTime,
                NearlyExpiredTime = timeResult.NearlyExpiredTime,
                NearlyExpiredTimeOne = timeResult.NearlyExpiredTimeOne,
            };
        }
        else
        {
            if (_appOptions.Value.IsZiGong)
            {
                if (dto.Workflow.FlowDirection.HasValue && dto.Workflow.FlowDirection == EFlowDirection.CenterToCenter)
                {
                    expiredTimeConfig = await _expireTime.CalcExpiredTime(DateTime.Now, DateTime.Now, EFlowDirection.CenterToCenter,
                        order.Adapt<OrderTimeClacInfo>());
                }
                else
                {
                    expiredTimeConfig = await _expireTime.CalcExpiredTime(DateTime.Now, DateTime.Now, EFlowDirection.CenterToOrg,
                        order.Adapt<OrderTimeClacInfo>());
                }
            }
            else
            {
                //期满时间
                expiredTimeConfig =
                    await _expireTime.CalcExpiredTime(DateTime.Now, DateTime.Now, EFlowDirection.CenterToOrg, order.Adapt<OrderTimeClacInfo>());
            }
        }

        order.IsForwarded = dto.Workflow.IsForwarded;
        _mapper.Map(expiredTimeConfig, order);

        if (dto.Workflow.BusinessType is EBusinessType.Department or EBusinessType.DepartmentLeader)
            order.ProcessType = EProcessType.Jiaoban;

        await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);

        try
        {
            var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
            startDto.DefinitionModuleCode = await _orderSnapshotApplication.GetStartflowAsync(order.Id, HttpContext.RequestAborted);
            startDto.Title = order.Title;
            var (workflow, startStep) =
                await _workflowDomainService.StartAsync(startDto, order.Id, order.ExpiredTime, cancellationToken: HttpContext.RequestAborted);

            await HandleOrderAsync(order, workflow, startStep, dto.Data, dto.Workflow, HttpContext.RequestAborted);
        }
        catch (Exception e)
        {
            _logger.LogError($"工单开启流程失败!, {e.Message}, {e.StackTrace}");
            throw new UserFriendlyException($"工单开启流程失败!, {e.Message}, {e.StackTrace}", "工单开启流程失败");
        }

        if ((_appOptions.Value.IsYiBin || _appOptions.Value.IsLuZhou) && order.Transpond.HasValue && order.Transpond.Value)
        {
            //开启流程处理事件，处理市州互转
            await _publisher.PublishAsync(new OrderStartWorkflowNotify(order.Id), PublishStrategy.ParallelWhenAll,
                HttpContext.RequestAborted);
        }
    }

    /// <summary>
    /// 查询工单办理流程开启参数
    /// </summary>
    /// <returns></returns>
    [HttpGet("startflow")]
    public async Task<NextStepsDto> GetFlowStartOptions([FromQuery] string? orderId)
    {
        var modelCode = await _orderSnapshotApplication.GetStartflowAsync(orderId, HttpContext.RequestAborted);
        var dto = await _workflowApplication.GetStartStepsAsync(modelCode, HttpContext.RequestAborted);
        if (orderId.NotNullOrEmpty())
        {
            dto.Opinion = await _typeCache.GetAsync($"tmp_opinion_{orderId}{_sessionContext.UserId}", HttpContext.RequestAborted);
            if (!string.IsNullOrEmpty(dto.Opinion))
            {
                dto.Opinion = await _typeCache.GetAsync($"tmp_opinion_{orderId}{dto.StepId}{_sessionContext.UserId}", HttpContext.RequestAborted);
            }
            dto.Content = (await _orderRepository.GetAsync(orderId, HttpContext.RequestAborted))?.Content;
        }

        var isAqyh = false; //行业类型是否为随手拍安全隐患
        if (_systemSettingCacheManager.Snapshot)
        {
            var orderSnapShot = await _orderSnapshotRepository.GetAsync(orderId, HttpContext.RequestAborted);
            if (orderSnapShot != null && string.CompareOrdinal(orderSnapShot.IndustryName, "安全隐患") == 0)
            {
                isAqyh = true;
                dto.Steps.RemoveAll(d => d.BusinessType == EBusinessType.Send);
            }
        }

        if (!isAqyh)
            dto.Steps = dto.Steps.Where(d => string.CompareOrdinal(d.Value, "网格员") != 0
                                             && string.CompareOrdinal(d.Value, "工单标记") != 0).ToList();

        return dto;
    }

    /// <summary>
    /// 工单办理
    /// </summary>
    [HttpPost("handle")]
    public async Task Handle([FromBody] NextWorkflowDto<OrderHandleFlowDto> dto)
    {
        var validator = new BasicWorkflowDtoValidator();
        var validResult = validator.Validate(dto.Workflow);
        if (!validResult.IsValid)
            throw new UserFriendlyException(
                $"非法参数, {string.Join(',', validResult.Errors.Select(d => d.ErrorMessage))}");

        var workflow = await _workflowDomainService.GetWorkflowAsync(dto.Workflow.WorkflowId, withDefine: true, withSteps: true, withTraces: true,
            cancellationToken: HttpContext.RequestAborted);

        #region 中心归档，自动延期一天

        if (dto.Workflow.NextStepCode == "end" && _appOptions.Value.IsYiBin && _sessionContext.OrgIsCenter)
        {
            var dOrder = await _orderRepository.GetAsync(workflow.ExternalId, HttpContext.RequestAborted);
            if (dOrder != null && dOrder.ExpiredTime < DateTime.Now)
            {
                var delays = await _orderDelayRepository.Queryable().Where(x => x.OrderId == dOrder.Id && x.AutomaticDelayNum > 0)
                    .ToListAsync(HttpContext.RequestAborted);
                var delayOrder = new OrderDelay();
                if (delays.Any())
                {
                    delayOrder = delays.First();
                    var startTime = DateTime.Now;
                    if (dOrder.CenterToOrgTime.HasValue)
                    {
                        startTime = dOrder.CenterToOrgTime.Value;
                    }

                    delayOrder.AfterDelay = (await _expireTime
                        .CalcEndTime(startTime, startTime, delayOrder.DelayUnit, delayOrder.DelayNum, dOrder.AcceptTypeCode))?.EndTime; //todo
                    await _orderDelayRepository.Updateable().SetColumns(x => new OrderDelay()
                    { AutomaticDelayNum = x.AutomaticDelayNum + 1, ApplyDelayTime = DateTime.Now, AfterDelay = delayOrder.AfterDelay })
                        .Where(x => x.Id == delayOrder.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                }
                else
                {
                    delayOrder.OrderId = dOrder.Id;
                    delayOrder.EmployeeId = "";
                    delayOrder.EmployeeName = "系统自动延期";
                    delayOrder.ApplyOrgName = OrgSeedData.CenterName;
                    delayOrder.ApplyOrgCode = OrgSeedData.CenterId;
                    delayOrder.DelayApplyType = EDelayApplyType.LocalApply;
                    delayOrder.BeforeDelay = dOrder.ExpiredTime;
                    delayOrder.DelayState = EDelayState.Pass;
                    delayOrder.DelayReason = "系统自动延期";
                    delayOrder.ApplyDelayTime = DateTime.Now;
                    delayOrder.No = dOrder.No;
                    delayOrder.AutomaticDelayNum = 1;
                    delayOrder.DelayNum = 1;
                    delayOrder.DelayUnit = Share.Enums.Settings.ETimeType.WorkDay;
                    delayOrder.IsProDelay = false;
                    delayOrder.CreatorOrgId = OrgSeedData.CenterId;
                    delayOrder.CreatorOrgName = OrgSeedData.CenterName;
                    delayOrder.CreatorName = "系统自动延期";
                    var startTime = DateTime.Now;
                    if (dOrder.CenterToOrgTime.HasValue)
                    {
                        startTime = dOrder.CenterToOrgTime.Value;
                    }

                    if (delayOrder.BeforeDelay != null)
                    {
                        delayOrder.AfterDelay = (await _expireTime
                                .CalcEndTime(delayOrder.BeforeDelay.Value, startTime, delayOrder.DelayUnit, delayOrder.DelayNum,
                                    dOrder.AcceptTypeCode))
                            ?.EndTime; //todo
                    }

                    await _orderDelayRepository.AddAsync(delayOrder, false, HttpContext.RequestAborted);
                }

                //处理工单延期
                await _orderApplication.DelayOrderExpiredTimeAsync(dOrder.Id, delayOrder.DelayNum,
                    delayOrder.DelayUnit, delayOrder.IsProDelay, HttpContext.RequestAborted);
            }
        }

        #endregion

        var order = await _orderApplication.SaveOrderWorkflowInfo(dto, HttpContext.RequestAborted);

        //预警模块
        if (bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsEarly).SettingValue[0]))
        {
            if (dto.Data.DispatchEarlyWarning != null && dto.Data.DispatchEarlyWarning.Count > 0)
            {
                var model = await _orderEarlyWarningRepository.Queryable().Where(x => x.OrderId == order.Id).FirstAsync(HttpContext.RequestAborted);
                if (model != null)
                {
                    model.DispatchEarlyWarning = _mapper.Map<List<EarlyWarningSetting>>(dto.Data.DispatchEarlyWarning);
                    //model.DispatchEarlyWarning = model.CanChooseEarlyWarning?.Where(x => dto.Data.DispatchEarlyWarning.Select(d=>d.Id).Contains(x.Id)).ToList();
                    await _orderEarlyWarningRepository.UpdateAsync(model, HttpContext.RequestAborted);
                    await _publisher.PublishAsync(new OrderEarlyWarningNotify(order, model.DispatchEarlyWarning), PublishStrategy.ParallelWhenAll, HttpContext.RequestAborted);
                }
            }
        }


        // 随手拍业务处理
        await _orderSnapshotApplication.SaveOrderWorkflowInfo(dto);

        //await _workflowApplication.NextAsync(dto.WorkflowDto, order.ExpiredTime, HttpContext.RequestAborted);
        var startStep = workflow.Steps.First(d => d.Id == dto.Workflow.StepId);
        await HandleOrderAsync(order, workflow, startStep, dto.Data, dto.Workflow, HttpContext.RequestAborted);

        if (_appOptions.Value.IsZiGong && dto.Data.Transpond.HasValue && dto.Data.Transpond.Value)
        {
            var count = await _transpondCityRawDataRepository.Queryable()
                .CountAsync(m => m.OrderCode == order.No && m.CityName == order.TranspondCityName
                                                         && m.Direction == ETranspondDirection.Out, HttpContext.RequestAborted);
            //处理市州互转
            if (count == 0)
                await _publisher.PublishAsync(new OrderStartWorkflowNotify(order.Id), PublishStrategy.ParallelWhenAll, HttpContext.RequestAborted);
        }
    }

    /// <summary>
    /// 工单批量标注是否安全生产
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut("sign/bath")]
    public async Task<string> OrderSignBathAsync([FromBody] OrderSignBathInDto dto)
    {
        var stringBuilder = new StringBuilder();
        if (dto.Status == 1)
        {
            foreach (var orderId in dto.OrderIds)
            {
                var order = await _orderRepository.GetAsync(orderId, HttpContext.RequestAborted);
                if (order is null)
                {
                    continue;
                }

                var snapshot = await _orderSnapshotApplication.UpdateSafetyAsync(orderId, dto.IsSafetyDepartment, dto.Remark);
                if (snapshot is null)
                {
                    stringBuilder.Append($"随手拍: {order.No} 不存在");
                    continue;
                }

                var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withDefine: true, withSteps: true, withTraces: true,
                    cancellationToken: HttpContext.RequestAborted);

                NextStepsWithOpinionDto<NextStepOption> nextSteps;
                try
                {
                    nextSteps = await _workflowApplication.GetNextStepsAsync(order.WorkflowId, HttpContext.RequestAborted);
                }
                catch (UserFriendlyException e)
                {
                    if (e.Message.Contains("未找到对应节点"))
                    {
                        stringBuilder.AppendLine($"{order.No} " + e.Message);
                        continue;
                    }

                    throw;
                }

                var stepInfo = nextSteps.Steps.FirstOrDefault(m => m.BusinessType == EBusinessType.Send);
                if (stepInfo == null)
                {
                    stringBuilder.Append($"下一步节点: [派单组] 未找到");
                    continue;
                }

                var data = new OrderHandleFlowDto
                {
                    OrderId = orderId,
                    IsSafetyDepartment = dto.IsSafetyDepartment
                };
                var workflowDto = new NextWorkflowDto
                {
                    WorkflowId = order.WorkflowId,
                    StepId = nextSteps.StepId,
                    NextStepCode = stepInfo.Key,
                    NextStepName = stepInfo.Value,
                    Opinion = dto.Remark,
                    BackToCountersignEnd = false,
                    IsSms = false,
                    IsForwarded = false,
                    HandlerType = EHandlerType.OrgLevel,
                    BusinessType = EBusinessType.Send,
                    FlowDirection = EFlowDirection.CenterToCenter,
                };
                var startStep = workflow.Steps.First(d => d.Id == nextSteps.StepId);
                await HandleOrderAsync(order, workflow, startStep, data, workflowDto, HttpContext.RequestAborted);
                stringBuilder.AppendLine($"{orderId} 标注完成;");
            }
        }
        else
        {
            var orderNo = await _redPackAuditRepository.Queryable()
                .LeftJoin<Order>((m, order) => m.OrderId == order.Id)
                .Where(m => dto.OrderIds.Contains(m.OrderId) && m.Status != ERedPackAuditStatus.Pending)
                .Select((m, order) => order.No)
                .ToListAsync();
            if (orderNo.NotNullOrEmpty())
                throw new UserFriendlyException("该工单已红包审批，无法修改标记状态！");
            else
            {
                await _orderSnapshotRepository.Updateable()
                    .SetColumns(m => m.IsSafetyDepartment, dto.IsSafetyDepartment)
                    .SetColumns(m => m.SignRemark, dto.Remark)
                    .Where(m => dto.OrderIds.Contains(m.Id))
                    .ExecuteCommandAsync();
                stringBuilder.AppendLine("标注完成;");
            }
        }

        return stringBuilder.ToString();
    }

    private async Task HandleOrderAsync(Order order, Workflow workflow, WorkflowStep startStep, OrderHandleFlowDto orderHandleFlowDto,
        BasicWorkflowDto workflowDto, CancellationToken cancellationToken)
    {
        var isAutoFillSummaryOpinion = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsAutoFillSummaryOpinion).SettingValue[0]);

        switch (orderHandleFlowDto.OrderAssignMode)
        {
            case EOrderAssignMode.AdjoinLevel: // 逐级
                var nextDto = _mapper.Map<NextWorkflowDto>(workflowDto);
                nextDto.WorkflowId = startStep.WorkflowId;
                nextDto.StepId = startStep.Id;

                if (workflowDto.BusinessType == EBusinessType.Send)
                {
                    // 宜宾需求： 1.是否是派单节点  2.是否存在历史派单节点  3.存在获取上个派单节点  4.不存在走平均派单   过滤历史派单节点不为派单池
                    if (_appOptions.Value.IsYiBin || _appOptions.Value.IsZiGong)
                    {
                        var sendOrderTrace = workflow.Traces
                            .Where(x => x.BusinessType == EBusinessType.Send && x.HandlerId != AppDefaults.SendPoolId)
                            .MaxBy(x => x.CreationTime);
                        var prevSendOrder = sendOrderTrace is not null;
                        if (_appOptions.Value.IsZiGong && prevSendOrder)
                        {
                            prevSendOrder = await _orderDomainService.SchedulingAtWork(sendOrderTrace.HandlerId);
                        }
                        if (prevSendOrder)
                        {
                            //todo
                            nextDto.NextHandlers = new List<StepAssignInfo>
                            {
                                new()
                                {
                                    Key = sendOrderTrace.HandlerId, Value = sendOrderTrace.HandlerName,
                                    UserId = sendOrderTrace.HandlerId, Username = sendOrderTrace.HandlerName,
                                    OrgId = sendOrderTrace.HandlerOrgId, OrgName = sendOrderTrace.HandlerOrgName,
                                    FlowAssignType = EFlowAssignType.User
                                }
                            };
                        }
                        else
                        {
                            await AverageSendOrderAsync(nextDto, HttpContext.RequestAborted);
                        }
                    }
                    else
                    {
                        await AverageSendOrderAsync(nextDto, HttpContext.RequestAborted);
                    }

                    // var flowStepHandler = nextDto.NextHandlers.FirstOrDefault();
                    // await _orderRepository.Updateable().SetColumns(o => new Order()
                    // {
                    //     CenterToOrgHandlerId = flowStepHandler.UserId,
                    //     CenterToOrgHandlerName = flowStepHandler.Username
                    // }).Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                }

                var (_, currentStep, _, _) = await _workflowDomainService.NextAsync(nextDto,
                    expiredTime: order.ExpiredTime,
                    isAutoFillSummaryOpinion: isAutoFillSummaryOpinion,
                    newStepConfig: OrderHandleNewStepConfig(),
                    cancellationToken: cancellationToken);
                if (currentStep.BusinessType is EBusinessType.Send)
                {
                    await _orderRepository.Updateable().SetColumns(o => new Order()
                    {
                        CenterToOrgHandlerId = currentStep.HandlerId,
                        CenterToOrgHandlerName = currentStep.HandlerName
                    }).Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                }

                break;
            case EOrderAssignMode.CrossLevel: // 跨级
                if (!orderHandleFlowDto.CrossSteps.Any())
                    throw new UserFriendlyException("跨级指派参数异常");

                orderHandleFlowDto.CrossSteps = orderHandleFlowDto.CrossSteps.OrderBy(d => d.Sort).ToList();
                var stepCount = orderHandleFlowDto.CrossSteps.Count;
                var unhandleSteps = new List<WorkflowStep> { startStep };
                for (int i = 0; i < stepCount; i++)
                {
                    var crossStep = orderHandleFlowDto.CrossSteps[i];
                    var tempSteps = new List<WorkflowStep>();
                    foreach (var unhandleStep in unhandleSteps)
                    {
                        var lowerLevelHandlers = crossStep.NextHandlers.Where(d => d.OrgId.StartsWith(unhandleStep.HandlerOrgId)).ToList();
                        if (!lowerLevelHandlers.Any()) continue;
                        var nextflowDto = _mapper.Map<NextWorkflowDto>(crossStep);
                        nextflowDto.WorkflowId = unhandleStep.WorkflowId;
                        nextflowDto.StepId = unhandleStep.Id;
                        nextflowDto.IsStartCountersign = lowerLevelHandlers.Count > 1;
                        nextflowDto.NextHandlers = lowerLevelHandlers;
                        if (unhandleStep.Id != startStep.Id)
                            nextflowDto.Opinion = "跨级派单，自动办理";

                        //var operater = new FakeSessionContext
                        //{
                        //    OrgId = unhandleStep.HandlerOrgId,
                        //    OrgName = unhandleStep.HandlerOrgName,
                        //};
                        if (unhandleStep.BusinessType is EBusinessType.Department)
                        {
                            var operater = await _orderApplication.GetHandlerRandomAsync(unhandleStep, cancellationToken);
                            // await _sessionContext.ChangeSessionAsync(operater.Id, cancellationToken);
                            await _sessionContextManager.ChangeSessionContextByUserIdAsync(operater.Id, cancellationToken);
                        }

                        var (_, _, _, nextSteps) = await _workflowDomainService.NextAsync(nextflowDto,
                            EHandleMode.CrossLevel, order.ExpiredTime,
                            isAutoFillSummaryOpinion,
                            newStepConfig: OrderHandleNewStepConfig(),
                            cancellationToken: cancellationToken);
                        tempSteps.AddRange(nextSteps);
                    }

                    unhandleSteps = tempSteps;
                }

                break;
            case EOrderAssignMode.MainAndSecondary:
                //主协办暂只支持指派给部门办理，且主办部门有且只有一个一级部门
                nextDto = _mapper.Map<NextWorkflowDto>(workflowDto);
                nextDto.WorkflowId = startStep.WorkflowId;
                nextDto.StepId = startStep.Id;
                nextDto.HandlerType = EHandlerType.OrgLevel;
                nextDto.FlowDirection = EFlowDirection.CenterToOrg;
                var secondaryOrgs = orderHandleFlowDto.SecondaryOrgs.DistinctBy(d => d.Id).ToList();
                var nextHandleOrgs = secondaryOrgs
                    .Where(d => d.Level == 1 && d.Id.StartsWith(OrgSeedData.CenterId))
                    .ToList();
                if (nextHandleOrgs.Any())
                    nextDto.NextHandlers.AddRange(nextHandleOrgs.Select(d => new StepAssignInfo
                    {
                        Key = d.Id,
                        Value = d.Name,
                        OrgId = d.Id,
                        OrgName = d.Name,
                        FlowAssignType = EFlowAssignType.Org
                    }));
                nextDto.IsStartCountersign = nextDto.NextHandlers.Count > 1;

                await HandleNextInMainAndSecondaryAsync(workflow.WorkflowDefinition,
                    secondaryOrgs, nextDto, order.ExpiredTime, isAutoFillSummaryOpinion,
                    cancellationToken);

                //抄送
                var ccs = orderHandleFlowDto.Copys
                    .Where(d => !string.IsNullOrEmpty(d.OrgId)
                                || !string.IsNullOrEmpty(d.RoleId)
                                || !string.IsNullOrEmpty(d.UserId))
                    .Select(d => _mapper.Map<OrderCarboncopy>(d))
                    .Distinct()
                    .ToList();
                ccs.ForEach(d => d.OrderId = order.Id);
                await _orderCarboncopy.AddRangeAsync(ccs, HttpContext.RequestAborted);

                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
    }

    private static Action<Workflow, WorkflowStep, StepDefine, WorkflowStep>? OrderHandleNewStepConfig()
    {
        return (_, _, stepDefine, newStep) =>
        {
            if (stepDefine.BusinessType is EBusinessType.Department)
            {
                newStep.HandlerId = null;
                newStep.HandlerName = null;
            }
        };
    }

    private async Task HandleNextInMainAndSecondaryAsync(WorkflowDefinition definition, List<OrgDto> orgs,
        NextWorkflowDto? flowDto, DateTime? expiredTime, bool isAutoFillSummaryOpinion, CancellationToken cancellation)
    {
        if (flowDto is null || !flowDto.NextHandlers.Any()) return;
        var (_, _, _, currentSteps) = await _workflowDomainService.NextAsync(flowDto,
            expiredTime: expiredTime,
            isAutoFillSummaryOpinion: isAutoFillSummaryOpinion,
            newStepConfig: OrderHandleNewStepConfig(),
            cancellationToken: cancellation);

        foreach (var currentStep in currentSteps)
        {
            var currentStepHandlerOrgId = currentStep?.HandlerOrgId;
            if (string.IsNullOrEmpty(currentStepHandlerOrgId))
                throw new UserFriendlyException($"数据异常, 待办部门id为空, stepId: {currentStep.Id}");
            var nextStepHandlerOrgLevel = currentStepHandlerOrgId.CalcOrgLevel() + 1;
            var nextHandlers = orgs.Where(d => d.Level == nextStepHandlerOrgLevel && d.Id.StartsWith(currentStepHandlerOrgId))
                .Select(d => new StepAssignInfo
                {
                    Key = d.Id,
                    Value = d.Name,
                    OrgId = d.Id,
                    OrgName = d.Name,
                    FlowAssignType = EFlowAssignType.Org
                })
                .ToList();
            if (nextHandlers.Any())
            {
                var nextStepDefine = definition.FindStepDefines(currentStep.NextSteps.Select(d => d.Code))
                    .FirstOrDefault(d =>
                        d.HandlerType == EHandlerType.OrgLevel &&
                        d.HandlerTypeItems.Any(x => x.Key == nextStepHandlerOrgLevel.ToString()));
                if (nextStepDefine == null)
                    throw new UserFriendlyException($"流程模板未配置该部门等级, defineId: {definition.Id}, level: {nextStepHandlerOrgLevel}");

                var nextDto = new NextWorkflowDto
                {
                    WorkflowId = flowDto.WorkflowId,
                    StepId = currentStep.Id,
                    NextStepCode = nextStepDefine.Code,
                    NextStepName = nextStepDefine.Name,
                    FlowDirection = EFlowDirection.OrgToOrg,
                    HandlerType = nextStepDefine.HandlerType,
                    StepType = nextStepDefine.StepType,
                    IsSms = false,
                    NextHandlers = nextHandlers,
                    IsStartCountersign = nextHandlers.Count > 1,
                    BusinessType = nextStepDefine.BusinessType,
                };

                if (currentStep.BusinessType is EBusinessType.Department)
                {
                    var operater = await _orderApplication.GetHandlerRandomAsync(currentStep, cancellation);
                    // await _sessionContext.ChangeSessionAsync(operater.Id, cancellation);
                    await _sessionContextManager.ChangeSessionContextByUserIdAsync(operater.Id, cancellation);
                }

                await HandleNextInMainAndSecondaryAsync(definition, orgs, nextDto, expiredTime, isAutoFillSummaryOpinion, cancellation);
            }
        }
    }

    private async Task AverageSendOrderAsync(NextWorkflowDto nextDto, CancellationToken cancellationToken)
    {
        if (!nextDto.NextHandlers.Any())
        {
            // 平均派单
            var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
            if (averageSendOrder)
            {
                var handler = await _orderDomainService.AverageOrder(cancellationToken);
                nextDto.NextHandlers = new List<StepAssignInfo> { handler };
            }
        }
    }

    /// <summary>
    /// 跨级指派查询下一步可选节点及办理对象参数
    /// </summary>
    /// <returns></returns>
    [HttpGet("nextsteps/cross")]
    public async Task<NextStepsDto<NextStepOption>> GetCrossLevelStepsOptions([FromQuery] GetCrossLevelStepsDto dto)
    {
        return await _workflowApplication.GetCrossLevelStepsAsync(dto, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 查询工单办理下一步可选节点(带推荐部门)
    /// </summary>
    [HttpGet("nextsteps/{orderId}")]
    public async Task<NextStepsWithOpinionDto<RecommendStepOption>> GetNextStepsWithRecommend(string orderId)
    {
        var order = await _orderDomainService.GetOrderAsync(orderId, cancellationToken: HttpContext.RequestAborted);

        if (string.IsNullOrEmpty(order.WorkflowId))
            throw UserFriendlyException.SameMessage("该工单未开启流程");
        var dto = await _workflowApplication.GetNextStepsAsync(order.WorkflowId, HttpContext.RequestAborted);

        dto.ExpiredTime = order.ExpiredTime;
        dto.Content = order.Content;
        var rsp = _mapper.Map<NextStepsWithOpinionDto<RecommendStepOption>>(dto);
        var org = await _organizeRepository.GetAsync(d => d.AreaCode == order.AreaCode, HttpContext.RequestAborted);
        if (org != null)
        {
            foreach (var step in rsp.Steps)
            {
                if (dto.CurrentStepBusinessType is not EBusinessType.Send ||
                    step.BusinessType is not EBusinessType.Department) continue;
                step.RecommendOrgId = org.Id;
                step.RecommendOrgName = org.Name;
            }
        }

        rsp.LeaderSMS = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.LeaderSMS)
            .Select(m => new Kv { Key = m.Id, Value = m.DicDataName }).ToList();
        var opinion = await _typeCache.GetAsync($"tmp_opinion_{orderId}{_sessionContext.UserId}", HttpContext.RequestAborted);
        if (opinion.NotNullOrEmpty())
        {
            rsp.Opinion = opinion;
        }

        rsp.TranspondCity = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.TranspondCity)
            .ToList().Adapt<List<SystemDicDataOutDto>>();

        rsp.CounterSignType = order.CounterSignType;

        //随手拍业务逻辑处理，并查询行业类型是否为随手拍安全隐患
        var isAqyh = await _orderSnapshotApplication.GetNextStepsDatabaseAsync(rsp, orderId);
        if (!isAqyh)
            rsp.Steps = rsp.Steps.Where(d => string.CompareOrdinal(d.Value, "网格员") != 0
                                             && string.CompareOrdinal(d.Value, "工单标记") != 0).ToList();

        return rsp;
    }

    /// <summary>
    /// 临时保存
    /// </summary>
    [HttpPost("steps/temp")]
    public async Task TempSaveAsync([FromBody] StepTempInDto dto)
    {
        if (dto.OrderId.IsNullOrEmpty() || dto.Opinion.IsNullOrEmpty()) return;
        //获取配置
        int days = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.TempOpinionDays)?.SettingValue[0]);
        await _typeCache.SetAsync($"tmp_opinion_{dto.OrderId}{dto.StepId}{_sessionContext.UserId}", dto.Opinion, TimeSpan.FromDays(days),
            HttpContext.RequestAborted);
    }

    /// <summary>
    /// 查询工单办理下一步可选节点(带推荐部门)工单代办业务
    /// </summary>
    [HttpGet("nextsteps_commission/{orderId}")]
    public async Task<NextStepsWithOpinionDto<RecommendStepOption>> GetNextStepsWithRecommendCommission(string orderId)
    {
        var order = await _orderDomainService.GetOrderAsync(orderId, cancellationToken: HttpContext.RequestAborted);
        if (string.IsNullOrEmpty(order.WorkflowId))
            throw UserFriendlyException.SameMessage("该工单未开启流程");
        var unhandleSteps =
            await _workflowDomainService.GetUnhandleStepsByOthersAsync(order.WorkflowId, HttpContext.RequestAborted);
        if (unhandleSteps.Count > 1)
            throw UserFriendlyException.SameMessage("会签工单不允许班长代办");
        if (unhandleSteps.Count < 1)
            throw UserFriendlyException.SameMessage("未查询到流程信息");
        var stepOne = unhandleSteps.First();
        if (stepOne.IsInCountersign())
            throw UserFriendlyException.SameMessage("会签工单不允许班长代办");
        var dto = await _workflowApplication.GetNextStepsAsync(order.WorkflowId, stepOne.Id, HttpContext.RequestAborted);
        dto.ExpiredTime = order.ExpiredTime;
        var rsp = _mapper.Map<NextStepsWithOpinionDto<RecommendStepOption>>(dto);
        foreach (var step in rsp.Steps)
        {
            if (dto.CurrentStepBusinessType is not EBusinessType.Send ||
                step.BusinessType is not EBusinessType.Department) continue;
            var org = await _organizeRepository.GetAsync(d => d.AreaCode == order.AreaCode, HttpContext.RequestAborted);
            if (org is null) continue;
            step.RecommendOrgId = org.Id;
            step.RecommendOrgName = org.Name;
        }

        return rsp;
    }

    /// <summary>
    /// 结束会签
    /// </summary>
    [HttpPost("endcs")]
    public async Task EndCountersign([FromBody] EndCountersignDto dto)
    {
        await _orderApplication.EndCountersignAsync(dto, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 查询工单办理的期满时间配置
    /// </summary>
    [HttpGet("time-config")]
    public async Task<TimeConfig> GetOrderHandleTimeConfigByAcceptType(EFlowDirection flowDirection, string? acceptTypeCode)
    {
        return flowDirection switch
        {
            //EFlowDirection.CenterToOrg => _timeLimitDomainService.GetOrderTimeLimitConfig(acceptTypeCode),
            EFlowDirection.CenterToOrg => _expireTime.GetOrderTimeLimitConfig(acceptTypeCode),
            //EFlowDirection.OrgToCenter => _timeLimitDomainService.GetOrderTimeLimitConfig(),
            EFlowDirection.OrgToCenter => _expireTime.GetOrderTimeLimitConfig(),
            _ => throw new ArgumentOutOfRangeException(nameof(flowDirection), flowDirection, null)
        };
    }

    /// <summary>
    /// 列表页面基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("base-data")]
    public async Task<object> BaseData()
    {
        var wfModule = await _workflowApplication.GetWorkflowModuleAsync(WorkflowModuleConsts.OrderHandle, HttpContext.RequestAborted);
        var definition = wfModule.Definition;
        var rsp = new
        {
            TranspondCity = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.TranspondCity),
            AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType),
            ChannelOptions = _sysDicDataCacheManager.GetSysDicDataCache(TimeLimitBaseDataConsts.SourceChannel),
            OrgsOptions = await _organizeRepository.GetOrgJson(),
            EmergencyLevelOptions = EnumExts.GetDescriptions<EEmergencyLevel>(),
            PushTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.PushType),
            OrderStatusOptions = EnumExts.GetDescriptions<EOrderStatus>(),
            CurrentStepOptions = definition?.Steps.Select(x => new Kv(x.Code, x.Name)),
            IdentityTypeOptions = EnumExts.GetDescriptions<EIdentityType>(),
            OrderTags = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderTag),
            FocusOnEvents = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.FocusOnEvent),
            PoliticalIdentity = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.PoliticalIdentity),
            SeatEvaluate = EnumExts.GetDescriptions<ESeatEvaluate>(),
            VisitSatisfaction = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction),
        };
        return rsp;
    }

    /// <summary>
    /// 预警基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("early-base-data")]
    public async Task<object> EarlyBaseData()
    {
        var rsp = new
        {
            EarlyWarningLevel = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.EarlyWarningLevel),
            EarlyWarningType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.EarlyWarningType),
        };
        return rsp;
    }

    /// <summary>
    /// 新增页面基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("base-data-add")]
    public async Task<object> BaseDataAdd()
    {
        //是否行政执法类工单
        var IsOpenJudicialManagement = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsOpenJudicialManagement).SettingValue[0]);
        //重点关注事件
        var FocusOnEvents = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.FocusOnEvent).ToList();
        if (!IsOpenJudicialManagement)
        {
            var xingzhengzhifa = FocusOnEvents.FirstOrDefault(d => d.DicDataValue == "2");
            if (xingzhengzhifa is not null)
                FocusOnEvents.Remove(xingzhengzhifa);
        }

        //List<Kv> FocusOnEvents = new()
        //{
        //    new Kv { Key = "0", Value = "紧急工单" },
        //    new Kv { Key = "1", Value = "形式主义工单" },
        //    new Kv { Key = "3", Value = "敏感类工单" }
        //};
        //if (IsOpenJudicialManagement)
        //    FocusOnEvents.Add(new Kv { Key = "2", Value = "行政执法类工单" });

        ////todo 宜宾add 1，3
        ////todo 自贡add 4
        //FocusOnEvents.Add(new Kv { Key = "4", Value = "24小时办结" });

        var industryItems = await _industryRepository.Queryable()
            .Select(d => new { d.Id, d.Name, })
            .ToListAsync();
        var rsp = new
        {
            Industry = industryItems,
            TranspondCity = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.TranspondCity),
            ChannelOptions = _sysDicDataCacheManager.GetSysDicDataCache(TimeLimitBaseDataConsts.SourceChannel),
            AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType),
            //EmergencyLevelOptions = EnumExts.GetDescriptions<EEmergencyLevel>(),
            PushTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.PushType),
            GenderOptions = EnumExts.GetDescriptions<EGender>(),
            IdentityTypeOptions = EnumExts.GetDescriptions<EIdentityType>(),
            LicenceTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.LicenceType),
            AgeRangeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AgeRange),
            OrderTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderType),
            OrderTags = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderTag),
            FocusOnEvents
        };
        return rsp;
    }

    /// <summary>
    /// 扩展信息新增页面基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("base-data-ext")]
    public async Task<object> BaseDataExtension()
    {
        var rsp = new
        {
            LicenceTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.LicenceType),
            IdentityTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ProviderIdentityType),
            IdentityOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.Identity),
            NationalityOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.Nationality),
            NationOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.Nation),
            MarketTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.MarketType),
            IndustryClassifyOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.IndustryClassify),
            BrandOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.Brand),
            ObjectClassifyOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ObjectClassify),
            ComplainClassifyOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ComplainClassify),
            ReportClassifyOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ReportClassify),
            SalesModeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SalesMode),
            ECommercePlatformOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ECommercePlatform),
            PatentTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.PatentType),
            AffairTargetOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AffairTarget),
            ComplainTypeOptions =
                EnumExts.GetDescriptions<EComplainType>().Select(d => new Kv(d.Key.ToString(), d.Value)),
            SalesChannelOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SalesChannel),
        };
        return rsp;
    }

    /// <summary>
    /// 扩展信息新增页面基础数据
    /// </summary>
    /// <returns></returns>
    [HttpPost("order_repeatable_event")]
    public async Task<bool> RepeatableEvent(QueryRepeatableEventDto dto)
    {
        var exp = Expressionable.Create<Orders.Order>()
            .OrIF(!string.IsNullOrEmpty(dto.HotspotSpliceName),
                x => x.HotspotSpliceName.EndsWith(dto.HotspotSpliceName!))
            .OrIF(!string.IsNullOrEmpty(dto.Address), x => x.Address != null && x.Address.EndsWith(dto.Address!));
        var count = await _orderRepository.Queryable()
            .Where(exp.ToExpression())
            .Where(d => d.CreationTime.ToString("yyyy-MM-dd") == DateTime.Now.ToString("yyyy-MM-dd"))
            .CountAsync();
        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.RepeatableEventNum);
        return count >= int.Parse(setting?.SettingValue[0] ?? "0");
    }

    /// <summary>
    /// 触发平均派单 
    /// </summary>
    /// <returns></returns>
    [HttpPost("trigger_average_order")]
    [AllowAnonymous]
    public async Task TriggerAverageOrder()
    {
        await _orderDomainService.TriggerAverageOrder(HttpContext.RequestAborted);
    }


    /// <summary>
    /// 提前触发平均派单 
    /// </summary>
    /// <returns></returns>
    [HttpPost("advanced_trigger_average_order")]
    [AllowAnonymous]
    public async Task AdvancedTriggerAverageOrder()
    {
        await _orderDomainService.AdvancedTriggerAverageOrder(HttpContext.RequestAborted);
    }

    /// <summary>
    /// 批量归档（暂时只支持派单组节点操作）
    /// </summary>
    /// <returns>成功总量</returns>
    [HttpPost("batch-file")]
    public async Task<string> BatchFile([FromBody] OrderBatchFileDto dto)
    {
        var orders = await _orderRepository.Queryable()
            .Includes(w => w.Workflow, d => d.WorkflowDefinition)
            .Includes(w => w.Workflow, d => d.Steps)
            .Includes(w => w.Workflow, d => d.Traces)
            .Includes(w => w.Workflow, d => d.Countersigns)
            .Where(d => dto.OrderIds.Contains(d.Id))
            .ToListAsync(HttpContext.RequestAborted);
        var success = 0;
        foreach (var order in orders)
        {
            //非派单组节点办理时不允许操作
            var unhandleSteps = order.Workflow.Steps
                .Where(d => d.Status != EWorkflowStepStatus.Handled)
                .ToList();
            if (unhandleSteps.Count == 0
                || unhandleSteps.Count > 2
                || unhandleSteps.First().BusinessType != EBusinessType.Send)
                continue;

            var startStep = order.Workflow.Steps.Where(d => d.StepType == EStepType.Start && d.IsOrigin)
                .MaxBy(d => d.CreationTime);
            if (startStep?.Status is not EWorkflowStepStatus.Handled || string.IsNullOrEmpty(startStep.Opinion))
                continue;
            var opinion = startStep.Opinion;

            await _workflowDomainService.JumpToEndAsync(_sessionContext, order.Workflow, opinion, dto.Files,
                order.ExpiredTime, cancellationToken: HttpContext.RequestAborted);
            success++;
        }

        return $"批量办理{dto.OrderIds.Count}件，成功{success}件";
    }

    /// <summary>
    /// 查询工单办理流程明细
    /// </summary>
    [HttpGet("traces/{workflowId}")]
    public async Task<IReadOnlyList<OrderFlowTraceDto>> GetOrderTraces(string workflowId)
    {
        var traces = await _workflowTraceRepository.Queryable()
            .Includes(d => d.OrderPublish)
            .Includes(d => d.OrderVisit, x => x.OrderVisitDetails)
            .Where(d => d.WorkflowId == workflowId && (d.HandleMode != EHandleMode.PreviousNoDisplay || d.HandleMode == null))
            .OrderBy(d => d.CreationTime)
            .ToTreeAsync(d => d.Traces, d => d.ParentId, null);
        var data = _mapper.Map<List<OrderFlowTraceDto>>(traces);
        foreach (var item in data)
        {
            if (item.TraceStyle == ETraceStyle.Publish && item.PublishState.HasValue)
                item.OpinionResult = item.PublishState == true ? "公开" : "不公开";

            if (item.TraceStyle == ETraceStyle.Visit && item.OrderFlowVisitDetails != null && item.OrderFlowVisitDetails.Any())
                item.OpinionResult = string.Join(",", item.OrderFlowVisitDetails.Select(x => x.OrgProcessingResults));
        }

        return data;
    }

    /// <summary>
    /// 流转到坐席的次数
    /// </summary>
    /// <returns></returns>
    [HttpGet("count-of-flow-to-seat/{orderId}")]
    public async Task<int> FlowToSeatCountAsync(string orderId)
    {
        var order = await _orderRepository.Queryable()
            .Includes(d => d.WorkflowTraces)
            .FirstAsync(d => d.Id == orderId, HttpContext.RequestAborted);
        return order.WorkflowTraces.Count(d => d.IsOrigin && d.BusinessType == EBusinessType.Seat);
    }

    /// <summary>
    /// 企业工单列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("enterprise/list")]
    public async Task<IReadOnlyList<OrderDto>> EnterpriseOrderQuery([FromQuery] QueryOrderDto dto)
    {
        var orders = await _orderApplication.QueryEnterprise(dto)
            .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted);
        var list = _mapper.Map<IReadOnlyList<OrderDto>>(orders);
        if ((_appOptions.Value.IsLuZhou || _appOptions.Value.IsZiGong) && !_sessionContext.OrgIsCenter)
            list = list.Select(p => p.DataMask(_appOptions.Value.IsZiGong)).ToList();
        return list;
    }

    /// <summary>
    /// 企业工单查询总数
    /// </summary>
    [HttpGet("enterprise/count")]
    public async Task<int> EnterpriseOrderCount([FromQuery] QueryOrderDto dto)
    {
        var query = _orderApplication.QueryEnterprise(dto);
        return await query.CountAsync(HttpContext.RequestAborted);
    }

    /// <summary>
    /// 企业工单导出
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("enterprise/export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> EnterpriseOrderExport([FromBody] ExportExcelDto<QueryOrderDto> dto)
    {
        var query = _orderApplication.QueryEnterprise(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);

        if ((_appOptions.Value.IsLuZhou || _appOptions.Value.IsZiGong) && !_sessionContext.OrgIsCenter)
            orderDtos = orderDtos.Select(p => p.DataMask(_appOptions.Value.IsZiGong)).ToList();

        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, "企业工单数据");
    }

    #region 附件列表

    /// <summary>
    /// 获取工单所有文件
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("all_file/{id}")]
    public async Task<List<FileDto>> GetOrderAllFile(string id)
    {
        var order = await _orderRepository.GetAsync(id);
        var steps = await _workflowStepRepository.Queryable().Where(x => x.WorkflowId == order.WorkflowId).ToListAsync();
        var allFiles = new List<FileDto>();
        if (order != null)
        {
            if (order.FileJson != null)
            {
                var ids = order.FileJson.Select(x => x.Id).ToList();
                allFiles = await _fileRepository.GetFilesAsync(ids, cancellationToken: HttpContext.RequestAborted);
                allFiles.ForEach(x => x.GetStepName("工单受理"));
            }
        }

        foreach (var step in steps)
        {
            if (step.FileJson != null && step.FileJson.Any())
            {
                var ids = step.FileJson.Select(x => x.Id).ToList();
                var stepFiles = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
                stepFiles.ForEach(x => x.GetStepName(step.Name));
                allFiles.AddRange(stepFiles);
            }
        }

        return allFiles;
    }

    /// <summary>
    /// 获取流程信息
    /// </summary>
    /// <param name="workflowId"></param>
    /// <returns></returns>
    [HttpGet("all_file/workflow/{workflowId}")]
    public async Task<WorkflowDto> GetOrderWorkflowAsync(string workflowId)
    {
        var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withSteps: true,
            cancellationToken: HttpContext.RequestAborted);
        var steps = _mapper.Map<List<WorkflowTraceDto>>(workflow.Steps);
        if (!_sessionContext.OrgIsCenter)
        {
            steps = steps.Where(x => x.HandlerOrgId != null && x.HandlerOrgId.StartsWith(_sessionContext.RequiredOrgId)).ToList();
        }

        var workflowDto = _mapper.Map<WorkflowDto>(workflow);
        workflowDto.Traces = steps;
        foreach (var item in workflowDto.Traces)
        {
            if (item.FileJson != null)
            {
                var ids = item.FileJson.Select(x => x.Id).ToList();
                item.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
            }

            item.Name = item.Name + "(" + item.HandlerOrgName + ")";
        }

        return workflowDto;
    }

    /// <summary>
    /// 附件列表补充附件
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPost("list/file_upload")]
    [LogFilter("附件列表补充附件")]
    public async Task Add([FromBody] OrderStepUploadFilesDto dto)
    {
        var order = await _orderRepository.GetAsync(dto.OrderId);
        var step = await _workflowStepRepository.GetAsync(dto.StepId);

        var listFileJson = new List<FileJson>();
        if (dto.Files.Any())
        {
            listFileJson = await _fileRepository.AddFileAsync(dto.Files, dto.StepId, "", HttpContext.RequestAborted);
        }

        await _workflowStepRepository.Updateable().SetColumns(x => new WorkflowStep { FileJson = listFileJson }).Where(x => x.Id == dto.StepId)
            .ExecuteCommandAsync(HttpContext.RequestAborted);
        await _workflowTraceRepository.Updateable().SetColumns(x => new WorkflowTrace { FileJson = listFileJson }).Where(x => x.Id == dto.StepId)
            .ExecuteCommandAsync(HttpContext.RequestAborted);

        ////附件上传后推送省上
        var orderDto = _mapper.Map<OrderDto>(order);
        var flowDto = new OrderFlowDto
        {
            Order = orderDto,
            WorkflowTrace = _mapper.Map<WorkflowTraceDto>(step),
            ExpiredTimeChanged = false,
            HandlerOrgLevel = step.HandlerOrgId.CalcOrgLevel()
        };
        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowFile, flowDto, cancellationToken: HttpContext.RequestAborted);
    }

    #endregion

    #endregion

    #region 工单待办

    ///// <summary>
    ///// 查询待办工单
    ///// </summary>
    //[HttpGet("waited")]
    //public async Task<PagedDto<OrderDto>> QueryWaited([FromQuery] QueryOrderWaitedDto dto)
    //{
    //    var isHandledStep = dto.IsHandled.HasValue && dto.IsHandled.Value;
    //    if (isHandledStep)
    //        dto.QueryType = null;

    //    var isAdmin = _orderDomainService.IsCheckAdmin();
    //    var query = _orderRepository
    //        .Queryable(hasHandledStep: isHandledStep, isAdmin: isAdmin)
    //        .Includes(d => d.OrderSpecials);
    //    if (dto.QueryType is 1 || dto.QueryType is 2)
    //    {
    //        query.WhereIF(dto.QueryType is 1, d => d.IsForwarded == false)
    //            .WhereIF(dto.QueryType is 2, d => d.IsForwarded == true)
    //            .Where(d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id && os.IsDeleted == false && os.SpecialType == ESpecialType.ReTransact)
    //                .NotAny())
    //            ;
    //    }

    //    var (total, items) = await query
    //        .Where(d => d.Status != EOrderStatus.WaitForAccept &&
    //                    d.Status != EOrderStatus.BackToUnAccept &&
    //                    d.Status != EOrderStatus.SpecialToUnAccept &&
    //                    d.Status != EOrderStatus.HandOverToUnAccept)
    //        .WhereIF(dto.QueryType is 3,
    //            d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id && os.IsDeleted == false && os.SpecialType == ESpecialType.ReTransact).Any())
    //        .Where(d => SqlFunc.Subqueryable<OrderDelay>().Where(od => od.OrderId == d.Id && od.IsDeleted == false && od.DelayState == EDelayState.Examining).NotAny())
    //        .Where(d => SqlFunc.Subqueryable<OrderSendBackAudit>().Where(osba => osba.OrderId == d.Id && osba.IsDeleted == false && osba.State == ESendBackAuditState.Apply)
    //            .NotAny())
    //        .Where(d => SqlFunc.Subqueryable<OrderSpecial>().Where(s => s.OrderId == d.Id && s.State == 0 && s.IsDeleted == false).NotAny())
    //        .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
    //        .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword))
    //        .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No)
    //        .WhereIF(!string.IsNullOrEmpty(dto.AreaCode), d => d.AreaCode == dto.AreaCode)
    //        .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
    //        .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == false, d => d.CounterSignType == null)
    //        .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == true,
    //            d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) ||
    //                 (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //超期 未办
    //        .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == false,
    //            d => d.NearlyExpiredTime < DateTime.Now && d.ExpiredTime > DateTime.Now) //即将超期 未办
    //        .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
    //        .Where(d => d.Status != EOrderStatus.BackToProvince)
    //        .WhereIF(!isHandledStep || _appOptions.Value.IsYiBin,d=>d.Status < EOrderStatus.Filed)
    //        //.Where(d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id).NotAny())
    //        //.Where(d => d.OrderSpecials.Any() == false || d.OrderSpecials.Any(s => s.State > 0))
    //        .WhereIF(dto.StartTime.HasValue, d => d.StartTime >= dto.StartTime)
    //        .WhereIF(dto.EndTime.HasValue, d => d.StartTime <= dto.EndTime)
    //        .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent!.Value)
    //        .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status)
    //        //.OrderByDescending(d => d.IsUrgent)
    //        .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.StartTime, OrderByType.Desc)
    //        .OrderByIF(dto is { SortField: "creationTime", SortRule: 0 }, d => d.CreationTime, OrderByType.Asc) //创建时间升序
    //        .OrderByIF(dto is { SortField: "creationTime", SortRule: 1 }, d => d.CreationTime, OrderByType.Desc) //创建时间降序
    //        .OrderByIF(dto is { SortField: "startTime", SortRule: 0 }, d => d.StartTime, OrderByType.Asc) //受理时间升序
    //        .OrderByIF(dto is { SortField: "startTime", SortRule: 1 }, d => d.StartTime, OrderByType.Desc) //受理时间降序
    //        .OrderByIF(dto is { SortField: "expiredTime", SortRule: 0 }, d => d.ExpiredTime, OrderByType.Asc) //期满时间升序
    //        .OrderByIF(dto is { SortField: "expiredTime", SortRule: 1 }, d => d.ExpiredTime, OrderByType.Desc) //期满时间降序
    //        .ToPagedListAsync(dto, HttpContext.RequestAborted);

    //    return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
    //}

    /// <summary>
    /// 列表页面基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("waited/base-data")]
    public async Task<object> WaitedBaseData()
    {
        var wfModule = await _workflowApplication.GetWorkflowModuleAsync(WorkflowModuleConsts.OrderHandle, HttpContext.RequestAborted);
        var definition = wfModule.Definition;
        var rsp = new
        {
            OrderStatusOptions = EnumExts.GetDescriptions<EOrderStatus>(),
            CurrentStepOptions = definition?.Steps.Select(x => new Kv(x.Code, x.Name)),
            OrderTags = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderTag)
        };
        return rsp;
    }

    /// <summary>
    /// 工单待办
    /// </summary>
    [HttpGet("waited")]
    public async Task<IReadOnlyList<OrderDto>> QueryWaited([FromQuery] QueryOrderWaitedDto dto)
    {
        var orders = await _orderApplication
            .QueryWaited(dto)
            .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted);

        return _mapper.Map<IReadOnlyList<OrderDto>>(orders);
    }

    [HttpGet("waited/count")]
    public async Task<int> QueryWaitedCount([FromQuery] QueryOrderWaitedDto dto)
    {
        return await _orderApplication
            .QueryWaited(dto)
            .CountAsync(HttpContext.RequestAborted);
    }

    /// <summary>
    /// 查询坐席待办
    /// </summary>
    [HttpGet("waited/sign")]
    public async Task<IReadOnlyList<OrderListOutDto>> QueryWaitedForSeat([FromQuery] QueryOrderWaitedDto dto)
    {
        var orders = await _orderApplication
            .QueryWaitedForSeat(dto)
            .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted);

        return _mapper.Map<IReadOnlyList<OrderListOutDto>>(orders);
    }

    [HttpGet("waited/sign/count")]
    public async Task<int> QueryWaitedForSeatCount([FromQuery] QueryOrderWaitedDto dto)
    {
        return await _orderApplication
            .QueryWaitedForSeat(dto)
            .CountAsync(HttpContext.RequestAborted);
    }

    /// <summary>
    /// 查询中心待办 //TODO
    /// </summary>
    [HttpGet("waited/center")]
    public async Task<PagedDto<OrderDto>> QueryWaitedForCenter([FromQuery] QueryOrderWaitedCenterDto dto)
    {
        var (total, items) = await _orderRepository.Queryable()
            .Includes(d => d.Workflow.Steps)
            .Where(d => SqlFunc.Subqueryable<WorkflowTrace>()
                            .WhereIF(!string.IsNullOrEmpty(dto.CenterToOrgHandlerName),
                                step => step.BusinessType == EBusinessType.Send && step.HandlerName.Contains(dto.CenterToOrgHandlerName))
                            .Where(step => step.ExternalId == d.Id &&
                                           step.HandlerOrgId == OrgSeedData.CenterId &&
                                           step.Status < EWorkflowStepStatus.Handled).Any()
                        || (string.IsNullOrEmpty(d.WorkflowId) && string.IsNullOrEmpty(dto.CenterToOrgHandlerName))
            )
            .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
            .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No!)
            .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.StartsWith(dto.Title!))
            .WhereIF(dto is { StCreationTime: not null, EndCreationTime: not null },
                d => d.CreationTime >= dto.StCreationTime && d.CreationTime <= dto.EndCreationTime)
            .WhereIF(dto is { StartTimeSt: not null, StartTimeEnd: not null }, d => d.StartTime >= dto.StartTimeSt && d.StartTime <= dto.StartTimeEnd)
            .WhereIF(!string.IsNullOrEmpty(dto.StepName), d => d.ActualHandleStepName == dto.StepName)
            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), d => d.ActualHandleOrgName.Contains(dto.ActualHandleOrgName))
            .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status)
            .WhereIF(!string.IsNullOrEmpty(dto.SourceChannelCode),
                d => d.SourceChannelCode == dto.SourceChannelCode) //任务：308  市州通用-【中心待办件】新增“来源渠道”查询条件
            .WhereIF(!string.IsNullOrEmpty(dto.AcceptorName), d => d.AcceptorName!.Contains(dto.AcceptorName!))
            .WhereIF(dto.ExpiredStatus is EExpiredStatus.Normal, d => DateTime.Now < d.NearlyExpiredTime)
            .WhereIF(dto.ExpiredStatus is EExpiredStatus.GoingToExpired, d => DateTime.Now > d.NearlyExpiredTime && DateTime.Now < d.ExpiredTime)
            .WhereIF(dto.ExpiredStatus is EExpiredStatus.Expired, d => DateTime.Now >= d.ExpiredTime)
            //.WhereIF(!string.IsNullOrEmpty(dto.CenterToOrgHandlerName), d => d.CenterToOrgHandlerName.Contains(dto.CenterToOrgHandlerName))
            .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent!.Value)
            .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.CreationTime, OrderByType.Desc)
            .OrderByIF(dto is { SortField: "startTime", SortRule: 0 }, d => d.StartTime, OrderByType.Asc) //受理时间升序
            .OrderByIF(dto is { SortField: "startTime", SortRule: 1 }, d => d.StartTime, OrderByType.Desc) //受理时间降序
            .OrderByIF(dto is { SortField: "expiredTime", SortRule: 0 }, d => d.ExpiredTime, OrderByType.Asc) //期满时间升序
            .OrderByIF(dto is { SortField: "expiredTime", SortRule: 1 }, d => d.ExpiredTime, OrderByType.Desc) //期满时间降序
            .ToPagedListAsync(dto, HttpContext.RequestAborted);

        return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
    }

    /// <summary>
    /// 查询中心待办基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("waited/center/base")]
    public async Task<Dictionary<string, object>> WaitedForCenterBaseData()
    {
        var rsp = new Dictionary<string, object>
        {
            { "orderStatus", EnumExts.GetDescriptions<EOrderStatus>() },
            { "expiredStatus", EnumExts.GetDescriptions<EExpiredStatus>() },
            { "stepNames", new string[] { "话务部", "派单组", "班长审批" } },
            { "channelOptions", _sysDicDataCacheManager.GetSysDicDataCache(TimeLimitBaseDataConsts.SourceChannel) } //任务：308  市州通用-【中心待办件】新增“来源渠道”查询条件
        };
        if (_systemSettingCacheManager.Snapshot)
        {
            var industry = await _industryRepository.Queryable()
                .Select(d => new { d.Id, d.Name, })
                .ToListAsync();
            rsp.Add("industry", industry);
        }

        return rsp;
    }

    /// <summary>
    /// 首页查询
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("waited/home")]
    public async Task<Object> QueryWaitedHome([FromQuery] QueryOrderWaitedDto dto)
    {
        var isHandled = dto.IsHandled.HasValue && dto.IsHandled.Value;
        //if (dto.EndTime.HasValue)
        //    dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
        var (total, items) = await _orderRepository
            .Queryable(hasHandled: isHandled)
            .Includes(d => d.OrderSpecials)
            .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.No.Contains(dto.Keyword) || d.Title.Contains(dto.Keyword))
            .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
            .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == false, d => d.CounterSignType == null)
            .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == true,
                d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) ||
                     (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //超期 未办
            .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == false,
                d => d.NearlyExpiredTime < DateTime.Now && d.ExpiredTime > DateTime.Now) //即将超期 未办
            .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
            .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
            .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
            .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
            //.Where(d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id).NotAny())
            .Where(d => d.OrderSpecials.Any() == false || d.OrderSpecials.Any(s => s.State == 0) == false)
            .OrderByDescending(d => d.StartTime)
            .ToPagedListAsync(dto, HttpContext.RequestAborted);

        var page1 = new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));

        dto.IsHandled = false;
        isHandled = dto.IsHandled.HasValue && dto.IsHandled.Value;
        EOrderStatus[] handleStatuses = EnumExts.GetFields<EOrderStatus>().Select(d => (EOrderStatus)d.Key).ToArray();
        handleStatuses = handleStatuses.WhereIF(dto.IsHandled.HasValue,
                d => dto.IsHandled!.Value
                    ? d is not EOrderStatus.WaitForAccept and not EOrderStatus.BackToUnAccept and not EOrderStatus.SpecialToUnAccept
                        and not EOrderStatus.HandOverToUnAccept
                    : d is EOrderStatus.WaitForAccept or EOrderStatus.BackToUnAccept or EOrderStatus.SpecialToUnAccept
                        or EOrderStatus.HandOverToUnAccept)
            .ToArray();

        var (total2, items2) = await _orderRepository.Queryable()
            .LeftJoin<WorkflowStep>((d, step) => d.Id == step.ExternalId)
            .Where((d, step) =>
                ((string.IsNullOrEmpty(d.WorkflowId) && (string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId)) ||
                 (!string.IsNullOrEmpty(d.WorkflowId) &&
                  ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) &&
                    step.HandlerId == _sessionContext.RequiredUserId) ||
                   (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) &&
                    step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
                   (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) &&
                    _sessionContext.Roles.Contains(step.RoleId))) &&
                  (((dto.IsHandled.HasValue && dto.IsHandled == false) && step.Status != EWorkflowStepStatus.Handled) ||
                   ((dto.IsHandled.HasValue && dto.IsHandled == true) && step.Status == EWorkflowStepStatus.Handled)))))
            .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
            .WhereIF(dto.IsHandled.HasValue, d => handleStatuses.Contains(d.Status))
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword!))
            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No)
            .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
            .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == false, d => d.CounterSignType == null)
            .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == true,
                d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) ||
                     (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //超期 未办
            .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == false,
                d => d.NearlyExpiredTime < DateTime.Now && d.ExpiredTime > DateTime.Now) //即将超期 未办
            .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
            .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
            .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
            .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
            .OrderBy(d => d.Status)
            .OrderByIF(dto.IsHandled == true, d => d.StartTime, OrderByType.Desc)
            .OrderByIF(dto.IsHandled == false, d => d.CreationTime, OrderByType.Desc)
            .Select((d, step) => d)
            .ToPagedListAsync(dto, HttpContext.RequestAborted);

        var page2 = new PagedDto<OrderDto>(total2, _mapper.Map<IReadOnlyList<OrderDto>>(items2));

        return new { Waited = page1, Sign = page2 };
    }

    #endregion

    #region 业务工单退回

    /// <summary>
    /// 工单退回退回（返回前一节点）
    /// </summary>
    [HttpPost("order_previous")]
    public async Task Previous([FromBody] OrderPreviousDto dto)
    {
        var oneSendBack = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.OneOrgSendBack)?.SettingValue[0]);
        var twoSendBack = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.TwoOrgSendBack)?.SettingValue[0]);
        //var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true, cancellationToken: HttpContext.RequestAborted);
        var order = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.Id == dto.OrderId);
        dto.ExpiredTime = order.ExpiredTime;
        var audit = new OrderSendBackAudit
        {
            OrderId = dto.OrderId,
            State = ESendBackAuditState.Apply,
            Content = dto.Opinion,
            SendBackData = dto,
            WorkflowOrgId = _sessionContext.RequiredOrgId,
            WorkflowUserId = _sessionContext.RequiredUserId,
            WorkflowRoleIds = _sessionContext.Roles.ToList(),
            Status = order.Status,
            OrderExpiredTime = order.ExpiredTime,
            AssignStepId = dto.AssignStepId,
            IsAssign = !string.IsNullOrEmpty(dto.AssignStepId),
        };
        audit.InitId();
        if (dto.Files.Any())
            audit.FileJson = await _fileRepository.AddFileAsync(dto.Files, audit.Id, "", HttpContext.RequestAborted);
        if (oneSendBack || twoSendBack)
        {
            var sendBack = await _orderSendBackAuditRepository.Queryable()
                .Where(x => x.OrderId == dto.OrderId && x.State == ESendBackAuditState.Apply).AnyAsync();
            if (sendBack)
                throw UserFriendlyException.SameMessage("当前工单已经生成退回记录");

            var specialAny = await _orderSpecialRepository.Queryable().Where(x => x.OrderId == order.Id && x.State == 0)
                .AnyAsync();
            if (specialAny) throw UserFriendlyException.SameMessage("工单已存在待审批特提信息！");
            if (order.Workflow.IsInCountersign) throw UserFriendlyException.SameMessage("工单会签中，无法进行退回！");

            var (currentStep, prevStep, steps, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync(
                dto.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles, dto.AssignStepId,
                HttpContext.RequestAborted);

            if (oneSendBack && isOrgToCenter && _appOptions.Value.IsZiGong)
            {
                if (order.SendBackAuditEndTime.HasValue && order.SendBackAuditEndTime.Value < DateTime.Now)
                    throw UserFriendlyException.SameMessage("工单截至退回时间【" + order.SendBackAuditEndTime.Value.ToString("yyyy-MM-dd HH:mm:ss") +
                                                            "】,无法进行退回！");

                var sendBackAgain = await _orderSendBackAuditRepository.Queryable().Where(x => x.OrderId == dto.OrderId && x.IsReturnAgain == false)
                    .AnyAsync();
                if (sendBackAgain)
                    throw UserFriendlyException.SameMessage("工单已不允许退回！");
            }

            if ((oneSendBack && isOrgToCenter) || (twoSendBack && isSecondToFirstOrgLevel))
            {
                await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { Status = EOrderStatus.SendBackAudit })
                    .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                audit.ApplyOrgId = currentStep.AcceptorOrgId;
                audit.ApplyOrgName = currentStep!.AcceptorOrgName;
                ///判断是否指定

                var assignStep = new WorkflowStep();
                if (audit.IsAssign.Value)
                {
                    assignStep = steps.FirstOrDefault(x => x.Id == dto.AssignStepId);
                }

                audit.SendBackOrgId = audit.IsAssign.Value ? assignStep.HandlerOrgId : prevStep.HandlerOrgId;
                audit.SendBackOrgName = audit.IsAssign.Value ? assignStep.HandlerOrgName : prevStep.HandlerOrgName;
                audit.SendBackStepName = audit.IsAssign.Value ? assignStep.Name : prevStep.Name;

                audit.WorkflowStepSendBackCrTime = currentStep.CreationTime;
                audit.TraceId = currentStep.Id;
                //await _orderSendBackAuditRepository.AddAsync(audit, HttpContext.RequestAborted);
            }
            else
            {
                audit.State = ESendBackAuditState.End;
                audit.AuditUser = "默认通过";
                audit.AuditTime = DateTime.Now;
                await _orderApplication.OrderPrevious(audit, order, HttpContext.RequestAborted);
            }
        }
        else
        {
            audit.State = ESendBackAuditState.End;
            audit.AuditUser = "默认通过";
            audit.AuditTime = DateTime.Now;
            await _orderApplication.OrderPrevious(audit, order, HttpContext.RequestAborted);
        }

        await _orderSendBackAuditRepository.AddAsync(audit, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 工单业务退回审批
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("order_previous_audit")]
    [LogFilterAlpha("退回审批")]
    public async Task Audit([FromBody] AuditSendBackDto dto)
    {
        if (dto.State == ESendBackAuditState.Refuse && string.IsNullOrEmpty(dto.AuditContent))
            throw UserFriendlyException.SameMessage("退回拒绝,请填写审批拒绝原因");
        //验证是否存在退回
        var sendBack = await _orderSendBackAuditRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        if (sendBack is null)
            throw UserFriendlyException.SameMessage("无效退回");
        if (sendBack.State != ESendBackAuditState.Apply)
            throw UserFriendlyException.SameMessage("退回已审批,请勿重复审批");

        _mapper.Map(dto, sendBack);
        sendBack.AuditId = _sessionContext.UserId;
        sendBack.AuditUser = _sessionContext.UserName;
        sendBack.AuditTime = DateTime.Now;

        //执行退回
        if (sendBack.State == ESendBackAuditState.End)
        {
            var order = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.Id == sendBack.OrderId);
            //if (_appOptions.Value.IsZiGong)
            //{
            //var (currentStep, prevStep, steps, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync(
            //    order.WorkflowId, sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(), sendBack.AssignStepId,
            //    HttpContext.RequestAborted);

            //if (prevStep.BusinessType == EBusinessType.Send)
            //{
            //    // 平均派单
            //    var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
            //    if (averageSendOrder)
            //    {
            //        var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
            //        sendBack.SendBackData.Handler = handler;
            //    }
            //}
            //}

            sendBack.SendBackData.ExpiredTime = order.ExpiredTime;
            await _orderApplication.OrderPrevious(sendBack, order, HttpContext.RequestAborted);
        }
        else
        {
            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { Status = sendBack.Status.Value })
                .Where(o => o.Id == sendBack.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
        }

        await _orderSendBackAuditRepository.UpdateAsync(sendBack, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 工单业务批量退回审批
    /// </summary>
    /// <returns></returns>
    [HttpPost("order_previous_audit_batch")]
    [LogFilterAlpha("退回审批批量")]
    public async Task AuditBatch([FromBody] BatchAuditSendBackDto dto)
    {
        foreach (string id in dto.Ids)
        {
            if (dto.State == ESendBackAuditState.Refuse && string.IsNullOrEmpty(dto.AuditContent))
                throw UserFriendlyException.SameMessage("退回拒绝,请填写审批拒绝原因");
            //验证是否存在退回
            var sendBack = await _orderSendBackAuditRepository.GetAsync(id, HttpContext.RequestAborted);
            if (sendBack is null)
                throw UserFriendlyException.SameMessage("无效退回");
            if (sendBack.State != ESendBackAuditState.Apply)
                throw UserFriendlyException.SameMessage("退回已审批,请勿重复审批");

            _mapper.Map(dto, sendBack);
            sendBack.AuditId = _sessionContext.UserId;
            sendBack.AuditUser = _sessionContext.UserName;
            sendBack.AuditTime = DateTime.Now;

            //执行退回
            if (sendBack.State == ESendBackAuditState.End)
            {
                var order = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.Id == sendBack.OrderId);
                //if (_appOptions.Value.IsZiGong)
                //{
                //    var (currentStep, prevStep, steps, isOrgToCenter, isSecondToFirstOrgLevel) =
                //        await _workflowApplication.GetPreviousInformationAsync(
                //            order.WorkflowId, sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(),
                //            sendBack.AssignStepId,
                //            HttpContext.RequestAborted);
                //    if (prevStep.BusinessType == EBusinessType.Send)
                //    {
                //        // 平均派单
                //        var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
                //        if (averageSendOrder)
                //        {
                //            var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
                //            sendBack.SendBackData.Handler = handler;
                //        }
                //    }
                //}

                sendBack.SendBackData.ExpiredTime = order.ExpiredTime;
                await _orderApplication.OrderPrevious(sendBack, order, HttpContext.RequestAborted);
            }
            else
            {
                await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { Status = sendBack.Status.Value })
                    .Where(o => o.Id == sendBack.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
            }

            await _orderSendBackAuditRepository.UpdateAsync(sendBack, HttpContext.RequestAborted);
        }
    }

    /// <summary>
    /// 工单业务退回审批列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("order_previous_list")]
    public async Task<PagedDto<SendBackDto>> AuditList([FromQuery] SendBackListDto dto)
    {
        var query = _orderSendBackAuditApplication.AuditList(dto);

        var (total, items) = await query.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<SendBackDto>(total, _mapper.Map<IReadOnlyList<SendBackDto>>(items));
    }

    /// <summary>
    /// 工单业务退回审批列表导出
    /// </summary>
    /// <returns></returns>
    [HttpPost("order_previous_list/_export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> OrgDataListDetailExport([FromBody] ExportExcelDto<SendBackListDto> dto)
    {
        var query = _orderSendBackAuditApplication.AuditList(dto.QueryDto);
        List<OrderSendBackAudit> 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<SendBackDto>>(data);

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<SendBackDto>(dto.ColumnInfos);

        var dtos = dataDtos
            .Select(stu => _mapper.Map(stu, typeof(SendBackDto), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);

        return ExcelStreamResult(stream, "工单退回列表数据");
    }

    /// <summary>
    /// 退回详情
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("order_previous/{id}")]
    public async Task<SendBackDto> OrderSendBackEntity(string id)
    {
        var res = await _orderSendBackAuditRepository.Queryable()
            .Includes(x => x.Order)
            .FirstAsync(x => x.Id == id);
        var resDto = _mapper.Map<SendBackDto>(res);
        if (res.FileJson != null && res.FileJson.Any())
        {
            var ids = res.FileJson.Select(x => x.Id).ToList();
            var files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
            resDto.Files = files.Where(x => x.Classify == "退回附件" && string.IsNullOrEmpty(x.FlowKey)).ToList();
        }

        return resDto;
    }

    /// <summary>
    /// 列表页面基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("order_previous/base-data")]
    public async Task<object> OrderSendBackBaseData()
    {
        var rsp = new
        {
            AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType),
            ESendBackAuditState = EnumExts.GetDescriptions<ESendBackAuditState>(),
        };
        return rsp;
    }

    /// <summary>
    /// 查询工单退回目标步节点信息
    /// </summary>
    [HttpGet("previous/targetStep/{orderId}")]
    public async Task<TargetStepInfo> GetPreviousTargetStepInfo(string orderId)
    {
        var order = await _orderDomainService.GetOrderAsync(orderId, cancellationToken: HttpContext.RequestAborted);
        if (string.IsNullOrEmpty(order.WorkflowId))
            throw UserFriendlyException.SameMessage("该工单未开启流程");

        var (currentStep, prevStep, steps, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync(
            order.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles, string.Empty,
            HttpContext.RequestAborted);
        ///查询上一节点是否是领导节点
        ///ture 流程排除领导节点 排除当前节点 prevStep.BusinessType == EBusinessType.DepartmentLeader
        if (_appOptions.Value.IsYiBin && prevStep.Name.Contains("领导"))
        {
            var step = steps.Where(x => !x.Name.Contains("领导") && x.Code != currentStep.Code).OrderByDescending(x => x.CreationTime).FirstOrDefault();
            var resStep = new List<WorkflowStep>
            {
                step,
                prevStep
            };
            return new TargetStepInfo
            {
                CurrentBusinessType = currentStep.BusinessType,
                TargetBusinessType = prevStep.BusinessType,
                Steps = _mapper.Map<List<TargetStep>>(resStep)
            };
        }

        return new TargetStepInfo
        {
            CurrentBusinessType = currentStep.BusinessType,
            TargetBusinessType = prevStep.BusinessType
        };
    }

    #endregion

    #region 省工单退回

    /// <summary>
    /// 工单退回列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("send_back")]
    public async Task<PagedDto<OrderSendBackDto>> UrgeList([FromQuery] OrderSendBackListDto dto)
    {
        var (total, items) = await _orderSendBackRepository.Queryable()
            .Includes(x => x.Order)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
            .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart)
            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd)
            .WhereIF(dto.State is > 0, d => d.State > 0)
            .WhereIF(dto.State is 0, d => d.State == 0)
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<OrderSendBackDto>(total, _mapper.Map<IReadOnlyList<OrderSendBackDto>>(items));
    }

    /// <summary>
    /// 批量省工单退回
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("send_back/batch")]
    public async Task<object> BatchApplyUrge([FromBody] BatchOrderSendBackAddDto dto)
    {
        int count = dto.OrderIds.Count;
        int successCount = 0;
        int errorCount = 0;
        var SendDatas = new List<PublishOrderSendBackModelDto>();
        foreach (var item in dto.OrderIds)
        {
            //验证工单是否可以申请
            var order = await _orderRepository.GetAsync(item.OrderId, HttpContext.RequestAborted);
            if (order is null)
            {
                errorCount++;
                continue;
            }

            if (order.Status >= EOrderStatus.Filed || order.Status == EOrderStatus.BackToProvince || !order.IsProvince ||
                (!string.IsNullOrEmpty(order.ActualHandleOrgCode) && order.ActualHandleOrgCode != "001"))
            {
                errorCount++;
                continue;
            }

            if (order.Source <= ESource.HotlineImport)
            {
                errorCount++;
                continue;
            }

            var model = new OrderSendBack()
            {
                Content = dto.Content,
                OrderId = item.OrderId,
                Destination = ESendBackDestination.Province
            };
            await _orderSendBackRepository.AddAsync(model, HttpContext.RequestAborted);
            if (!string.IsNullOrEmpty(model.Id))
            {
                order.Status = EOrderStatus.BackToProvince;
                await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
                successCount++;
                var sendBackDto = _mapper.Map<OrderSendBackDto>(model);
                var OrderDto = _mapper.Map<OrderDto>(order);
                SendDatas.Add(new PublishOrderSendBackModelDto() { Order = OrderDto, SendBack = sendBackDto, ClientGuid = "" });
            }
        }

        //推省上
        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowPrevious,
            new PublishOrderSendBackDto() { SendDatas = SendDatas });
        return new { Count = count, ErrorCount = errorCount, SuccessCount = successCount };
    }


    /// <summary>
    /// 退回申请
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("send_back/apply")]
    [LogFilter("新增工单退回申请")]
    public async Task ApplyUrge([FromBody] OrderSendBackAddDto dto)
    {
        //验证工单是否可以申请
        var order = await _orderRepository.GetAsync(dto.OrderId, HttpContext.RequestAborted);
        if (order is null)
            throw UserFriendlyException.SameMessage("无效工单");
        if (order.Status >= EOrderStatus.Filed || order.Status == EOrderStatus.BackToProvince || !order.IsProvince ||
            (!string.IsNullOrEmpty(order.ActualHandleOrgCode) && order.ActualHandleOrgCode != "001"))
            throw UserFriendlyException.SameMessage("工单状态无效,请确认当前工单状态");
        if (order.Source <= ESource.HotlineImport)
            throw UserFriendlyException.SameMessage("工单来源无效,请确认当前工单来源");
        var model = _mapper.Map<OrderSendBack>(dto);
        model.InitId();
        if (dto.Files.Any())
            model.FileJson = await _fileRepository.AddFileAsync(dto.Files, model.Id, "", HttpContext.RequestAborted);
        await _orderSendBackRepository.AddAsync(model, HttpContext.RequestAborted);

        if (!string.IsNullOrEmpty(model.Id))
        {
            order.Status = EOrderStatus.BackToProvince;
            await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
            var sendBackDto = _mapper.Map<OrderSendBackDto>(model);
            var OrderDto = _mapper.Map<OrderDto>(order);
            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowPrevious,
                new PublishOrderSendBackDto()
                {
                    SendDatas = new List<PublishOrderSendBackModelDto>()
                        { new PublishOrderSendBackModelDto() { Order = OrderDto, SendBack = sendBackDto, ClientGuid = "" } }
                });
        }
    }

    /// <summary>
    /// 退回审核
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("send_back/audit")]
    [LogFilter("审核工单退回申请")]
    public async Task ReplyUrge([FromBody] AuditOrderSendBackDto dto)
    {
        //验证是否存在退回
        var sendBack = await _orderSendBackRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        if (sendBack is null)
            throw UserFriendlyException.SameMessage("无效退回");
        if (sendBack.State > 0)
            throw UserFriendlyException.SameMessage("退回已审核,请勿重复审核");

        _mapper.Map(dto, sendBack);
        sendBack.AuditName = _sessionContext.UserName;
        sendBack.AuditTime = DateTime.Now;
        await _orderSendBackRepository.UpdateAsync(sendBack, HttpContext.RequestAborted);
        //推省上
        if (sendBack.State == 1)
        {
            var order = await _orderRepository.GetAsync(sendBack.OrderId);
            var sendBackDto = _mapper.Map<OrderSendBackDto>(sendBack);
            var OrderDto = _mapper.Map<OrderDto>(order);
            //await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowPrevious,
            //      new PublishOrderSendBackDto() { Order = OrderDto, SendBack = sendBackDto, ClientGuid = "" });
            //try
            //{
            //    await _provinceService.GetCaseBackApply(
            //        new PublishOrderSendBackDto { Order = OrderDto, SendBack = sendBackDto, ClientGuid = "" },
            //        HttpContext.RequestAborted);
            //}
            //catch (Exception e)
            //{
            //    _logger.LogError("_provinceService.GetCaseBackApply throw exception: {ex}", e.Message);
            //}
        }
    }

    /// <summary>
    /// 退回详情
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("send_back/{id}")]
    public async Task<OrderSendBack> SendBackEntity(string id)
    {
        return await _orderSendBackRepository.Queryable()
            .Includes(x => x.Order)
            .FirstAsync(x => x.Id == id);
    }

    #endregion

    #region 工单特提

    /// <summary>
    /// 工单特提信息
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPost("special")]
    [LogFilter("新增工单特提")]
    [LogFilterAlpha("特提审核")]
    public async Task Add([FromBody] OrderSpecialAddDto dto)
    {
        var specialAny = await _orderSpecialRepository.Queryable().Where(x => x.OrderId == dto.OrderId && x.State == 0)
            .AnyAsync();
        if (specialAny) throw UserFriendlyException.SameMessage("工单已存在待审批特提信息！");
        var order = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.Id == dto.OrderId);
        await _orderApplication.SpecialVerify(dto, order, HttpContext.RequestAborted);

        dto.Cause ??= dto.Reason;
        var special = _mapper.Map<OrderSpecial>(dto);
        special.OrgId = _sessionContext.RequiredOrgId;
        special.OrgName = _sessionContext.OrgName;
        special.Status = order.Status;

        var audit = true;
        var specialAudit = _systemSettingCacheManager.GetSetting(SettingConstants.SpecialAduit);
        if (bool.Parse(specialAudit?.SettingValue[0]))
        {
            //if (!dto.Audit) model.State = 1;
            //取消根据进入界面判断是否审批  最新按照系统配置设定
            var setting = _systemSettingCacheManager.GetSetting(SettingConstants.SeatsMonitor);
            var settingStr = setting?.SettingValue;
            var roles = _sessionContext.Roles;
            foreach (var item in settingStr)
            {
                if (roles != null && roles.Contains(item)) audit = false;
            }
        }
        else
        {
            audit = false;
        }

        if (!audit) special.State = 1;

        special.InitId();
        if (dto.Files.Any())
            special.FileJson = await _fileRepository.AddFileAsync(dto.Files, special.Id, "", HttpContext.RequestAborted);

        if (special.State == 1)
        {
            var recall = new RecallDto
            {
                WorkflowId = dto.WorkflowId!,
                NextStepCode = dto.NextStepCode,
                NextStepName = dto.NextStepName,
                NextHandlers = dto.NextHandlers,
                Opinion = "【特提理由】" + dto.Reason,
                FlowDirection = dto.FlowDirection,
                HandlerType = dto.HandlerType,
                BusinessType = dto.BusinessType
            };

            if (dto.FlowDirection is not EFlowDirection.OrgToOrg and not EFlowDirection.Other)
            {
                //重新计算期满时间
                ExpiredTimeWithConfig expiredTime;
                if (_appOptions.Value.IsZiGong)
                {
                    if (dto.FlowDirection != null)
                    {
                        expiredTime = await _expireTime.CalcExpiredTime(DateTime.Now, DateTime.Now, dto.FlowDirection.Value,
                            order.Adapt<OrderTimeClacInfo>());
                    }
                    else
                    {
                        expiredTime = await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, order.AcceptTypeCode);
                    }
                }
                else
                {
                    expiredTime = await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, order.AcceptTypeCode);
                }

                if (expiredTime?.ExpiredTime > order.ExpiredTime)
                {
                    order.ExpiredTime = expiredTime.ExpiredTime;
                    order.NearlyExpiredTime = expiredTime.NearlyExpiredTime;
                    order.NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne;

                    var orderDto = _mapper.Map<OrderDto>(order);
                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
                        cancellationToken: HttpContext.RequestAborted);
                }
            }

            var (workflow, targetStepDefine, currentStep, targetStep, newStep, isOrgToCenter) = await _workflowDomainService.RecallAsync(recall,
                dto.NextHandlers.FirstOrDefault(), EWorkflowTraceType.Recall,
                order.ExpiredTime, order.Status >= EOrderStatus.Filed, EHandleMode.Recall,
                (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) =>
                {
                    var basicWorkflowDto = _mapper.Map<BasicWorkflowDto>(dto);
                    var stepAssignInfo = _orderApplication.GetOrderRecallAssignInfoAsync(workflow, targetStepDefine, targetStep,
                        basicWorkflowDto, HttpContext.RequestAborted).Result; //todo 优化异步
                    if (stepAssignInfo is null) return;
                    var validator = new StepAssignInfoValidator();
                    validator.ValidateAndThrow(stepAssignInfo);
                    targetStepNew.Assign(stepAssignInfo);
                },
                HttpContext.RequestAborted);

            if (_appOptions.Value.IsYiBin && order.ActualHandleOrgCode != OrgSeedData.CenterId && order.Status < EOrderStatus.Filed)
            {
                await _circularRecordDomainService.OrderSpecialCircularMessage(special, order, HttpContext.RequestAborted);
            }

            if (string.IsNullOrEmpty(currentStep?.HandlerOrgId))
            {
                special.OrgId = currentStep.HandlerOrgId;
                special.OrgName = currentStep.HandlerOrgName;
                special.StepName = currentStep.Name;
                special.StepCode = currentStep.Code;
            }

            if (_appOptions.Value.IsZiGong && dto.BusinessType == EBusinessType.Send)
            {
                special.NextHandlers = new List<StepAssignInfo> { newStep.GetWorkflowStepHandler() };
            }

            if (dto.BusinessType == EBusinessType.Send)
            {
                order.CenterToOrgHandlerId = newStep.HandlerId;
                order.CenterToOrgHandlerName = newStep.HandlerName;
            }

            _mapper.Map(workflow, order);
            order.FileEmpty();
            order.Status = targetStepDefine.StepType is EStepType.Start
                ? EOrderStatus.SpecialToUnAccept
                : EOrderStatus.Special;

            order.ProcessType = dto.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter
                ? EProcessType.Zhiban
                : EProcessType.Jiaoban;

            if (special.Status >= EOrderStatus.Filed)
            {
                var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == dto.OrderId);
                if (publish != null)
                {
                    var publishHistory = _mapper.Map<OrderPublishHistory>(publish);
                    publishHistory.OrderPublishId = publish.Id;
                    publishHistory.ArrangeTitleAfter = publish.ArrangeTitle;
                    publishHistory.ArrangeTitleBefor = publish.ArrangeTitle;
                    publishHistory.ArrangeContentAfter = publish.ArrangeContent;
                    publishHistory.ArrangeContentBefor = publish.ArrangeContent;
                    publishHistory.ArrangeOpinionAfter = publish.ArrangeOpinion;
                    publishHistory.ArrangeOpinionBefor = publish.ArrangeOpinion;
                    await _orderPublishHistoryRepository.AddAsync(publishHistory, HttpContext.RequestAborted);
                    await _orderPublishRepository.RemoveAsync(publish, false, HttpContext.RequestAborted);
                }

                var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == dto.OrderId && x.VisitState != EVisitState.None);
                if (visit != null)
                {
                    visit.VisitState = EVisitState.None;
                    await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted);
                }
            }

            await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);

            var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0];
            var cityBase = JsonSerializer.Deserialize<CityBaseConfiguration>(setting);
            if (order != null && (cityBase.CityProvince.OrgId.Equals(special.OrgId) ||
                                  cityBase.CityProvinceAssign.OrgId.Equals(special.OrgId) || cityBase.CityEnterprise.OrgId.Equals(special.OrgId) ||
                                  cityBase.PublicSecurity.OrgId.Equals(special.OrgId)))
            {
                if (special.Status < EOrderStatus.Filed)
                {
                    await _capPublisher.PublishAsync(EventNames.HotlineOrderFlowRecalled,
                        new PublishSpecialDto { Order = _mapper.Map<OrderDto>(order), Special = _mapper.Map<OrderSpecialDto>(special) },
                        cancellationToken: HttpContext.RequestAborted);
                }
            }
        }
        else
        {
            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { Status = EOrderStatus.SpecialAudit })
                .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
        }

        await _orderSpecialRepository.AddAsync(special, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 工单重办信息
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("re_transact")]
    [LogFilter("工单重办")]
    public async Task Add([FromBody] OrderReTransactDto dto)
    {
        var order = await _orderRepository
            .Queryable()
            .Includes(d => d.Workflow)
            .FirstAsync(d => d.Id == dto.OrderId);
        if (order.Workflow.IsInCountersign) throw UserFriendlyException.SameMessage("工单会签中，无法进行重办！");
        var specialAny = await _orderSpecialRepository.Queryable().Where(x => x.OrderId == dto.OrderId && x.State == 0)
            .AnyAsync();
        if (specialAny) throw UserFriendlyException.SameMessage(order.No + " 工单已存在待审批特提信息！");

        var screen = await _orderScreenRepository.Queryable().Where(x => x.OrderId == dto.OrderId && (int)x.Status < 2).AnyAsync();
        if (screen) throw UserFriendlyException.SameMessage(order.No + " 工单存在甄别中的信息！");

        if (await _orderSendBackAuditRepository.AnyAsync(x => x.OrderId == dto.OrderId && x.State == ESendBackAuditState.Apply,
                HttpContext.RequestAborted))
        {
            throw UserFriendlyException.SameMessage(order.No + " 工单存在正在审核中的退回，不能办理");
        }

        var special = _mapper.Map<OrderSpecial>(dto);
        special.OrgId = _sessionContext.RequiredOrgId;
        special.OrgName = _sessionContext.OrgName;
        special.State = 1;
        special.SpecialType = dto.SpecialType;
        special.LastFileOpinion = order.FileOpinion;
        special.FirstFileOpinion = order.FileOpinion;
        special.Status = order.Status;
        var firstSpecial = await _orderSpecialRepository.Queryable().Where(x => x.OrderId == dto.OrderId).FirstAsync();
        if (firstSpecial is not null)
            special.FirstFileOpinion = firstSpecial.FirstFileOpinion;
        special.InitId();
        if (dto.Files.Any())
            special.FileJson = await _fileRepository.AddFileAsync(dto.Files, special.Id, "", HttpContext.RequestAborted);

        if (dto.ReTransactError != null && dto.ReTransactError.Any())
        {
            List<OrderSpecialDetail> details = new();
            foreach (var item in dto.ReTransactError)
            {
                var detail = new OrderSpecialDetail();
                _mapper.Map(item, detail);
                detail.SpecialId = special.Id;
                details.Add(detail);
            }

            await _orderSpecialDetailRepository.AddRangeAsync(details, HttpContext.RequestAborted);
        }

        if (special.State == 1)
        {
            var recall = new RecallDto
            {
                WorkflowId = dto.WorkflowId!,
                NextStepCode = dto.NextStepCode,
                NextStepName = dto.NextStepName,
                NextHandlers = dto.NextHandlers,
                Opinion = dto.Reason,
                FlowDirection = dto.FlowDirection,
                HandlerType = dto.HandlerType,
                BusinessType = dto.BusinessType,
            };
            //todo
            //宜宾需求：1. 坐席申请特提：指派给申请人办理 2. 派单员申请特提：所有派单员都能办 3.其他特提场景：按节点原配置办理
            order.ProcessType = dto.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter
                ? EProcessType.Zhiban
                : EProcessType.Jiaoban;
            // 计算期满时间
            if (dto.AlterTime)
            {
                DateTime startTime = DateTime.Now;
                DateTime beginTime = DateTime.Now;

                if (order.CenterToOrgTime.HasValue && order.FileOrgIsCenter.HasValue && !order.FileOrgIsCenter.Value)
                {
                    startTime = order.CenterToOrgTime.Value;
                }
                else if (order.FileOrgIsCenter.HasValue && order.FileOrgIsCenter.Value)
                {
                    startTime = order.StartTime.Value;
                }

                if (_appOptions.Value.IsLuZhou)
                {
                    startTime = DateTime.Now;
                }

                var expiredTime = await _expireTime.CalcEndTime(beginTime, startTime, order.AcceptTypeCode);
                if (dto.TimeLimit.HasValue && dto.TimeLimit.Value > 0)
                {
                    var config = new TimeConfig(dto.TimeLimit.Value, ETimeType.WorkDay);
                    expiredTime = await _expireTime.CalcEndTime(beginTime, startTime, config, order.AcceptTypeCode);
                }

                //if (expiredTime.EndTime < order.ExpiredTime.Value)
                //{
                //    expiredTime.EndTime = order.ExpiredTime.Value;
                //    expiredTime.NearlyExpiredTime = order.NearlyExpiredTime.Value;
                //    expiredTime.NearlyExpiredTimeOne = order.NearlyExpiredTimeOne.Value;
                //}

                //endTime = expiredTime.EndTime;
                //await _orderRepository.Updateable().SetColumns(o => new Orders.Order()
                //{
                //    ExpiredTime = expiredTime.EndTime,
                //    NearlyExpiredTime = expiredTime.NearlyExpiredTime,
                //    NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne
                //})
                //    .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);

                if ((expiredTime?.ExpiredTime > order.ExpiredTime) || _appOptions.Value.IsLuZhou)
                {
                    order.ExpiredTime = expiredTime.ExpiredTime;
                    order.NearlyExpiredTime = expiredTime.NearlyExpiredTime;
                    order.NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne;

                    var orderDto = _mapper.Map<OrderDto>(order);
                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
                        cancellationToken: HttpContext.RequestAborted);
                }
            }

            // if (dto.BusinessType == EBusinessType.Send && recall.NextHandlers.Any())
            // {
            //     var flowStepHandler = recall.NextHandlers.FirstOrDefault();
            //     await _orderRepository.Updateable().SetColumns(o => new Orders.Order()
            //             { CenterToOrgHandlerId = flowStepHandler.UserId, CenterToOrgHandlerName = flowStepHandler.Username })
            //         .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
            // }
            var handleMode = EHandleMode.Redo;
            var workflowTraceType = EWorkflowTraceType.Redo;
            if (dto.SpecialType == ESpecialType.Special)
            {
                handleMode = EHandleMode.Recall;
                workflowTraceType = EWorkflowTraceType.Recall;
            }

            if (dto.SpecialType == ESpecialType.SendBack)
            {
                handleMode = EHandleMode.PublishPrevious;
                workflowTraceType = EWorkflowTraceType.PublishPrevious;
            }

            DateTime endTime = order.ExpiredTime!.Value;
            var (workflow, targetStepDefine, currentStep, targetStep, newStep, isOrgToCenter) =
                await _workflowDomainService.RecallAsync(
                    recall, recall.NextHandlers.FirstOrDefault(), workflowTraceType,
                    endTime, order.Status >= EOrderStatus.Filed, handleMode,
                    (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) =>
                    {
                        var stepAssignInfo = recall.NextHandlers.FirstOrDefault()
                                             ?? _orderApplication.GetOrderRecallAssignInfoAsync(workflow, targetStepDefine, targetStep,
                                                 recall, HttpContext.RequestAborted).Result; //todo 优化异步
                        if (stepAssignInfo is null) return;
                        var validator = new StepAssignInfoValidator();
                        validator.ValidateAndThrow(stepAssignInfo);
                        targetStepNew.Assign(stepAssignInfo);
                    }, HttpContext.RequestAborted);

            //记录特提后最新的流程节点
            if (!string.IsNullOrEmpty(newStep.Id))
                special.NewCurrentStepId = newStep.Id;

            if (string.IsNullOrEmpty(currentStep?.HandlerOrgId))
            {
                special.OrgId = currentStep.HandlerOrgId;
                special.OrgName = currentStep.HandlerOrgName;
                special.StepName = currentStep.Name;
                special.StepCode = currentStep.Code;
            }

            if (_appOptions.Value.IsZiGong && dto.BusinessType == EBusinessType.Send)
            {
                special.NextHandlers = new List<StepAssignInfo> { newStep.GetWorkflowStepHandler() };
            }

            if (dto.BusinessType == EBusinessType.Send)
            {
                order.CenterToOrgHandlerId = newStep.HandlerId;
                order.CenterToOrgHandlerName = newStep.HandlerName;
            }

            _mapper.Map(workflow, order);
            order.FileEmpty();
            order.Status = targetStepDefine.StepType is EStepType.Start
                ? EOrderStatus.SpecialToUnAccept
                : EOrderStatus.Special;

            if (special.Status >= EOrderStatus.Filed)
            {
                var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == dto.OrderId);
                if (publish != null)
                {
                    var publishHistory = _mapper.Map<OrderPublishHistory>(publish);
                    publishHistory.OrderPublishId = publish.Id;
                    publishHistory.ArrangeTitleAfter = publish.ArrangeTitle;
                    publishHistory.ArrangeTitleBefor = publish.ArrangeTitle;
                    publishHistory.ArrangeContentAfter = publish.ArrangeContent;
                    publishHistory.ArrangeContentBefor = publish.ArrangeContent;
                    publishHistory.ArrangeOpinionAfter = publish.ArrangeOpinion;
                    publishHistory.ArrangeOpinionBefor = publish.ArrangeOpinion;
                    await _orderPublishHistoryRepository.AddAsync(publishHistory, HttpContext.RequestAborted);
                    await _orderPublishRepository.RemoveAsync(publish, false, HttpContext.RequestAborted);
                }

                var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == dto.OrderId && x.VisitState != EVisitState.None);
                if (visit != null)
                {
                    visit.VisitState = EVisitState.None;
                    await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted);
                }
            }

            //var reTransactNum = order.ReTransactNum.HasValue ? order.ReTransactNum.Value + 1 : 1;
            var orderStatus = EOrderStatus.SendBack;
            var orderStartStatus = EOrderStatus.BackToUnAccept;

            if (_appOptions.Value.IsZiGong)
            {
                orderStatus = special.SpecialType == ESpecialType.SendBack ? EOrderStatus.SendBack : EOrderStatus.Special;
                orderStartStatus = special.SpecialType == ESpecialType.SendBack ? EOrderStatus.BackToUnAccept : EOrderStatus.SpecialToUnAccept;
            }

            //ReTransactNum = reTransactNum,
            order.Status = special.StepType == EStepType.Start ? orderStartStatus : orderStatus;
            await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);

            // 重办清空已取消发布的工单的回访信息
            await _orderDomainService.VisitNoneByCancelPublishAsync(order.Id, HttpContext.RequestAborted);
            //var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == dto.OrderId && x.VisitState != EVisitState.None);
            //if (visit != null)
            //{
            //    visit.VisitState = EVisitState.None;
            //    await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted);
            //}
        }

        await _orderSpecialRepository.AddAsync(special, HttpContext.RequestAborted);
        await _publisher.PublishAsync(new AddOrderSpecialNotify(order.Id, order.SourceChannel, dto.ReTransactError), PublishStrategy.ParallelWhenAll,
            HttpContext.RequestAborted);
    }

    /// <summary>
    /// 审批工单特提信息
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut("special")]
    [LogFilter("审批工单特提")]
    public async Task Update([FromBody] AuditOrderSpecialDto dto)
    {
        var special = await _orderSpecialRepository
            .Queryable()
            .Includes(d => d.Order)
            .FirstAsync(d => d.Id == dto.Id);
        if (special is null) throw UserFriendlyException.SameMessage("无效特提审批信息！");
        if (special.State != 0) throw UserFriendlyException.SameMessage("无效特提审批信息,特提审批信息错误,该信息已审核！");
        special.State = dto.State;
        special.Opinion = dto.Opinion;
        if (dto.Files.Any())
            special.ReplyFileJson = await _fileRepository.AddFileAsync(dto.Files, special.Id, "", HttpContext.RequestAborted);
        else
            special.ReplyFileJson = new List<Share.Dtos.File.FileJson>();

        var order = await _orderRepository.GetAsync(x => x.Id == special.OrderId);
        if (special.State == 1)
        {
            var (workflow, targetStepDefine, currentStep, targetStep, newStep, isOrgToCenter) =
                await _orderApplication.RecallAsync(dto, special, order, HttpContext.RequestAborted);

            if (string.IsNullOrEmpty(currentStep?.HandlerOrgId))
            {
                special.OrgId = currentStep.HandlerOrgId;
                special.OrgName = currentStep.HandlerOrgName;
                special.StepName = currentStep.Name;
                special.StepCode = currentStep.Code;
            }

            if (special.Status >= EOrderStatus.Filed)
            {
                var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == special.OrderId);
                if (publish != null)
                {
                    var publishHistory = _mapper.Map<OrderPublishHistory>(publish);
                    publishHistory.OrderPublishId = publish.Id;
                    publishHistory.ArrangeTitleAfter = publish.ArrangeTitle;
                    publishHistory.ArrangeTitleBefor = publish.ArrangeTitle;
                    publishHistory.ArrangeContentAfter = publish.ArrangeContent;
                    publishHistory.ArrangeContentBefor = publish.ArrangeContent;
                    publishHistory.ArrangeOpinionAfter = publish.ArrangeOpinion;
                    publishHistory.ArrangeOpinionBefor = publish.ArrangeOpinion;
                    await _orderPublishHistoryRepository.AddAsync(publishHistory, HttpContext.RequestAborted);
                    await _orderPublishRepository.RemoveAsync(publish, false, HttpContext.RequestAborted);
                }

                var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == special.OrderId && x.VisitState != EVisitState.None);
                if (visit != null)
                {
                    visit.VisitState = EVisitState.None;
                    await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted);
                }
            }

            var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0];
            var cityBase = JsonSerializer.Deserialize<CityBaseConfiguration>(setting);
            if (order != null && (cityBase.CityProvince.OrgId.Equals(special.OrgId) ||
                                  cityBase.CityProvinceAssign.OrgId.Equals(special.OrgId) || cityBase.CityEnterprise.OrgId.Equals(special.OrgId) ||
                                  cityBase.PublicSecurity.OrgId.Equals(special.OrgId)))
            {
                if (order.Status < EOrderStatus.Filed)
                {
                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowRecalled,
                        new PublishSpecialDto { Order = _mapper.Map<OrderDto>(order), Special = _mapper.Map<OrderSpecialDto>(special) },
                        cancellationToken: HttpContext.RequestAborted);
                }
            }
        }
        else
        {
            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { Status = special.Status.Value })
                .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
        }

        await _orderSpecialRepository.UpdateAsync(special, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 批量审批工单特提
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPut("special_batch")]
    [LogFilter("批量审批工单特提")]
    [LogFilterAlpha("特提审核批量")]
    public async Task UpdateBatch([FromBody] BatchAuditOrderSpecialDto dto)
    {
        var specials = await _orderSpecialRepository.Queryable()
            .Includes(d => d.Order)
            .Where(d => dto.ids.Contains(d.Id))
            .ToListAsync(HttpContext.RequestAborted);
        foreach (var special in specials)
        {
            if (special is null) throw UserFriendlyException.SameMessage("无效特提审批信息！");
            if (special.State != 0) throw UserFriendlyException.SameMessage("无效特提审批信息,特提审批信息错误,该信息已审核！");
            special.State = dto.State;
            special.Opinion = dto.Opinion;
            if (dto.Files.Any())
                special.ReplyFileJson = await _fileRepository.AddFileAsync(dto.Files, special.Id, "", HttpContext.RequestAborted);
            else
                special.ReplyFileJson = new List<Share.Dtos.File.FileJson>();

            //var order = await _orderRepository.GetAsync(x => x.Id == special.OrderId);
            var order = special.Order;
            if (special.State == 1)
            {
                #region MyRegion

                //var recall = new RecallDto
                //{
                //    WorkflowId = special.WorkflowId!,
                //    NextStepCode = special.NextStepCode,
                //    NextStepName = special.NextStepName,
                //    NextHandlers = special.NextHandlers,
                //    Opinion = "【特提理由】" + dto.Opinion,
                //    FlowDirection = special.FlowDirection,
                //    HandlerType = special.HandlerType.Value,
                //    BusinessType = special.BusinessType.Value
                //};

                //if (dto.FlowDirection is not EFlowDirection.OrgToOrg)
                //{
                //    //重新计算期满时间
                //    ExpiredTimeWithConfig expiredTime;
                //    if (_appOptions.Value.IsZiGong)
                //    {
                //        if (dto.FlowDirection != null)
                //        {
                //            expiredTime = await _expireTime.CalcExpiredTime(DateTime.Now, DateTime.Now, dto.FlowDirection.Value,
                //                order.Adapt<OrderTimeClacInfo>());
                //        }
                //        else
                //        {
                //            expiredTime = await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, order.AcceptTypeCode);
                //        }
                //    }
                //    else
                //    {
                //        expiredTime = await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, order.AcceptTypeCode);
                //    }

                //    if (expiredTime?.ExpiredTime > order.ExpiredTime)
                //    {
                //        order.ExpiredTime = expiredTime.ExpiredTime;
                //        order.NearlyExpiredTime = expiredTime.NearlyExpiredTime;
                //        order.NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne;

                //        var orderDto = _mapper.Map<OrderDto>(order);
                //        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
                //            cancellationToken: HttpContext.RequestAborted);
                //    }
                //}

                //order.ProcessType = special.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter
                //    ? EProcessType.Zhiban
                //    : EProcessType.Jiaoban;
                ////}
                //// if (special.BusinessType == EBusinessType.Send && recall.NextHandlers.Any())
                //// {
                ////     var flowStepHandler = recall.NextHandlers.FirstOrDefault();
                ////     await _orderRepository.Updateable().SetColumns(o => new Orders.Order()
                ////             { CenterToOrgHandlerId = flowStepHandler.UserId, CenterToOrgHandlerName = flowStepHandler.Username })
                ////         .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                //// }
                ////todo 特提重办，按审批通过时间依据中心派至部门的规则计算期满时间，更新order

                //var (workflow, targetStepDefine, currentStep, targetStep, newStep, isOrgToCenter) = await _workflowDomainService.RecallAsync(
                //    recall, recall.NextHandlers.FirstOrDefault(), EWorkflowTraceType.Recall,
                //    order.ExpiredTime, order.Status >= EOrderStatus.Filed, EHandleMode.Recall,
                //    async (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) =>
                //    {
                //        var stepAssignInfo = recall.NextHandlers.FirstOrDefault()
                //                             ?? await _orderApplication.GetOrderRecallAssignInfoAsync(workflow, targetStepDefine, targetStep,
                //                                 recall, HttpContext.RequestAborted);
                //        if (stepAssignInfo is null) return;
                //        var validator = new StepAssignInfoValidator();
                //        await validator.ValidateAndThrowAsync(stepAssignInfo, HttpContext.RequestAborted);
                //        targetStepNew.Assign(stepAssignInfo);
                //    }, HttpContext.RequestAborted);

                //if (_appOptions.Value.IsZiGong && dto.BusinessType == EBusinessType.Send)
                //{
                //    special.NextHandlers = new List<StepAssignInfo> { newStep.GetWorkflowStepHandler() };
                //}

                //if (dto.BusinessType == EBusinessType.Send)
                //{
                //    order.CenterToOrgHandlerId = newStep.HandlerId;
                //    order.CenterToOrgHandlerName = newStep.HandlerName;
                //    await _orderRepository.Updateable(order)
                //        .UpdateColumns(d => new { d.CenterToOrgHandlerId, d.CenterToOrgHandlerName })
                //        .ExecuteCommandAsync(HttpContext.RequestAborted);
                //}

                #endregion

                var (workflow, targetStepDefine, currentStep, targetStep, newStep, isOrgToCenter) =
                    await _orderApplication.RecallAsync(dto, special, order, HttpContext.RequestAborted);

                if (string.IsNullOrEmpty(currentStep?.HandlerOrgId))
                {
                    special.OrgId = currentStep.HandlerOrgId;
                    special.OrgName = currentStep.HandlerOrgName;
                    special.StepName = currentStep.Name;
                    special.StepCode = currentStep.Code;
                }

                if (special.Status >= EOrderStatus.Filed)
                {
                    var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == special.OrderId);
                    if (publish != null)
                    {
                        var publishHistory = _mapper.Map<OrderPublishHistory>(publish);
                        publishHistory.OrderPublishId = publish.Id;
                        publishHistory.ArrangeTitleAfter = publish.ArrangeTitle;
                        publishHistory.ArrangeTitleBefor = publish.ArrangeTitle;
                        publishHistory.ArrangeContentAfter = publish.ArrangeContent;
                        publishHistory.ArrangeContentBefor = publish.ArrangeContent;
                        publishHistory.ArrangeOpinionAfter = publish.ArrangeOpinion;
                        publishHistory.ArrangeOpinionBefor = publish.ArrangeOpinion;
                        await _orderPublishHistoryRepository.AddAsync(publishHistory, HttpContext.RequestAborted);
                        await _orderPublishRepository.RemoveAsync(publish, false, HttpContext.RequestAborted);
                    }

                    var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == special.OrderId && x.VisitState != EVisitState.None);
                    if (visit != null)
                    {
                        visit.VisitState = EVisitState.None;
                        await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted);
                    }
                }

                var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0];
                var cityBase = JsonSerializer.Deserialize<CityBaseConfiguration>(setting);
                if (order != null && (cityBase.CityProvince.OrgId.Equals(special.OrgId) ||
                                      cityBase.CityProvinceAssign.OrgId.Equals(special.OrgId) ||
                                      cityBase.CityEnterprise.OrgId.Equals(special.OrgId) ||
                                      cityBase.PublicSecurity.OrgId.Equals(special.OrgId)))
                {
                    if (order.Status < EOrderStatus.Filed)
                    {
                        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowRecalled,
                            new PublishSpecialDto { Order = _mapper.Map<OrderDto>(order), Special = _mapper.Map<OrderSpecialDto>(special) },
                            cancellationToken: HttpContext.RequestAborted);
                    }
                }
            }
            else
            {
                await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { Status = special.Status.Value })
                    .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
            }

            //await _orderSpecialRepository.UpdateAsync(special, HttpContext.RequestAborted);
        }

        await _orderSpecialRepository.UpdateRangeAsync(specials, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 获取工单特提信息列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("special/list")]
    public async Task<PagedDto<OrderSpecialDto>> List([FromQuery] OrderSpecialListDto dto)
    {
        var (total, items) = await _orderSpecialRepository.Queryable()
            .Includes(x => x.Order)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                x => x.Order.No.Contains(dto.Keyword!) || x.Order.Title.Contains(dto.Keyword!))
            .WhereIF(dto.State.HasValue, x => x.State == dto.State)
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderSpecialDto>(total, _mapper.Map<IReadOnlyList<OrderSpecialDto>>(items));
    }

    /// <summary>
    /// 特提列表
    /// </summary>
    /// <param name="pagedDto"></param>
    /// <returns></returns>
    [HttpGet("special/getspeciallist")]
    public async Task<PagedDto<SpecialOrderListDto>> GetSpecialList([FromQuery] SpecialPagedListDto pagedDto)
    {
        RefAsync<int> total = 0;
        var dataList = await _orderRepository.Queryable()
            .LeftJoin<OrderSpecial>((x, p) => x.Id == p.OrderId)
            .WhereIF(pagedDto.StartTime.HasValue, (x, p) => p.CreationTime >= pagedDto.StartTime)
            .WhereIF(pagedDto.EndTime.HasValue, (x, p) => p.CreationTime <= pagedDto.EndTime)
            .WhereIF(!string.IsNullOrEmpty(pagedDto.No), (x, p) => x.No.Contains(pagedDto.No))
            .WhereIF(pagedDto.State.HasValue, (x, p) => p.State == pagedDto.State)
            .WhereIF(!string.IsNullOrEmpty(pagedDto.CreatorName), (x, p) => p.CreatorName.Contains(pagedDto.CreatorName))
            .Select((x, p) => new
            {
                index = SqlFunc.RowNumber($"{p.CreationTime} desc ", $"{p.OrderId}"),
                x.Title,
                x.Status,
                x.No,
                x.AcceptType,
                x.AcceptTypeCode,
                x.HotspotName,
                x.HotspotId,
                x.HotspotSpliceName,
                x.ActualHandleTime,
                x.ExpiredTime,
                x.NearlyExpiredTime,
                x.NearlyExpiredTimeOne,
                p.NextStepName,
                p.NextStepCode,
                p.StepName,
                p.StepCode,
                p.CreatorName,
                p.CreatorOrgName,
                p.CreationTime,
                p.State,
                p.Opinion,
                SpecialId = p.Id,
                p.OrderId,
                p.WorkflowId
            })
            //将结果合并成一个表
            .MergeTable()
            //取第一条数据
            .Where(d => d.index == 1)
            .OrderByDescending(d => d.CreationTime)
            //转分页数据
            .ToPageListAsync(pagedDto.PageIndex, pagedDto.PageSize, total);
        //返回数据
        return new PagedDto<SpecialOrderListDto>(total.Value, _mapper.Map<IReadOnlyList<SpecialOrderListDto>>(dataList));
    }

    /// <summary>
    /// 工单列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("special/apply_list")]
    public async Task<PagedDto<OrderDto>> SpecialList([FromQuery] QueryOrderDto dto)
    {
        var query = _orderRepository.Queryable()
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
            //.WhereIF(!string.IsNullOrEmpty(dto.Content), d => d.Content.Contains(dto.Content!))
            .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.AcceptTypeCode == dto.AcceptType) //受理类型
                                                                                                     //.WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型
            .WhereIF(!string.IsNullOrEmpty(dto.Channel), d => d.SourceChannelCode == dto.Channel) //来源渠道
            .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.HotspotSpliceName != null && d.HotspotSpliceName.Contains(dto.Hotspot))
            .WhereIF(!string.IsNullOrEmpty(dto.TransferPhone), d => d.TransferPhone.Contains(dto.TransferPhone!))
            //.WhereIF(!string.IsNullOrEmpty(dto.OrgId), d => d.CurrentHandleOrgId == dto.OrgId)//接办部门
            .WhereIF(!string.IsNullOrEmpty(dto.OrgId), d => d.CurrentHandleOrgId == dto.OrgId) //接办部门
            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo),
                d => d.AcceptorName.Contains(dto.NameOrNo!) || d.AcceptorStaffNo.Contains(dto.NameOrNo!))
            .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart)
            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd)
            //.WhereIF(dto.EmergencyLevels.Any(), d => dto.EmergencyLevels.Contains(d.EmergencyLevel))
            .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo),
                d => d.FromPhone.Contains(dto.PhoneNo!) || d.Contact.Contains(dto.PhoneNo!))
            //.WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.PushTypeCode == dto.PushTypeCode)
            .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.OrderPushTypes.Any(opt => opt.PushTypeCode == dto.PushTypeCode)) //推送分类
            .WhereIF(dto.ExpiredTimeStart.HasValue, d => d.ExpiredTime >= dto.ExpiredTimeStart)
            .WhereIF(dto.ExpiredTimeEnd.HasValue, d => d.ExpiredTime <= dto.ExpiredTimeEnd)
            .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status) //工单状态
            .WhereIF(dto.Status != null && dto.Status == EOrderStatus.BackToUnAccept, d => d.Status <= EOrderStatus.HandOverToUnAccept);
        if (!_sessionContext.OrgIsCenter && _sessionContext.OrgId.Length >= 6)
        {
            var oneCode = _sessionContext.OrgId.Substring(0, 6);
            query = query.Where(x =>
                x.AcceptorOrgCode.StartsWith(oneCode) && !x.AcceptorOrgCode.StartsWith(_sessionContext.OrgId));
        }

        var (total, items) = await query
            .OrderByDescending(d => d.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
    }

    /// <summary>
    /// 获取工单特提信息
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("special/{id}")]
    public async Task<OrderSpecialDto> SpecialEntity(string id)
    {
        var item = await _orderSpecialRepository.Queryable()
            .Includes(x => x.Order)
            .FirstAsync(x => x.Id == id);
        var itemDto = new OrderSpecialDto();
        if (item != null)
        {
            itemDto = _mapper.Map<OrderSpecialDto>(item);
            if (itemDto.FileJson != null && itemDto.FileJson.Any())
            {
                var ids = itemDto.FileJson.Select(x => x.Id).ToList();
                itemDto.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
            }
        }

        return itemDto;
    }

    /// <summary>
    /// 列表页面基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("special/base/{id}")]
    public async Task<object> SpecialBaseData(string id)
    {
        var step = await _workflowApplication.GetRecallStepsAsync(id, HttpContext.RequestAborted);
        var specialSeats = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.SpecialSeats).SettingValue[0]);
        var specialSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.SpecialSendOrder).SettingValue[0]);
        var order = await _orderRepository.Queryable().Where(d => d.WorkflowId == id).FirstAsync(HttpContext.RequestAborted);
        if (order == null) throw UserFriendlyException.SameMessage("无效工单信息！");

        var baseTypeId = string.Empty;
        if (!_sessionContext.Roles.Contains("banzhang"))
        {
            if (step != null && step.Steps.Any() && _sessionContext.Roles.Contains("zuoxi") && specialSeats &&
                !_sessionContext.Roles.Contains("paidanyuan"))
            {
                step.Steps = step.Steps.Where(x => x.Key.ToLower() == "start").ToList();
                if (step.Steps.Any()) baseTypeId = step.Steps[0].Key;
            }

            if (step != null && step.Steps.Any() && _sessionContext.Roles.Contains("paidanyuan") && specialSendOrder &&
                !_sessionContext.Roles.Contains("zuoxi"))
            {
                step.Steps = step.Steps.Where(d => d.BusinessType is EBusinessType.Send).ToList();
                if (step.Steps.Any()) baseTypeId = step.Steps[0].Key;
            }
        }

        var isInstaShot = order.SourceChannel.Contains("随手拍");
        var rsp = new
        {
            SpecialTimeType = EnumExts.GetDescriptions<ETimeType>(),
            SpecialReason = isInstaShot
                ? _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.InstaShotSpecialReason)
                : _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SpecialReason),
            InstaShotSpecialReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.InstaShotSpecialReason),
            Step = step,
            IsTerminate =
                await _orderTerminateRepository.Queryable().Where(d => d.OrderId == order.Id && d.Status == ETerminateStatus.End).AnyAsync(),
            BaseTypeId = baseTypeId
        };
        return rsp;
    }

    /// <summary>
    /// 重办基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("reTransact/base/{id}")]
    public async Task<object> ReTransactBaseData(string id)
    {
        var order = await _orderRepository.GetAsync(id, HttpContext.RequestAborted);
        var isInstaShot = order.SourceChannel.Contains("随手拍");
        var defaultStepKey = string.Empty;
        List<Kv> orgs = new();
        if (order == null) throw UserFriendlyException.SameMessage("无效工单信息！");
        //中心会签调取方法
        var org = await _workflowDomainService.GetLevelOneOrgsAsync(order.WorkflowId, HttpContext.RequestAborted);
        orgs.AddRange(org);
        var step = await _workflowApplication.GetRecallStepsAsync(order.WorkflowId, HttpContext.RequestAborted);
        if (_appOptions.Value.IsZiGong)
        {
            step.Steps = step.Steps.Where(x => x.Key.ToLower() != "start").ToList();
            if (step.Steps.Where(x => x.BusinessType == EBusinessType.Department && x.StepType == EStepType.Normal && x.OrgLevel == 1).Any())
            {
                var stepdDefault = step.Steps
                    .Where(x => x.BusinessType == EBusinessType.Department && x.StepType == EStepType.Normal && x.OrgLevel == 1)
                    .FirstOrDefault();
                defaultStepKey = stepdDefault.Key;
            }
        }

        //获取部门信息
        var rsp = new
        {
            SpecialTimeType = EnumExts.GetDescriptions<ETimeType>(),
            SpecialReason = isInstaShot
                ? _sysDicDataCacheManager.InstaShotSpecialReason
                : _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SpecialReason),
            ReTransactErrorType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ReTransactErrorType),
            IsTerminate =
                await _orderTerminateRepository.Queryable().Where(d => d.OrderId == order.Id && d.Status == ETerminateStatus.End).AnyAsync(),
            Step = step,
            Orgs = orgs,
            DefaultStepKey = defaultStepKey
        };
        return rsp;
    }

    /// <summary>
    /// 退回基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("sendback/base/{id}")]
    public async Task<object> SendBackBaseData(string id)
    {
        var order = await _orderRepository.GetAsync(id, HttpContext.RequestAborted);
        var isInstaShot = order.SourceChannel.Contains("随手拍");
        var defaultStepKey = string.Empty;
        var defaultHandlerKey = string.Empty;
        List<Kv> orgs = new();
        if (order == null) throw UserFriendlyException.SameMessage("无效工单信息！");
        //中心会签调取方法
        var org = await _workflowDomainService.GetLevelOneOrgsAsync(order.WorkflowId, HttpContext.RequestAborted);
        orgs.AddRange(org);
        var step = await _workflowApplication.GetRecallStepsAsync(order.WorkflowId, HttpContext.RequestAborted);
        if (_appOptions.Value.IsZiGong)
        {
            step.Steps = step.Steps.Where(x => x.Key.ToLower() != "start").ToList();
            if (step.Steps.Where(x => x.BusinessType == EBusinessType.Department && x.OrgLevel == 1).Any())
            {
                var stepdDefault = step.Steps.Where(x => x.BusinessType == EBusinessType.Department && x.OrgLevel == 1)
                    .FirstOrDefault();
                defaultStepKey = stepdDefault.Key;
            }
        }

        if (_appOptions.Value.IsYiBin || _appOptions.Value.IsLuZhou)
        {
            if (order.FileOrgIsCenter.Value)
            {
                var stepdDefault = step.Steps.Where(x => x.Key.ToLower() == "start").FirstOrDefault();
                defaultStepKey = stepdDefault.Key;
                defaultHandlerKey = stepdDefault.Handler.Key;
            }

            if (!order.FileOrgIsCenter.Value)
            {
                if (step.Steps.Where(x => x.BusinessType == EBusinessType.Department && x.OrgLevel == 1).Any())
                {
                    var stepdDefault = step.Steps
                        .Where(x => x.BusinessType == EBusinessType.Department && x.OrgLevel == 1 && x.StepType == EStepType.Normal)
                        .FirstOrDefault();
                    defaultStepKey = stepdDefault.Key;
                    defaultHandlerKey = stepdDefault.Handler.Key;
                }
            }
        }

        //获取部门信息
        var rsp = new
        {
            SpecialTimeType = EnumExts.GetDescriptions<ETimeType>(),
            SpecialReason = isInstaShot
                ? _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.InstaShotSpecialReason)
                : _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SpecialReason),
            ReTransactErrorType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ReTransactErrorType),
            IsTerminate =
                await _orderTerminateRepository.Queryable().Where(d => d.OrderId == order.Id && d.Status == ETerminateStatus.End).AnyAsync(),
            Step = step,
            Orgs = orgs,
            DefaultStepKey = defaultStepKey,
            DefaultHandlerKey = defaultHandlerKey
        };
        return rsp;
    }

    /// <summary>
    /// 部门批量重提 该部门及下级部门回访结果 不满意 未评价 视为满意 
    /// </summary>
    /// <returns></returns>
    [HttpPost("org_batch_special")]
    [AllowAnonymous]
    public async Task OrgBatchSpecial([FromBody] OrgBatchSpecialDto model)
    {
        //部门信息
        var org = await _organizeRepository.Queryable().Where(o => o.Id == model.OrgId).FirstAsync(HttpContext.RequestAborted);
        if (org is null)
            throw UserFriendlyException.SameMessage("部门信息不存在 请检查部门信息是否正确！");
        //用户信息  && !u.Name.Contains("测试")
        var user = await _userRepository.Queryable().Where(u => u.OrgId == model.OrgId).FirstAsync(HttpContext.RequestAborted);
        if (user is null)
            throw UserFriendlyException.SameMessage("用户信息不存在 请检查部门下用户信息是否正确！");
        //工单信息 中心会签件不处理
        var orders = await _orderRepository.Queryable(isAdmin: true)
            .Includes(o => o.Workflow)
            .Includes(o => o.OrderVisits)
            .Where(o => (o.CounterSignType == null || o.CounterSignType == ECounterSignType.Department) && o.OrderVisits.Any(ov =>
                ov.VisitState == EVisitState.Visited &&
                ov.VisitTime >= model.StartTime && ov.VisitTime <= model.EndTime &&
                ov.OrderVisitDetails.Any(ord => ord.VisitOrgCode.StartsWith(model.OrgId) &&
                                                (SqlFunc.JsonField(ord.OrgProcessingResults, "Key") == "2" ||
                                                 SqlFunc.JsonField(ord.OrgProcessingResults, "Key") == "7" ||
                                                 SqlFunc.JsonField(ord.OrgProcessingResults, "Key") == "-1")
                ))).ToListAsync();
        if (!orders.Any())
            throw UserFriendlyException.SameMessage(org.Name + " 部门及下级部门不存在回访结果为不满意、未评价、视为满意的工单！");
        foreach (var order in orders)
        {
            var nextStep = await _workflowStepRepository.Queryable().Where(step =>
                    step.WorkflowId == order.WorkflowId && step.HandlerOrgId == model.OrgId &&
                    step.StepType == EStepType.Normal).OrderByDescending(step => step.CreationTime)
                .FirstAsync(HttpContext.RequestAborted);
            if (nextStep is null)
                continue;
            var dto = new OrderReTransactDto
            {
                AlterTime = true,
                BusinessType = EBusinessType.Department,
                FlowDirection = EFlowDirection.FiledToOrg,
                HandlerType = EHandlerType.OrgLevel,
                NextHandlers = new List<StepAssignInfo>
                {
                    new()
                    {
                        Key = org.Id, Value = org.Name,
                        OrgId = org.Id, OrgName = org.Name,
                        UserId = user.Id, Username = user.Name,
                        FlowAssignType = EFlowAssignType.Org
                    }
                },
                NextStepCode = nextStep.Code,
                NextStepName = nextStep.Name,
                OrderId = order.Id,
                Cause = "不满意二次办理",
                Reason = "部门回访不满意  批量特提",
                SpecialType = ESpecialType.SendBack,
                StepType = EStepType.Normal,
                TimeLimit = 5,
                TimeLimitUnit = ETimeType.WorkDay,
                WorkflowId = order.WorkflowId
            };
            await Add(dto);
        }
    }

    /// <summary>
    /// 批量重提   根据传入的工单编号特提所有工单
    /// </summary>
    /// <returns></returns>
    [HttpPost("order_batch_special")]
    [AllowAnonymous]
    public async Task BatchSpecial([FromBody] OrderBatchSpecialDto model)
    {
        var orders = await _orderRepository.Queryable(isAdmin: true)
            .Includes(o => o.Workflow)
            .Includes(o => o.OrderVisits)
            .Where(o => (o.CounterSignType == null || o.CounterSignType == ECounterSignType.Department))
            .In(o => o.No, model.No).ToListAsync();
        if (!orders.Any())
            throw UserFriendlyException.SameMessage("未查询到工单信息！");
        foreach (var order in orders)
        {
            var nextStep = await _workflowTraceRepository.Queryable()
                .LeftJoin<SystemOrganize>((step, o) => step.HandlerOrgId == o.Id)
                .Where((step, o) => step.WorkflowId == order.WorkflowId && step.TraceStyle == ETraceStyle.Flow && step.StepType == EStepType.Normal
                                    && !string.IsNullOrEmpty(step.HandlerOrgId) && o.Level == 1 && step.BusinessType == EBusinessType.Department)
                .OrderByDescending(step => step.CreationTime)
                .FirstAsync(HttpContext.RequestAborted);
            if (nextStep is null)
                continue;
            var dto = new OrderReTransactDto
            {
                AlterTime = true,
                BusinessType = EBusinessType.Department,
                FlowDirection = EFlowDirection.FiledToOrg,
                HandlerType = EHandlerType.OrgLevel,
                NextHandlers = new List<StepAssignInfo>
                {
                    new()
                    {
                        Key = nextStep.HandlerOrgId, Value = nextStep.HandlerOrgName,
                        OrgId = nextStep.HandlerOrgId, OrgName = nextStep.HandlerOrgName,
                        FlowAssignType = EFlowAssignType.Org
                    }
                },
                NextStepCode = nextStep.Code,
                NextStepName = nextStep.Name,
                OrderId = order.Id,
                Cause = "不满意二次办理",
                Reason = "部门回访不满意  批量特提",
                SpecialType = ESpecialType.SendBack,
                StepType = EStepType.Normal,
                TimeLimit = 5,
                TimeLimitUnit = ETimeType.WorkDay,
                WorkflowId = order.WorkflowId
            };
            await Add(dto);
        }
    }

    #endregion

    #region 市民信息

    /// <summary>
    /// 新增市民信息
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPost("citizen")]
    [LogFilter("新增市民信息")]
    public async Task Add([FromBody] CitizenAddDto dto)
    {
        var citizen =
            await _citizenRepository.CountAsync(x => x.PhoneNumber == dto.PhoneNumber, HttpContext.RequestAborted);
        if (citizen > 0)
            throw UserFriendlyException.SameMessage("市民联系电话信息重复");
        await _citizenRepository.AddAsync(dto, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 删除市民信息
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpDelete("citizen")]
    [LogFilter("删除市民信息")]
    public async Task Delete([FromBody] CitizenDeleteDto dto)
    {
        await _citizenRepository.RemoveAsync(x => x.Id == dto.Id);
    }

    /// <summary>
    /// 更新市民信息
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut("citizen")]
    [LogFilter("更新市民信息")]
    public async Task Update([FromBody] CitizenUpdateDto dto)
    {
        var citizen = await _citizenRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        if (citizen is null)
            throw UserFriendlyException.SameMessage("无效市民信息");
        _mapper.Map(dto, citizen);
        citizen.LastModificationName = _sessionContext.UserName;
        await _citizenRepository.UpdateAsync(citizen, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 获取市民信息列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("citizen/list")]
    public async Task<PagedDto<CitizenDto>> List([FromQuery] CitizenListDto dto)
    {
        var (total, items) = await _citizenRepository.Queryable()
            .WhereIF(!string.IsNullOrEmpty(dto.PhoneNumber), x => x.PhoneNumber.Contains(dto.PhoneNumber!))
            .WhereIF(!string.IsNullOrEmpty(dto.Label), x => x.Label != null && x.Label.Contains(dto.Label!))
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<CitizenDto>(total, _mapper.Map<IReadOnlyList<CitizenDto>>(items));
    }

    /// <summary>
    /// 获取市民信息
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("citizen/{id}")]
    public async Task<Citizen> CitizenEntity(string id)
    {
        return await _citizenRepository.Queryable()
            .Includes(x => x.labelDetails)
            .FirstAsync(x => x.Id == id);
    }

    /// <summary>
    /// 获取市民信息
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("citizen_phone/{phone}")]
    public async Task<object> Citizen(string phone)
    {
        //市民基本信息
        var citizen = await _citizenRepository.Queryable()
            .Includes(x => x.labelDetails)
            .FirstAsync(x => x.PhoneNumber == phone);
        //var calls = await _trCallRecordRepository.Queryable().Where(x => x.CallDirection == 0 && x.CPN == phone).OrderBy(x => x.CreatedTime).ToListAsync();
        //var oneCallTime = calls != null && calls.Count() > 0 ? calls[0].CreatedTime : DateTime.Now;
        //var lastNum = calls != null && calls.Count() > 0 ? calls.Count() - 1 : -1;
        //var lastCallTime = lastNum >= 0 ? calls[lastNum].CreatedTime : DateTime.Now;

        var oneCallTime = DateTime.Now;
        var lastCallTime = DateTime.Now;
        if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun)
        {
            var calls = await _callApplication.QueryTianrunCallsAsync(phone, ECallDirection.In, cancellationToken: HttpContext.RequestAborted);
            oneCallTime = calls.FirstOrDefault()?.CreatedTime ?? DateTime.Now;
            var count = calls.Count;
            lastCallTime = count > 1 ? calls[count - 2].CreatedTime : oneCallTime;
        }
        else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang)
        {
            var calls = await _callApplication.QueryCallsAsync(phone, ECallDirection.In, cancellationToken: HttpContext.RequestAborted);
            oneCallTime = calls.FirstOrDefault()?.BeginIvrTime ?? DateTime.Now;
            var count = calls.Count;
            lastCallTime = count > 1 ? calls[count - 2].CreationTime : oneCallTime;
        }


        //工单历史 
        var oders = await _orderRepository.Queryable().Where(x => x.Contact == phone)
            .OrderBy(x => x.CreationTime, OrderByType.Desc).ToListAsync();
        var allOrderNum = oders.Count;
        var endOrderNum = oders.Count(x => (int)x.Status >= 300);
        var handOrderNum =
            oders.Count(x => (int)x.Status < 300);
        var DissatisfactionNum = await _orderVisitedDetailRepository.Queryable()
            .Includes(x => x.OrderVisit)
            .Includes(x => x.OrderVisit, v => v.Order)
            .Where(x => x.OrderVisit.Order.Contact == phone && (SqlFunc.JsonField(x.OrgProcessingResults, "Value") == "不满意" ||
                                                                SqlFunc.JsonField(x.OrgProcessingResults, "Value") == "非常不满意"))
            .Distinct().Select(x => new { x.OrderVisit.OrderId }).CountAsync();
        //来电历史
        //var callsHistory = await _trCallRecordRepository.Queryable().Where(x => x.CPN == phone || x.CDPN == phone).ToListAsync();
        var allCallNum = 0;
        var connectNum = 0;
        var callBackNum = 0;
        //if (callsHistory != null && callsHistory.Any())
        //{
        //    allCallNum = callsHistory.Count(x => x.CallDirection == ECallDirection.In);
        //    connectNum = callsHistory.Count(x => x.CallDirection == ECallDirection.In && x.Duration > 0);
        //    callBackNum = callsHistory.Count(x => x.CallDirection == ECallDirection.Out);
        //}

        if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun)
        {
            var callsHistory =
                await _callApplication.QueryTianrunCallsAsync(phone, cancellationToken: HttpContext.RequestAborted);
            if (callsHistory != null && callsHistory.Any())
            {
                allCallNum = callsHistory.Count(x => x.CallDirection == ECallDirection.In);
                connectNum = callsHistory.Count(x => x.CallDirection == ECallDirection.In && x.Duration > 0);
                callBackNum = callsHistory.Count(x => x.CallDirection == ECallDirection.Out);
            }
        }
        else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang)
        {
            var histories =
                await _callApplication.QueryCallsAsync(phone, cancellationToken: HttpContext.RequestAborted);
            if (histories.Any())
            {
                allCallNum = histories.Count(x => x.Direction == ECallDirection.In);
                connectNum = histories.Count(x => x.Direction == ECallDirection.In && x.Duration > 0);
                callBackNum = histories.Count(x => x.Direction == ECallDirection.Out);
            }
        }

        //关注诉求
        var hotspotNames = string.Join(",", oders.Select(x => x.HotspotName).Distinct().Take(5).ToList());
        var rsp = new
        {
            Citizen = citizen,
            OneCallTime = oneCallTime,
            LastCallTime = lastCallTime,
            Order = new
            {
                allOrderNum = allOrderNum,
                endOrderNum = endOrderNum,
                handOrderNum = handOrderNum,
                DissatisfactionNum = DissatisfactionNum
            },
            CallHistory = new { AllCallNum = allCallNum, ConnectNum = connectNum, CallBackNum = callBackNum },
            HotspotNames = hotspotNames,
        };
        return rsp;
    }


    /// <summary>
    /// 新增市民标签信息
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPost("citizen_label")]
    public async Task Add([FromBody] LabelDetailAddDto dto)
    {
        var label = await _labelDetailRepository.CountAsync(x => x.CitizenId == dto.CitizenId && x.Label == dto.Label,
            HttpContext.RequestAborted);
        if (label > 0)
            throw UserFriendlyException.SameMessage("市民联系标签信息重复");
        await _citizenRepository.LabelAddAsync(dto, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 删除市民标签信息
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpDelete("citizen_label")]
    public async Task Delete([FromBody] LabelDetailDeleteDto dto)
    {
        var label = await _labelDetailRepository.GetAsync(x => x.Id == dto.Id, HttpContext.RequestAborted);
        if (label == null || (label.CreatorName != _sessionContext.UserName))
            throw UserFriendlyException.SameMessage("市民联系标签信息错误");
        await _citizenRepository.LabelDeleteAsync(label, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 获取市民标签信息列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("citizen_label/list")]
    public async Task<PagedDto<LabelDetailDto>> List([FromQuery] CitizenQueryDto dto)
    {
        var (total, items) = await _labelDetailRepository.Queryable()
            .Includes(x => x.Citizen)
            .WhereIF(!string.IsNullOrEmpty(dto.Label), x => x.Label.Contains(dto.Label!))
            .WhereIF(!string.IsNullOrEmpty(dto.CreatorName),
                x => x.CreatorName != null && x.CreatorName.Contains(dto.CreatorName!))
            .Where(x => x.CitizenId == dto.CitizenId)
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<LabelDetailDto>(total, _mapper.Map<IReadOnlyList<LabelDetailDto>>(items));
    }

    #endregion

    #region 重复性事件

    /// <summary>
    /// 新增重复性事件
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPost("repeatable_event")]
    [LogFilter("新增重复性事件")]
    public async Task Add([FromBody] RepeatableEventAddDto dto)
    {
        var repeatable = _mapper.Map<RepeatableEvent>(dto);
        var repeatableId = await _repeatableEventRepository.AddAsync(repeatable, HttpContext.RequestAborted);
        List<RepeatableEventDetail> detail;
        if (!string.IsNullOrEmpty(repeatableId) && dto.Details.Any())
            dto.Details.ForEach(x => x.RepeatableId = repeatableId);
        detail = _mapper.Map<List<RepeatableEventDetail>>(dto.Details);
        if (detail.Any())
            await _repeatableEventDetailRepository.AddRangeAsync(detail, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 删除重复性事件
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpDelete("repeatable_event")]
    [LogFilter("删除重复性事件")]
    public async Task Delete([FromBody] RepeatableEventDeleteDto dto)
    {
        await _repeatableEventRepository.RemoveAsync(x => x.Id == dto.Id);
        await _repeatableEventDetailRepository.RemoveAsync(x => x.RepeatableId == dto.Id);
    }

    /// <summary>
    /// 删除重复性事件明细
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpDelete("repeatable_event_detail/{id}")]
    [LogFilter("删除重复性事件")]
    public async Task Delete([FromBody] string id)
    {
        await _repeatableEventDetailRepository.RemoveAsync(x => x.Id == id);
    }

    /// <summary>
    /// 更新重复性事件
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut("repeatable_event")]
    [LogFilter("更新重复性事件")]
    public async Task Update([FromBody] RepeatableEventUpdateDto dto)
    {
        var repeatable = await _repeatableEventRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        if (repeatable is null)
            throw UserFriendlyException.SameMessage("无效重复性事件");
        _mapper.Map(dto, repeatable);
        repeatable.LastModificationName = _sessionContext.UserName;
        await _repeatableEventRepository.UpdateAsync(repeatable, HttpContext.RequestAborted);
        List<RepeatableEventDetail> detail;
        if (dto.Details.Any())
            dto.Details.ForEach(x => x.RepeatableId = dto.Id);
        await _repeatableEventDetailRepository.DeleteAsync(dto.Id, HttpContext.RequestAborted);
        detail = _mapper.Map<List<RepeatableEventDetail>>(dto.Details);
        if (detail.Any())
            await _repeatableEventDetailRepository.AddRangeAsync(detail, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 获取重复性事件列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("repeatable_event/list")]
    public async Task<PagedDto<RepeatableEventDto>> List([FromQuery] RepeatableEventListDto dto)
    {
        var (total, items) = await _repeatableEventRepository.Queryable()
            .Includes(x => x.Details)
            .Includes(x => x.Details, y => y.Order)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                d => d.Title.Contains(dto.Keyword!) || (d.KeyWords != null && d.KeyWords.Contains(dto.Keyword!)))
            .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart)
            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd)
            .WhereIF(!string.IsNullOrEmpty(dto.Code), x => x.Code != null && x.Code.Contains(dto.Code!))
            .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title.Contains(dto.Title!))
            .WhereIF(!string.IsNullOrEmpty(dto.KeyWords), x => x.KeyWords != null && x.KeyWords.Contains(dto.KeyWords!))
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<RepeatableEventDto>(total, _mapper.Map<IReadOnlyList<RepeatableEventDto>>(items));
    }

    /// <summary>
    /// 获取重复性事件
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("repeatable_event")]
    public async Task<RepeatableEventDto> CitizenEntity([FromQuery] RepeatableEventEntityDto dto)
    {
        var repeatableEvent = await _repeatableEventRepository.Queryable()
            .Includes(x =>
                x.Details.WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Order.Title.Contains(dto.Keyword!))
                    .ToList())
            .Includes(x => x.Details, y => y.Order)
            .FirstAsync(x => x.Id == dto.Id);
        return _mapper.Map<RepeatableEventDto>(repeatableEvent);
    }

    #endregion

    #region 工单词库

    /// <summary>
    /// 新增工单词库
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPost("order_word")]
    [LogFilter("新增工单词库")]
    public async Task Add([FromBody] OrderWordAddDto dto)
    {
        var word = _mapper.Map<OrderWord>(dto);
        var any = await _orderWrodRepository.Queryable().Where(x => x.Tag == dto.Tag).AnyAsync();
        if (any)
            throw UserFriendlyException.SameMessage("已存在相同关键词！");
        await _orderWrodRepository.AddAsync(word, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 删除工单词库
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpDelete("order_word")]
    [LogFilter("删除工单词库")]
    public async Task Delete([FromBody] OrderWordDeleteDto dto)
    {
        await _orderRepository.RemoveOrderWrodBatchAsync(dto.Ids, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 更新工单词库
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut("order_word")]
    [LogFilter("更新工单词库")]
    public async Task Update([FromBody] OrderWordUpdateDto dto)
    {
        var word = await _orderWrodRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        if (word is null)
            throw UserFriendlyException.SameMessage("无效工单词库");

        var any = await _orderWrodRepository.Queryable().Where(x => x.Tag == dto.Tag && x.Id != dto.Id).AnyAsync();
        if (any)
            throw UserFriendlyException.SameMessage("已存在相同关键词！");

        _mapper.Map(dto, word);
        word.LastModificationName = _sessionContext.UserName;
        await _orderWrodRepository.UpdateAsync(word, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 获取工单词库列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("order_word/list")]
    public async Task<PagedDto<OrderWordDto>> List([FromQuery] OrderWordListDto dto)
    {
        var (total, items) = await _orderWrodRepository.Queryable()
            .WhereIF(!string.IsNullOrEmpty(dto.Tag), x => x.Tag == dto.Tag!)
            .WhereIF(!string.IsNullOrEmpty(dto.Classify), x => x.Classify.Contains(dto.Classify!))
            .WhereIF(!string.IsNullOrEmpty(dto.Synonym), x => x.Synonym != null && x.Synonym.Contains(dto.Synonym!))
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderWordDto>(total, _mapper.Map<IReadOnlyList<OrderWordDto>>(items));
    }

    /// <summary>
    /// 导出工单词库列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("order_word/list/export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> ListExport([FromBody] ExportExcelDto<OrderWordListDto> dto)
    {
        var query = _orderRepository.QueryOrderWordList(dto.QueryDto);
        List<OrderWord> list;
        if (dto.IsExportAll)
        {
            list = await query.ToListAsync(HttpContext.RequestAborted);
        }
        else
        {
            var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
            list = items;
        }

        var orderDtos = _mapper.Map<ICollection<OrderWordDto>>(list);

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderWordDto>(dto.ColumnInfos);

        var dtos = orderDtos
            .Select(stu => _mapper.Map(stu, typeof(OrderWordDto), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);
        return ExcelStreamResult(stream, "工单词库导出");
    }

    /// <summary>
    /// 获取工单词库
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("order_word/{id}")]
    public async Task<OrderWord> OrderWordEntity(string id)
    {
        return await _orderWrodRepository.Queryable()
            .FirstAsync(x => x.Id == id);
    }

    /// <summary>
    /// 获取工单词库基本信息
    /// </summary>
    /// <returns></returns>
    [HttpGet("order_word/base")]
    public async Task<object> Base()
    {
        var rsp = new
        {
            OrderWordClassify = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderWordClassify),
        };
        return rsp;
    }

    #endregion

    #region 工单观察、关注

    /// <summary>
    /// 新增工单观察
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPost("order_observe")]
    [LogFilter("新增工单观察")]
    public async Task Add([FromBody] OrderObserveAddDto dto)
    {
        var ids = dto.OrderIds.Select(x => x.OrderId).ToList();
        var list = await _orderObserveRepository.Queryable().In(x => x.OrderId, ids).Select(x => x.OrderId)
            .ToListAsync();
        if (list.Any())
            dto.OrderIds = ids.Except(list).Select(x => new OrdersObserveAddDto { OrderId = x }).ToList();
        if (!dto.OrderIds.Any())
            throw UserFriendlyException.SameMessage("无效工单观察,当前所选工单都已观察");
        var observe = _mapper.Map<List<OrderObserve>>(dto.OrderIds);
        await _orderObserveRepository.AddRangeAsync(observe, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 删除工单观察
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpDelete("order_observe")]
    [LogFilter("删除工单观察")]
    public async Task Delete([FromBody] OrderObserveDeleteDto dto)
    {
        await _orderRepository.RemoveOrderObserveBatchAsync(dto.Ids, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 更新工单观察
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut("order_observe")]
    [LogFilter("更新工单观察")]
    public async Task Update([FromBody] OrderObserveUpdateDto dto)
    {
        var word = await _orderObserveRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        if (word is null)
            throw UserFriendlyException.SameMessage("无效工单观察");
        _mapper.Map(dto, word);
        await _orderObserveRepository.UpdateAsync(word, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 获取工单观察列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("order_observe/list")]
    public async Task<PagedDto<OrderObserveDto>> List([FromQuery] OrderObserveListDto dto)
    {
        var quer = _orderApplication.OrderObserveList(dto);
        var (total, items) = await
            quer.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderObserveDto>(total, _mapper.Map<IReadOnlyList<OrderObserveDto>>(items));
    }

    /// <summary>
    /// 获取工单观察列表导出
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("order_observe/list/export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> ListExport([FromBody] ExportExcelDto<OrderObserveListDto> dto)
    {
        var query = _orderApplication.OrderObserveList(dto.QueryDto);
        List<OrderObserve> 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<OrderObserveDto>>(data);

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderObserveDto>(dto.ColumnInfos);

        var dtos = dataDtos
            .Select(stu => _mapper.Map(stu, typeof(OrderObserveDto), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);

        return ExcelStreamResult(stream, "工单关注列表");
    }

    /// <summary>
    /// 获取工单观察
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("order_observe/{id}")]
    public async Task<OrderObserve> OrderObserveEntity(string id)
    {
        return await _orderObserveRepository.Queryable()
            .FirstAsync(x => x.Id == id);
    }

    /// <summary>
    /// 列表页面基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("order_observe/base-data")]
    public async Task<object> OrderObserveBaseData()
    {
        var rsp = new
        {
            AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType)
        };
        return rsp;
    }

    #endregion

    #region 工单终结

    /// <summary>
    /// 新增工单终结
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPost("order_finality")]
    [LogFilter("新增工单终结")]
    public async Task Add([FromBody] OrderFinalityAddDto dto)
    {
        var ids = dto.OrderIds.Select(x => x.OrderId).ToList();
        var list = await _orderFinalityRepository.Queryable().In(x => x.OrderId, ids).Select(x => x.OrderId)
            .ToListAsync();
        if (list.Any())
            dto.OrderIds = ids.Except(list).Select(x => new OrdersFinalityAddDto { OrderId = x }).ToList();
        if (!dto.OrderIds.Any())
            throw UserFriendlyException.SameMessage("无效工单终结,当前所选工单都已终结");
        var observe = _mapper.Map<List<OrderFinality>>(dto.OrderIds);
        await _orderFinalityRepository.AddRangeAsync(observe, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 删除工单终结
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpDelete("order_finality")]
    [LogFilter("删除工单终结")]
    public async Task Delete([FromBody] OrderFinalityDeleteDto dto)
    {
        await _orderRepository.RemoveOrderFinalityBatchAsync(dto.Ids, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 更新工单终结
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut("order_finality")]
    [LogFilter("更新工单终结")]
    public async Task Update([FromBody] OrderFinalityUpdateDto dto)
    {
        var word = await _orderFinalityRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        if (word is null)
            throw UserFriendlyException.SameMessage("无效工单观察");
        _mapper.Map(dto, word);
        await _orderFinalityRepository.UpdateAsync(word, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 获取工单终结列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("order_finality/list")]
    public async Task<PagedDto<OrderFinalityDto>> List([FromQuery] OrderFinalityListDto dto)
    {
        var (total, items) = await _orderFinalityRepository.Queryable()
            .Includes(x => x.Order)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Order.No.Contains(dto.Keyword!) || x.Order.Title.Contains(dto.Keyword!))
            .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true, x => x.Order.IsProvince == true)   //是否省工单
            .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == false, x => x.Order.IsProvince == false)
            .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.Order.No.Contains(dto.No))                                //工单编号
            .WhereIF(dto.Status.HasValue, x => x.Order.Status == dto.Status)                                         //工单状态
            .WhereIF(!string.IsNullOrEmpty(dto.Channel), x => x.Order.SourceChannelCode == dto.Channel)              //来源渠道
            .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepName), x => x.Order.CurrentStepName.Contains(dto.CurrentStepName)) //当前节点
            .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Order.Title.Contains(dto.Title))                       //工单标题
            .WhereIF(dto.CreationTimeStart.HasValue, x => x.Order.CreationTime >= dto.CreationTimeStart)             //受理时间Start
            .WhereIF(dto.CreationTimeEnd.HasValue, x => x.Order.CreationTime <= dto.CreationTimeEnd)                 //受理时间End
            .WhereIF(!string.IsNullOrEmpty(dto.CreatorName), x => x.CreatorName.Contains(dto.CreatorName))           //设置人
            .WhereIF(dto.SetCreationTimeStart.HasValue, x => x.CreationTime >= dto.SetCreationTimeStart)             //设置时间Start
            .WhereIF(dto.SetCreationTimeEnd.HasValue, x => x.CreationTime <= dto.SetCreationTimeEnd)                 //设置时间End
            .WhereIF(dto.ExpiredTimeStart.HasValue, x => x.Order.ExpiredTime >= dto.ExpiredTimeStart)                //期满时间Start
            .WhereIF(dto.ExpiredTimeEnd.HasValue, x => x.Order.ExpiredTime <= dto.ExpiredTimeEnd)                    //期满时间End
            .WhereIF(!string.IsNullOrEmpty(dto.AcceptTypeCode), x => x.Order.AcceptTypeCode == dto.AcceptTypeCode)   //受理类型
            .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), x => x.Order.HotspotSpliceName != null && x.Order.HotspotSpliceName.Contains(dto.Hotspot)) //热点
            .WhereIF(!string.IsNullOrEmpty(dto.CurrentHandleOrgName), x => x.Order.CurrentHandleOrgName.Contains(dto.CurrentHandleOrgName)) //接办部门
            .WhereIF(dto.CurrentHandleTimeStart.HasValue, x => x.Order.CurrentHandleTime >= dto.CurrentHandleTimeStart)//接办时间Start
            .WhereIF(dto.CurrentHandleTimeEnd.HasValue, x => x.Order.CurrentHandleTime <= dto.CurrentHandleTimeEnd)    //接办时间End
            .WhereIF(dto.FiledTimeStart.HasValue, x => x.Order.FiledTime >= dto.FiledTimeStart)                        //办结时间Start
            .WhereIF(dto.FiledTimeEnd.HasValue, x => x.Order.FiledTime <= dto.FiledTimeEnd)                            //办结时间End
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderFinalityDto>(total, _mapper.Map<IReadOnlyList<OrderFinalityDto>>(items));
    }

    /// <summary>
    /// 获取工单终结
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("order_finality/{id}")]
    public async Task<OrderFinality> OrderFinalityEntity(string id)
    {
        return await _orderFinalityRepository.Queryable()
            .FirstAsync(x => x.Id == id);
    }

    #endregion

    #region 超期查询

    /// <summary>
    /// 工单即将超期列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("order/about_expire/list")]
    public async Task<PagedDto<OrderDto>> AboutList([FromQuery] AboutToExpireListDto dto)
    {
        var (total, items) = await _orderApplication.GetAboutToExpireAsync(dto)
            .ToPagedListAsync(dto, HttpContext.RequestAborted);
        return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
    }

    /// <summary>
    /// 工单即将超期列表(不查总条数)
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("order/about_expire/list_items")]
    public async Task<List<OrderDto>> AboutListAsnc([FromQuery] AboutToExpireListDto dto)
    {
        return (await _orderApplication.GetAboutToExpireAsync(dto).ToFixedListAsync(dto.PageIndex - 1, dto.PageSize, HttpContext.RequestAborted))
            .Adapt<List<OrderDto>>();
    }

    /// <summary>
    /// 工单即将超期列表总条数
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("order/about_expire/list_count")]
    public async Task<int> AboutListCountAsnc([FromQuery] AboutToExpireListDto dto)
    {
        return await _orderApplication.GetAboutToExpireAsync(dto).CountAsync(HttpContext.RequestAborted);
    }

    /// <summary>
    /// 工单即将超期列表(优化测试)
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("order/about_expire/list_optimize")]
    public async Task<PagedDto<OrderDto>> GetAboutToExpireAsyncV1([FromQuery] AboutToExpireListDto dto)
    {
        var (t, i) = await _orderApplication.GetAboutToExpireAsync(dto)
            .ToPagedListAsync(dto, HttpContext.RequestAborted);
        return new PagedDto<OrderDto>(t, _mapper.Map<IReadOnlyList<OrderDto>>(i));
    }

    /// <summary>
    /// 工单即将超期列表导出
    /// </summary>
    /// <returns></returns>
    [HttpPost("order/about_expire/_export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> AboutListExport([FromBody] ExportExcelDto<AboutToExpireListDto> dto)
    {
        var query = _orderApplication.GetAboutToExpireAsync(dto.QueryDto);
        List<Hotline.Orders.Order> orders;
        if (dto.IsExportAll)
        {
            orders = await query.ToListAsync(HttpContext.RequestAborted);
        }
        else
        {
            var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
            orders = items;
        }

        var ordersDtos = _mapper.Map<ICollection<OrderDto>>(orders);
        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderDto>(dto.ColumnInfos);
        var dtos = ordersDtos
            .Select(stu => _mapper.Map(stu, typeof(OrderDto), dynamicClass))
            .Cast<object>()
            .ToList();
        var stream = ExcelHelper.CreateStream(dtos);
        return ExcelStreamResult(stream, "工单即将超期列表数据");
    }

    ///// <summary>
    ///// 工单即将超期节点列表
    ///// </summary>
    ///// <param name="dto"></param>
    ///// <returns></returns>
    //[HttpGet("order/about_expire_node/list")]
    //public async Task<PagedDto<WorkflowOrderDto>> AboutNodeList([FromQuery] AboutToExpireListDto dto)
    //{
    //    return await _orderApplication.GetAboutToExpireNodeAsync(dto, HttpContext.RequestAborted);
    //}

    /// <summary>
    /// 工单超期列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("order/expire/list")]
    public async Task<PagedDto<OrderDto>> ExpireList([FromQuery] AboutToExpireListDto dto)
    {
        var (total, items) = await _orderApplication.GetToExpireAsync(dto)
            .ToPagedListAsync(dto, HttpContext.RequestAborted);
        return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
    }

    /// <summary>
    /// 工单超期列表导出
    /// </summary>
    /// <returns></returns>
    [HttpPost("order/expire/_export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> ExpireListExport([FromBody] ExportExcelDto<AboutToExpireListDto> dto)
    {
        var query = _orderApplication.GetToExpireAsync(dto.QueryDto);
        List<Hotline.Orders.Order> orders;
        if (dto.IsExportAll)
        {
            orders = await query.ToListAsync(HttpContext.RequestAborted);
        }
        else
        {
            var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
            orders = items;
        }

        var ordersDtos = _mapper.Map<ICollection<OrderDto>>(orders);
        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderDto>(dto.ColumnInfos);
        var dtos = ordersDtos
            .Select(stu => _mapper.Map(stu, typeof(OrderDto), dynamicClass))
            .Cast<object>()
            .ToList();
        var stream = ExcelHelper.CreateStream(dtos);
        return ExcelStreamResult(stream, "工单超期列表数据");
    }

    ///// <summary>
    ///// 工单超期节点列表
    ///// </summary>
    ///// <param name="dto"></param>
    ///// <returns></returns>
    //[HttpGet("order/expire_node/list")]
    //public async Task<PagedDto<WorkflowOrderDto>> NodeList([FromQuery] AboutToExpireListDto dto)
    //{
    //    return await _orderApplication.GetToExpireNodeAsync(dto, HttpContext.RequestAborted);
    //}

    #endregion

    #region 工单签收

    /// <summary>
    /// 工单签收
    /// </summary>
    [HttpPost("sign/{orderId}")]
    [LogFilter("工单签收")]
    public async Task Sign(string orderId)
    {
        var order = await _orderRepository.GetAsync(orderId, HttpContext.RequestAborted);
        if (order == null)
            throw new UserFriendlyException($"无效工单编号, orderId: {orderId}", "无效工单编号");
        if (order.IsSigned())
            throw UserFriendlyException.SameMessage("该工单已被签收");
        order.Sign(_sessionContext.RequiredUserId, _sessionContext.UserName);
        order.AutoAccept(_sessionContext.RequiredUserId, _sessionContext.UserName, _sessionContext.StaffNo);

        if (!string.IsNullOrEmpty(order.WorkflowId))
        {
            var workflow = await _workflowDomainService.SignToSomebodyAsync(
                order.WorkflowId,
                _sessionContext.RequiredUserId, _sessionContext.UserName,
                _sessionContext.RequiredOrgId, _sessionContext.OrgName,
                HttpContext.RequestAborted);

            order.HandlerOrgs = workflow.HandlerOrgs;
            order.HandlerUsers = workflow.HandlerUsers;
            order.FlowedOrgIds = workflow.FlowedOrgIds;
            order.FlowedUserIds = workflow.FlowedUserIds;
        }

        await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
    }

    #endregion

    #region 导入工单

    /// <summary>
    /// 下载工单导入模板
    /// </summary>
    /// <returns></returns>
    [HttpGet("download-order-template")]
    public async Task<object> DownLoadOrderTemplate()
    {
        List<ExcelContent> list = new List<ExcelContent>();
        ExcelContent excelContent = new ExcelContent() { ExternalId = "自编号" };
        list.Add(excelContent);
        return _exportApplication.ExportData(list, "demo.xlsx");
    }

    /// <summary>
    /// 导入工单
    /// TODO 回访信息需要写回访表? 
    /// TODO 工单是否需要写发布表?
    /// TODO 是否自动签收工单?
    /// TODO SourceChannel 是否和 Source 相同?
    /// </summary>
    /// <param name="file"></param>
    /// <returns></returns>
    [HttpPost("import-order")]
    public async Task<object> ImportOrder(IFormFile file)
    {
        using (var stream = new MemoryStream())
        {
            file.CopyTo(stream);
            var list = MiniExcel.Query<ExcelContent>(stream).ToList();
            int count = 0;
            int errorCount = 0;
            int addCount = 0;
            int modifyCount = 0;
            var allowSources = new Dictionary<string, string>
            {
                { "麻辣社区", "MLSQ" }, { "人民网", "RMW" }, { "省长信箱", "SZXX" }, { "问政四川", "WZSC" }
            };
            var errorMessage = new StringBuilder();
            if (list == null || list.Count == 0)
            {
                return new { Count = count, ErrorCount = errorCount, AddCount = addCount, ModifyCount = modifyCount, ErrorMessage = "数据为空" };
            }

            count = list.Count;
            var i = 0;
            foreach (var item in list)
            {
                i++;
                try
                {
                    var validationResult = item.ValidateObject(false);
                    if (validationResult.NotNullOrEmpty())
                    {
                        errorMessage.Append($"第{i + 1}行: {validationResult}\r\n");
                        errorCount++;
                        continue;
                    }

                    var allowSource = allowSources.FirstOrDefault(m => m.Key == item.Source).Value;
                    if (allowSource.IsNullOrEmpty())
                    {
                        errorCount++;
                        continue;
                    }

                    var SourceCode = (ESource)Enum.Parse(typeof(ESource), allowSource);
                    var acceptType = _sysDicDataCacheManager.AcceptType
                        .FirstOrDefault(m => m.DicDataName == item.AcceptType);

                    if (acceptType == null)
                    {
                        errorMessage.Append($"第{i + 1}行: 不能通过受理类型 {item.AcceptType} 查询到对应的受理类型Code\r\n");
                        continue;
                    }

                    var order = await _orderRepository.GetAsync(x => x.ExternalId == item.ExternalId && x.Source == SourceCode,
                        HttpContext.RequestAborted) ?? new Orders.Order();
                    item.Source = SourceCode.ToString();
                    order = _mapper.Map(item, order);
                    order.AcceptTypeCode = acceptType.DicDataValue;
                    order.SourceChannel = SourceCode.GetDescription();
                    order.SourceChannelCode = ((int)SourceCode).ToString();
                    order.Status = EOrderStatus.Visited;

                    #region 处理数据开始

                    // order.Source = SourceCode; //来源

                    //处理热点
                    //处理一级热点
                    string hotspotId = "";
                    string hotspotName = "";
                    string hotspotFullName = "";
                    var hotspotOne = await _hotspotTypeRepository.Queryable()
                        .FirstAsync(x => x.HotSpotName == item.HotspotNameOne, HttpContext.RequestAborted);
                    if (hotspotOne != null)
                    {
                        hotspotId = hotspotOne.Id;
                        hotspotName = hotspotOne.HotSpotName;
                        hotspotFullName = hotspotOne.HotSpotFullName;
                        var hotspotTwo = await _hotspotTypeRepository.Queryable()
                            .FirstAsync(x => x.HotSpotName == item.HotspotNameTwo && x.ParentId == hotspotId, HttpContext.RequestAborted);
                        if (hotspotTwo != null)
                        {
                            hotspotId = hotspotTwo.Id;
                            hotspotName = hotspotTwo.HotSpotName;
                            hotspotFullName = hotspotTwo.HotSpotFullName;
                            var hotspotThree = await _hotspotTypeRepository.Queryable()
                                .FirstAsync(x => x.HotSpotName == item.HotspotNameThree && x.ParentId == hotspotId, HttpContext.RequestAborted);
                            if (hotspotThree != null)
                            {
                                hotspotId = hotspotThree.Id;
                                hotspotName = hotspotThree.HotSpotName;
                                hotspotFullName = hotspotThree.HotSpotFullName;
                                var hotspotFour = await _hotspotTypeRepository.Queryable()
                                    .FirstAsync(x => x.HotSpotName == item.HotspotNameFour && x.ParentId == hotspotId,
                                        HttpContext.RequestAborted);
                                if (hotspotFour != null)
                                {
                                    hotspotId = hotspotFour.Id;
                                    hotspotName = hotspotFour.HotSpotName;
                                    hotspotFullName = hotspotFour.HotSpotFullName;
                                    var hotspotFive = await _hotspotTypeRepository.Queryable()
                                        .FirstAsync(x => x.HotSpotName == item.HotspotNameFive && x.ParentId == hotspotId,
                                            HttpContext.RequestAborted);
                                    if (hotspotFive != null)
                                    {
                                        hotspotId = hotspotFive.Id;
                                        hotspotName = hotspotFive.HotSpotName;
                                        hotspotFullName = hotspotFive.HotSpotFullName;
                                    }
                                }
                            }
                        }
                    }

                    order.HotspotId = hotspotId;
                    order.HotspotName = hotspotName;
                    order.HotspotSpliceName = hotspotFullName;

                    //处理部门
                    var orgOne = await _organizeRepository.Queryable()
                        .FirstAsync(x => x.Name == item.OrgLevelOneName, HttpContext.RequestAborted);
                    if (orgOne != null)
                    {
                        order.OrgLevelOneCode = orgOne.Id;
                        order.OrgLevelOneName = orgOne.Name;
                        var orgTwo = await _organizeRepository.Queryable()
                            .FirstAsync(x => x.Name == item.OrgLevelTwoName && x.ParentId == order.OrgLevelOneCode, HttpContext.RequestAborted);
                        if (orgTwo != null)
                        {
                            order.OrgLevelTwoCode = orgTwo.Id;
                            order.OrgLevelTwoName = orgTwo.Name;
                        }
                    }

                    //承办部门
                    var ActualHandleOrg = await _organizeRepository.Queryable()
                        .FirstAsync(x => x.Name == item.ActualHandleOrgName, HttpContext.RequestAborted);
                    if (ActualHandleOrg != null)
                    {
                        order.ActualHandleOrgCode = ActualHandleOrg.Id;
                    }

                    //处理地址
                    order.FullAddress = $"{order.Address}{order.Street}";

                    order.FirstVisitResultCode = _sysDicDataCacheManager
                                                     .GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction)
                                                     .FirstOrDefault(m => m.DicDataName == item.VisitResult)?.DicDataValue
                                                 ?? order.FirstVisitResultCode;

                    #endregion

                    if (order.Id.IsNullOrEmpty())
                    {
                        //order.Source = item;
                        var id = await _orderDomainService.AddAsync(order, false, HttpContext.RequestAborted);
                        if (!string.IsNullOrEmpty(id))
                        {
                            addCount++;
                        }
                        else
                        {
                            errorCount++;
                        }
                    }
                    else
                    {
                        // _mapper.Map(item, order);
                        await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
                        modifyCount++;
                    }
                }
                catch (Exception ex)
                {
                    errorCount++;
                }
            }

            return new
            {
                Count = count,
                ErrorCount = errorCount,
                AddCount = addCount,
                ModifyCount = modifyCount,
                ErrorMessage = errorMessage.ToString()
            };
        }
    }

    /// <summary>
    /// 导入基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("import-basedata")]
    public async Task<object> ImportBaseData()
    {
        var rsp = new
        {
            Source = EnumExts.GetDescriptions<ESource>(),
        };
        return rsp;
    }

    #endregion

    #region 二次办理

    /// <summary>
    /// 新增二次办理
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPost("secondary_handling")]
    [LogFilter("新增二次办理")]
    public async Task OrderSecondaryHandlingAdd([FromBody] AddOrderSecondaryHandlingDto dto)
    {
        await _orderSecondaryHandlingApplication.AddAsync(dto, HttpContext.RequestAborted);
    }


    /// <summary>
    /// 二次办理退回
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPost("secondary_handling/send_back")]
    [LogFilter("二次办理退回")]
    public async Task OrderSecondaryHandlingSendBackAsync([FromBody] SendBackOrderSecondaryHandlingDto dto)
    {
        await _orderSecondaryHandlingApplication.SendBackAsync(dto, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 二次办理审批
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPut("secondary_handling/audit")]
    [LogFilter("二次办理审批")]
    [LogFilterAlpha("二次办理审核")]
    public async Task OrderSecondaryHandlingAudit([FromBody] AuditOrderSecondaryHandlingDto dto)
    {
        var model = await _orderSecondaryHandlingApplication.Entity(dto.Id, HttpContext.RequestAborted);
        if (model == null || model.State != ESecondaryHandlingState.Apply)
            throw UserFriendlyException.SameMessage("无效二次办理审批信息！");
        await _orderSecondaryHandlingApplication.AuditAsync(dto, model, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 二次办理批量审批
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPut("secondary_handling/batch_audit")]
    [LogFilter("二次办理批量审批")]
    [LogFilterAlpha("二次办理审核批量")]
    public async Task OrderSecondaryHandlingBatchAudit([FromBody] AuditOrderSecondaryHandlingDto dto)
    {
        foreach (var item in dto.Ids)
        {
            var model = await _orderSecondaryHandlingApplication.Entity(item, HttpContext.RequestAborted);
            if (model == null || model.State != ESecondaryHandlingState.Apply)
                throw UserFriendlyException.SameMessage("无效二次办理审批信息！");
            await _orderSecondaryHandlingApplication.AuditAsync(dto, model, HttpContext.RequestAborted);
        }
    }


    /// <summary>
    /// 二次办理申请列表
    /// </summary>
    /// <returns></returns>
    [HttpGet("secondary_handling/apply")]
    public async Task<PagedDto<OrderVisitDetailDto>> OrderSecondaryHandlingApplyQuery([FromQuery] MayScreenListDto dto)
    {
        var query = _orderSecondaryHandlingApplication.ApplyQuery(dto, HttpContext.RequestAborted);
        var (total, items) = await query.ToPagedListAsync(dto, HttpContext.RequestAborted);

        return new PagedDto<OrderVisitDetailDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDetailDto>>(items));
    }

    /// <summary>
    /// 二次办理申请列表导出
    /// </summary>
    /// <returns></returns>
    [HttpPost("secondary_handling/apply_export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> OrderSecondaryHandlingApplyExport([FromBody] ExportExcelDto<MayScreenListDto> dto)
    {
        var query = _orderSecondaryHandlingApplication.ApplyQuery(dto.QueryDto, HttpContext.RequestAborted);
        List<OrderVisitDetail> visitDetails;
        if (dto.IsExportAll)
        {
            visitDetails = await query.ToListAsync(HttpContext.RequestAborted);
        }
        else
        {
            var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
            visitDetails = items;
        }

        var visitDetailsDtos = _mapper.Map<ICollection<OrderVisitDetailDto>>(visitDetails);

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderVisitDetailDto>(dto.ColumnInfos);

        var dtos = visitDetailsDtos
            .Select(stu => _mapper.Map(stu, typeof(OrderVisitDetailDto), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);

        return ExcelStreamResult(stream, "二次办理申请列表数据");
    }

    /// <summary>
    /// 二次办理列表
    /// </summary>
    /// <returns></returns>
    [HttpGet("secondary_handling")]
    public async Task<PagedDto<OrderSecondaryHandlingDto>> OrderSecondaryHandlingQuery([FromQuery] SecondaryHandlingListDto dto)
    {
        var query = _orderSecondaryHandlingApplication.Query(dto, HttpContext.RequestAborted);
        var (total, items) = await query.ToPagedListAsync(dto, HttpContext.RequestAborted);

        return new PagedDto<OrderSecondaryHandlingDto>(total, _mapper.Map<IReadOnlyList<OrderSecondaryHandlingDto>>(items));
    }

    /// <summary>
    /// 二次办理列表导出
    /// </summary>
    /// <returns></returns>
    [HttpPost("secondary_handling/_export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> OrderSecondaryHandlingExport([FromBody] ExportExcelDto<SecondaryHandlingListDto> dto)
    {
        var query = _orderSecondaryHandlingApplication.Query(dto.QueryDto, HttpContext.RequestAborted);
        List<OrderSecondaryHandling> secondaryHandling;
        if (dto.IsExportAll)
        {
            secondaryHandling = await query.ToListAsync(HttpContext.RequestAborted);
        }
        else
        {
            var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
            secondaryHandling = items;
        }

        var secondaryHandlingDtos = _mapper.Map<ICollection<OrderSecondaryHandlingDto>>(secondaryHandling);

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderSecondaryHandlingDto>(dto.ColumnInfos);

        var dtos = secondaryHandlingDtos
            .Select(stu => _mapper.Map(stu, typeof(OrderSecondaryHandlingDto), dynamicClass))
            .Cast<object>()
            .ToList();

        var stream = ExcelHelper.CreateStream(dtos);

        return ExcelStreamResult(stream, "二次办理列表数据");
    }

    /// <summary>
    /// 获取实体
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("secondary_handling/{id}")]
    public async Task<OrderSecondaryHandlingDto> OrderSecondaryHandlingEntity(string id)
    {
        var model = await _orderSecondaryHandlingApplication.Entity(id, HttpContext.RequestAborted);
        var dto = _mapper.Map<OrderSecondaryHandlingDto>(model);
        if (model.FileJson != null && model.FileJson.Any())
        {
            var ids = model.FileJson.Select(x => x.Id).ToList();
            var files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
            dto.Files = files.Where(x => x.Classify == "二次办理申请").ToList();
        }

        return dto;
    }

    /// <summary>
    /// 列表页面基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("secondary_handling/base")]
    public async Task<object> SecondaryHandlingBaseData()
    {
        var rsp = new
        {
            Status = EnumExts.GetDescriptions<ESecondaryHandlingState>(),
            CounterSignType = EnumExts.GetDescriptions<ECounterSignType>(),
            AcceptType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType),
            SourceChannel = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SourceChannel),
            VisitSatisfaction = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction),
            DissatisfiedReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.DissatisfiedReason),
        };
        return rsp;
    }

    #endregion

    #region 副本工单

    /// <summary>
    /// 获取副本工单列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("order_copy/list")]
    public async Task<PagedDto<OrderDto>> OrderCopyList([FromQuery] OrderCopyListDto dto)
    {
        var (total, items) = await _orderCopyRepository.Queryable()
            .Where(x => x.OrderId == dto.OrderId)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.No.Contains(dto.Keyword!))
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
    }

    /// <summary>
    /// 查询工单修改记录
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("order_modify_records/list")]
    public async Task<PagedDto<OrderDto>> OrderModifyRecordsList([FromQuery] PagedKeywordRequest dto)
    {
        var (total, items) = await _orderCopyRepository.Queryable()
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.No.Contains(dto.Keyword!))
            .WhereIF(_appOptions.Value.IsLuZhou, x => x.AuditSource == EOrderUpdateSource.Alter)
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
    }

    /// <summary>
    /// 修改明细
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("order_modify_records/getinfo/{id}")]
    public async Task<object> GetModifyRecordsInfo(string id)
    {
        //修改前数据
        var modifyRecordsInfo = await _orderCopyRepository.GetAsync(p => p.Id == id, HttpContext.RequestAborted);
        if (modifyRecordsInfo is null)
            throw UserFriendlyException.SameMessage("修改明细查询失败！");

        //如何取修改后的数据
        var copyNew = await _orderCopyRepository.Queryable().OrderBy(x => x.CreationTime)
            .FirstAsync(p => p.OrderId == modifyRecordsInfo.OrderId && p.CreationTime > modifyRecordsInfo.CreationTime);
        OrderDto newInfo = null;
        if (copyNew != null)
        {
            newInfo = _mapper.Map<OrderDto>(copyNew);
        }
        else
        {
            var order = await _orderRepository.Queryable().FirstAsync(d => d.Id == modifyRecordsInfo.OrderId);
            if (order is not null)
            {
                newInfo = _mapper.Map<OrderDto>(order);
                newInfo.CenterOpinion = order.CenterToOrgOpinion;
            }
        }

        var oldInfo = _mapper.Map<OrderDto>(modifyRecordsInfo);
        oldInfo.CenterOpinion = modifyRecordsInfo.CenterToOrgOpinion;
        return new { OldInfo = oldInfo, NewInfo = newInfo };
    }

    #endregion

    #region 外部市民管理

    /// <summary>
    /// 下载外部市民导入模板
    /// </summary>
    /// <returns></returns>
    [HttpGet("download-externalcitizens-template")]
    public async Task<object> DownLoadCitizensTemplate()
    {
        List<ExternalCitizensExcelContent> list = new List<ExternalCitizensExcelContent>();
        ExternalCitizensExcelContent excelContent = new ExternalCitizensExcelContent() { };
        list.Add(excelContent);
        return _exportApplication.ExportData(list, "demo.xlsx");
    }

    /// <summary>
    /// 导入外部市民
    /// </summary>
    /// <param name="file"></param>
    /// <returns></returns>
    [HttpPost("import-externalcitizens")]
    public async Task<object> ImportExternalcitizens(IFormFile file)
    {
        using (var stream = new MemoryStream())
        {
            file.CopyTo(stream);
            var list = MiniExcel.Query<ExternalCitizensExcelContent>(stream).ToList();
            int count = 0;
            int errorCount = 0;
            int addCount = 0;
            //int modifyCount = 0;
            List<ExternalCitizensExcelContent> listreturn = new List<ExternalCitizensExcelContent>();
            if (list != null && list.Count > 0)
            {
                count = list.Count;
                foreach (var item in list)
                {
                    try
                    {
                        var externalcitizens =
                            await _externalCitizensRepository.GetAsync(x => x.PhoneNum == item.PhoneNum, HttpContext.RequestAborted);
                        if (externalcitizens is null)
                        {
                            externalcitizens = _mapper.Map<ExternalCitizens>(item);
                            var id = await _externalCitizensRepository.AddAsync(externalcitizens, HttpContext.RequestAborted);
                            if (!string.IsNullOrEmpty(id))
                            {
                                addCount++;
                                listreturn.Add(item);
                            }
                            else
                            {
                                errorCount++;
                            }
                        }
                        else
                        {
                            listreturn.Add(item);
                            //_mapper.Map(item, externalcitizens);
                            //await _externalCitizensRepository.UpdateAsync(externalcitizens, HttpContext.RequestAborted);
                            //modifyCount++;
                        }
                    }
                    catch (Exception ex)
                    {
                        errorCount++;
                    }
                }
            }

            return new { Count = count, ErrorCount = errorCount, AddCount = addCount, ResultList = listreturn /*, ModifyCount = modifyCount*/ };
        }
    }

    /// <summary>
    /// 外部市民列表
    /// </summary>
    /// <returns></returns>
    [HttpGet("externalcitizens-list")]
    public async Task<PagedDto<ExternalcitizensRep>> QueryExternalcitizens([FromQuery] QueryExternalcitizensRequest dto)
    {
        var (total, items) = await _externalCitizensRepository.Queryable()
            .WhereIF(!string.IsNullOrEmpty(dto.PhoneNum), x => x.PhoneNum.Contains(dto.PhoneNum))
            .WhereIF(!string.IsNullOrEmpty(dto.Name), x => x.Name.Contains(dto.Name))
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

        return new PagedDto<ExternalcitizensRep>(total, _mapper.Map<IReadOnlyList<ExternalcitizensRep>>(items));
    }

    /// <summary>
    /// 删除外部市民
    /// </summary>
    /// <param name="ids"></param>
    /// <returns></returns>
    [HttpDelete("del-externalcitizens")]
    public async Task DelExternalcitizens(string[] ids)
    {
        var list = await _externalCitizensRepository.Queryable().In(ids).ToListAsync(HttpContext.RequestAborted);
        await _externalCitizensRepository.RemoveRangeAsync(list, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 修改外部市民
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("modify-externalcitizens")]
    public async Task ModifyExternalcitizens([FromBody] ModifyExternalcitizensDto dto)
    {
        if (dto.PhoneNum.Length != 11)
            throw UserFriendlyException.SameMessage("手机号不合法");
        bool isHas = await _externalCitizensRepository.Queryable().AnyAsync(x => x.Id != dto.Id && x.PhoneNum == dto.PhoneNum);
        if (isHas)
            throw UserFriendlyException.SameMessage("已存在当前电话，请核对后再修改");
        var model = await _externalCitizensRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        if (model == null)
            throw UserFriendlyException.SameMessage("无效数据");
        model.PhoneNum = dto.PhoneNum;
        model.Name = dto.Name;
        await _externalCitizensRepository.UpdateAsync(model, HttpContext.RequestAborted);
    }

    #endregion

    #region 工单期满时间、来源方式修改

    /// <summary>
    /// 修改期满时间  
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("update-orderexpired-time")]
    public async Task UpdateOrderExpiredTime([FromBody] UpdateOrderExpiredTimeDto dto)
    {
        if (dto == null || string.IsNullOrEmpty(dto.Id) || !dto.ExpiredTime.HasValue)
            throw UserFriendlyException.SameMessage("参数信息有误！");

        var orderData = await _orderRepository.GetAsync(p => p.Id == dto.Id, HttpContext.RequestAborted);
        if (orderData == null)
            throw UserFriendlyException.SameMessage("工单查询失败！");

        #region 写入操作记录

        OrderModifyingRecords orderModifyingRecords = new()
        {
            OrderId = orderData.Id,
            OrderNo = orderData.No,
            ProvinceNo = orderData.ProvinceNo,
            UpdateOrderType = EUpdateType.ExpiredTime,
            OldValue = orderData.ExpiredTime == null ? "" : orderData.ExpiredTime.Value.ToString("yyyy-MM-dd HH:mm:ss"),
            NewValue = dto.ExpiredTime.Value.ToString("yyyy-MM-dd HH:mm:ss")
        };
        await _orderModifyingRecordsRepository.AddAsync(orderModifyingRecords, HttpContext.RequestAborted);

        #endregion

        //写入新的数据
        orderData.ExpiredTime = dto.ExpiredTime;
        await _orderRepository.UpdateAsync(orderData, HttpContext.RequestAborted);

        //向省上推送数据
        if (dto.IsPush && orderData.Status > EOrderStatus.WaitForAccept)
        {
            var orderDto = _mapper.Map<OrderDto>(orderData);
            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
                cancellationToken: HttpContext.RequestAborted);
        }
    }

    /// <summary>
    /// 修改来源方式
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("update-order-sourcechannel")]
    [AllowAnonymous]
    public async Task UpdateOrderSourceChannel([FromBody] UpdateOrderSourceChannelDto dto)
    {
        if (dto == null || dto.Ids == null || dto.Ids.Count == 0)
            throw UserFriendlyException.SameMessage("参数信息有误！");

        foreach (var item in dto.Ids)
        {
            var orderData = await _orderRepository.GetAsync(p => p.Id == item || p.ProvinceNo == item, HttpContext.RequestAborted);

            if (orderData != null)
            {
                #region 写入操作记录

                OrderModifyingRecords orderModifyingRecords = new()
                {
                    OrderId = orderData.Id,
                    OrderNo = orderData.No,
                    ProvinceNo = orderData.ProvinceNo,
                    UpdateOrderType = EUpdateType.SourceChannel,
                    OldValue = orderData.SourceChannelCode + "_" + orderData.SourceChannel,
                    NewValue = "QT_其他"
                };
                await _orderModifyingRecordsRepository.AddAsync(orderModifyingRecords, HttpContext.RequestAborted);

                #endregion

                orderData.SourceChannel = "其他";
                orderData.SourceChannelCode = "QT";
                // await _orderRepository.UpdateAsync(orderData, HttpContext.RequestAborted);

                //向省上推送数据
                if (dto.IsPush)
                {
                    var orderDto = _mapper.Map<OrderDto>(orderData);
                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
                        cancellationToken: HttpContext.RequestAborted);
                }
            }
        }
    }

    /// <summary>
    /// 根据工单ID获取修改记录
    /// </summary>
    /// <returns></returns>
    [HttpGet("get-order-modifying-records-list")]
    public async Task<IReadOnlyList<OrderModifyingRecordsDto>> GetOrderModifyingRecordsList([FromQuery] string Id)
    {
        var list = await _orderModifyingRecordsRepository.Queryable().Where(p => p.OrderId == Id).OrderByDescending(p => p.CreationTime)
            .ToListAsync();
        return _mapper.Map<IReadOnlyList<OrderModifyingRecordsDto>>(list);
    }

    /// <summary>
    /// 获取修改记录
    /// </summary>
    /// <returns></returns>
    [HttpGet("get-order-modifying-records-all-list")]
    public async Task<IReadOnlyList<OrderModifyingRecordsDto>> GetOrderModifyingRecordsAllList([FromQuery] OrderModifyingRecordsRequest dto)
    {
        var list = await _orderModifyingRecordsRepository.Queryable()
            .WhereIF(dto.StartTime.HasValue, p => p.CreationTime >= dto.StartTime)
            .WhereIF(dto.EndTime.HasValue, p => p.CreationTime <= dto.EndTime)
            .WhereIF(!string.IsNullOrEmpty(dto.OrderNo), p => p.OrderNo.Contains(dto.OrderNo))
            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.ProvinceNo.Contains(dto.ProvinceNo))
            .WhereIF(dto.UpdateOrderType == "0", p => p.UpdateOrderType == EUpdateType.ExpiredTime)
            .WhereIF(dto.UpdateOrderType == "1", p => p.UpdateOrderType == EUpdateType.SourceChannel)
            .OrderByDescending(p => p.CreationTime)
            .ToListAsync();
        return _mapper.Map<IReadOnlyList<OrderModifyingRecordsDto>>(list);
    }

    #endregion

    #region 工单平移

    /// <summary>
    /// 查询工单平移待办理人
    /// </summary>
    /// <returns></returns>
    [HttpGet("migration/{orderId}")]
    public async Task<GetOrderMigrationDto> Migration(string orderId)
    {
        var order = await _orderRepository.GetAsync(orderId, HttpContext.RequestAborted);
        var step = new WorkflowStep();
        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.RoleZuoXi);
        if (string.IsNullOrEmpty(order.SignerId))
            throw UserFriendlyException.SameMessage("工单尚未签收，暂不支持平移");
        if (!string.IsNullOrEmpty(order.WorkflowId))
        {
            var steps = await _workflowStepRepository.Queryable()
                .Where(d => d.ExternalId == orderId && d.Status != EWorkflowStepStatus.Handled)
                .ToListAsync(HttpContext.RequestAborted);
            if (steps.Count > 1)
                throw UserFriendlyException.SameMessage("多个待办理节点暂不支持平移");
            step = steps.First();
            if (step.BusinessType is not EBusinessType.Seat and not EBusinessType.Send)
                throw UserFriendlyException.SameMessage("当前办理节点非中心暂不支持平移");
            setting = step.BusinessType is EBusinessType.Seat
                ? _systemSettingCacheManager.GetSetting(SettingConstants.RoleZuoXi)
                : _systemSettingCacheManager.GetSetting(SettingConstants.RolePaiDan);
        }

        var roles = setting?.SettingValue.ToList();
        var users = await _userRepository.Queryable()
            .Includes(d => d.Organization)
            .Includes(d => d.Roles)
            .Where(d => d.Roles.Any(x => roles.Contains(x.Name)))
            .ToListAsync(HttpContext.RequestAborted);
        return new GetOrderMigrationDto
        {
            StepId = step.Id,
            OrderId = orderId,
            Handlers = users.Select(d => new OrderMigrationHandler
            {
                UserId = d.Id,
                Username = d.Name,
                OrgId = d.OrgId,
                OrgName = d.Organization.Name,
                RoleNames = string.Join(',', d.Roles.Select(x => x.DisplayName).ToList())
            }).ToList()
        };
    }


    /// <summary>
    /// 工单平移
    /// </summary>
    [HttpPost("change-handler")]
    public async Task ChangeHandler([FromBody] ChangeHandlerDto dto)
    {
        var special = await _orderSpecialRepository.Queryable().Where(x => x.OrderId == dto.OrderId && x.State == 0).AnyAsync();
        if (special)
            throw UserFriendlyException.SameMessage("当前工单特提审批中，请审批后再操作！");
        if (string.IsNullOrEmpty(dto.StepId))
        {
            await _orderRepository.Updateable()
                .SetColumns(o => new Orders.Order()
                { SignerId = dto.Handler.UserId, SignerName = dto.Handler.Username, Status = EOrderStatus.HandOverToUnAccept })
                .Where(o => o.Id == dto.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
        }
        else
        {
            var step = await _workflowStepRepository.Queryable()
                .Includes(d => d.WorkflowTrace)
                .FirstAsync(d => d.Id == dto.StepId, HttpContext.RequestAborted);
            if (step is null)
                throw UserFriendlyException.SameMessage("无效节点编号");
            await _workflowDomainService.ChangeHandlerBatchAsync(
                new List<(string userId, string username, string orgId, string orgName, string? roleId, string? roleName, ICollection<WorkflowStep>
                    steps)>
                {
                    new(dto.Handler.UserId, dto.Handler.Username, dto.Handler.OrgId, dto.Handler.OrgName, step.RoleId, step.RoleName,
                        new List<WorkflowStep> { step })
                }, HttpContext.RequestAborted);
            var status = EOrderStatus.HandOver;
            if (step.BusinessType == EBusinessType.Seat && step.StepType == EStepType.Start)
            {
                status = EOrderStatus.HandOverToUnAccept;
                await _orderRepository.Updateable()
                    .SetColumns(o => new Orders.Order() { Status = status, SignerId = dto.Handler.UserId })
                    .Where(o => o.Id == dto.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
            }
            else if (step.BusinessType == EBusinessType.Send)
            {
                await _orderRepository.Updateable()
                    .SetColumns(o => new Orders.Order()
                    { Status = status, CenterToOrgHandlerId = dto.Handler.UserId, CenterToOrgHandlerName = dto.Handler.Username })
                    .Where(o => o.Id == dto.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
            }
            else
            {
                await _orderRepository.Updateable()
                    .SetColumns(o => new Orders.Order() { Status = status })
                    .Where(o => o.Id == dto.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
            }
        }
    }

    #endregion

    #region 分析报告

    /// <summary>
    /// 新增分析报告
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPost("analysis")]
    [LogFilter("新增分析报告")]
    public async Task OrderAnalysisAdd([FromBody] AddOrderAnalysisDto dto)
    {
        await _orderAnalysisApplication.AddAsync(dto, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 修改分析报告
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPut("analysis")]
    [LogFilter("修改分析报告")]
    public async Task OrderAnalysisUpdate([FromBody] UpdateOrderAnalysisDto dto)
    {
        await _orderAnalysisApplication.UpdateAsync(dto, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 删除分析报告
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpDelete("analysis")]
    [LogFilter("删除分析报告")]
    public async Task OrderAnalysisDelete([FromBody] DeleteOrderAnalysisDto dto)
    {
        await _orderAnalysisApplication.DeleteAsync(dto, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 分析报告列表
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpGet("analysis_list")]
    [LogFilter("分析报告列表")]
    public async Task<PagedDto<OrderAnalysisDto>> OrderAnalysisListQuery([FromQuery] OrderAnalysisListDto dto)
    {
        var (total, items) = await _orderAnalysisApplication.ListQuery(dto, HttpContext.RequestAborted)
            .ToPagedListAsync(dto, HttpContext.RequestAborted);
        return new PagedDto<OrderAnalysisDto>(total, items);
    }

    /// <summary>
    /// 分析报告明细
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpGet("analysis_detail")]
    [LogFilter("分析报告明细")]
    public async Task<PagedDto<OrderDto>> OrderAnalysisDetailQuery([FromQuery] OrderAnalysisDetailDto dto)
    {
        var (total, items) = await _orderAnalysisApplication.DetailQuery(dto, HttpContext.RequestAborted)
            .ToPagedListAsync(dto, HttpContext.RequestAborted);
        return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
    }

    /// <summary>
    /// 生成分析报告
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpGet("analysis_report")]
    [LogFilter("生成分析报告")]
    public async Task<object> OrderAnalysisReportQuery([FromQuery] OrderAnalysisDetailDto dto)
    {
        return await _orderAnalysisApplication.ReportQuery(dto, HttpContext.RequestAborted);
    }

    #endregion

    #region 添加补充

    /// <summary>
    /// 添加补充 _notificationWaitSendRepository
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("add_order_complement")]
    public async Task AddOrderComplement([FromBody] AddComplementDto 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 _orderDomainService.GetOrderAsync(dto.OrderId, cancellationToken: HttpContext.RequestAborted);
        if (data == null)
            throw UserFriendlyException.SameMessage("工单查询失败！");

        OrderComplement complement = new OrderComplement()
        {
            OrderId = dto.OrderId,
            Opinion = dto.Opinion,
            SupplyName = _sessionContext.UserName,
            SupplyTime = DateTime.Now,
            No = data.No,
            IsProComplement = false
        };

        var id = await _orderComplementRepository.AddAsync(complement, HttpContext.RequestAborted);
        if (!string.IsNullOrEmpty(id))
        {
            #region 处理推送消息

            //获取当前办理节点数据
            var work = await _workflowStepRepository.GetAsync(p => p.Id == data.ActualHandleStepId, HttpContext.RequestAborted);
            if (work != null)
            {
                //获取办理指定类型
                var workflowStepHandler = work.GetWorkflowStepHandler();
                if (workflowStepHandler != null)
                {
                    AddCircularDto circularDto = new AddCircularDto()
                    {
                        Title = "工单补充",
                        Content = "工单" + data.No + "有补充内容，请注意查收！",
                        CircularTypeId = "6",
                        CircularTypeName = "工单补充",
                        IsMustRead = true,
                        SourceOrgId = _sessionContext.RequiredOrgId,
                        SourceOrgName = _sessionContext.OrgName,
                        CircularType = ECircularType.Person
                    };

                    List<CircularReadGroupDto> users = [];
                    if (!string.IsNullOrEmpty(workflowStepHandler.UserId)) //指定用户
                    {
                        users.Add(new CircularReadGroupDto()
                        {
                            UserId = workflowStepHandler.UserId,
                            UserName = workflowStepHandler.Username
                        });
                    }
                    else if (!string.IsNullOrEmpty(workflowStepHandler.RoleId)) //指定角色
                    {
                        //查询指定角色下面所有的用户
                        var userlist = await _userRepository.Queryable().Where(x =>
                                x.OrgId == workflowStepHandler.OrgId && x.Roles.Any(d => workflowStepHandler.RoleId.Contains(d.Id)))
                            .Select(d => new CircularReadGroupDto
                            {
                                UserId = d.Id,
                                UserName = d.Name
                            }).ToListAsync();
                        users.AddRange(userlist);
                    }
                    else if (!string.IsNullOrEmpty(workflowStepHandler.OrgId)) //指定部门
                    {
                        users.Add(new CircularReadGroupDto()
                        {
                            OrgId = workflowStepHandler.OrgId,
                            OrgName = workflowStepHandler.OrgName
                        });
                        circularDto.CircularType = ECircularType.Org;
                    }

                    if (users != null && users.Count > 0)
                    {
                        circularDto.CircularReadGroups = users;
                        //调用推送消息通用接口
                        await _circularRecordDomainService.AddCircularMessage(circularDto, HttpContext.RequestAborted);
                    }
                }
            }

            #endregion
        }
    }

    #endregion
}