using DotNetCore.CAP;
using Hotline.Api.Filter;
using Hotline.Application.ExportExcel;
using Hotline.Application.FlowEngine;
using Hotline.Application.Orders;
using Hotline.Application.Quality;
using Hotline.Caching.Interfaces;
using Hotline.CallCenter.Calls;
using Hotline.Enterprise;
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.Permissions;
using Hotline.Push.FWMessage;
using Hotline.Push.Notifies;
using Hotline.Repository.SqlSugar.Extensions;
using Hotline.Repository.SqlSugar.Ts;
using Hotline.SeedData;
using Hotline.Settings;
using Hotline.Settings.Hotspots;
using Hotline.Settings.TimeLimits;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.Enterprise;
using Hotline.Share.Dtos.FlowEngine;
using Hotline.Share.Dtos.FlowEngine.Workflow;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Dtos.Order.Migration;
using Hotline.Share.Dtos.Order.Publish;
using Hotline.Share.Dtos.Settings;
using Hotline.Share.Enums.CallCenter;
using Hotline.Share.Enums.FlowEngine;
using Hotline.Share.Enums.Order;
using Hotline.Share.Enums.Push;
using Hotline.Share.Enums.Quality;
using Hotline.Share.Enums.Settings;
using Hotline.Share.Requests;
using Hotline.Tools;
using Hotline.Users;
using Hotline.YbEnterprise.Sdk;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.OpenApi.Writers;
using MiniExcelLibs;
using MongoDB.Driver;
using NPOI.SS.Formula.Functions;
using NPOI.SS.Util;
using Org.BouncyCastle.Utilities;
using SqlSugar;
using StackExchange.Redis;
using System.Diagnostics.Tracing;
using XF.Domain.Authentications;
using XF.Domain.Cache;
using XF.Domain.Constants;
using XF.Domain.Entities;
using XF.Domain.Exceptions;
using XF.Domain.Repository;
using XF.Utility.EnumExtensions;

namespace Hotline.Api.Controllers;

/// <summary>
/// 工单
/// </summary>
public class OrderController : BaseController
{
    private readonly IOrderDomainService _orderDomainService;
    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 ISessionContext _sessionContext;
    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 IRepository<TrCallRecord> _trCallRecordRepository;
    private readonly IOrderApplication _orderApplication;
    private readonly IEnterpriseService _enterpriseService;
    private readonly IPushDomainService _pushDomainService;
    private readonly ILogger<OrderController> _logger;
    private readonly ITypedCache<YbEnterpriseToken> _cacheResponse;
    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;

    public OrderController(
        IOrderDomainService orderDomainService,
        IOrderRepository orderRepository,
        IWorkflowApplication workflowApplication,
        IWorkflowDomainService workflowDomainService,
        IRepository<Hotspot> hotspotTypeRepository,
        ISystemOrganizeRepository organizeRepository,
        IDefinitionDomainService definitionDomainService,
        ISystemDicDataCacheManager sysDicDataCacheManager,
        ISessionContext sessionContext,
        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,
        IRepository<TrCallRecord> trCallRecordRepository,
        IOrderApplication orderApplication,
        IEnterpriseService enterpriseService,
        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,
        IRepository<OrderModifyingRecords> orderModifyingRecordsRepository
        )
    {
        _orderDomainService = orderDomainService;
        _orderRepository = orderRepository;
        _workflowApplication = workflowApplication;
        _workflowDomainService = workflowDomainService;
        _hotspotTypeRepository = hotspotTypeRepository;
        _organizeRepository = organizeRepository;
        _definitionDomainService = definitionDomainService;
        _sysDicDataCacheManager = sysDicDataCacheManager;
        _sessionContext = sessionContext;
        _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;
        _trCallRecordRepository = trCallRecordRepository;
        _logger = logger;
        _orderApplication = orderApplication;
        _enterpriseService = enterpriseService;
        _pushDomainService = pushDomainService;
        _cacheResponse = cacheResponse;
        _orderSendBackAuditRepository = orderSendBackAuditRepository;
        _userRepository = userRepository;
        _exportApplication = exportApplication;
        _transpondCityRawDataRepository = transpondCityRawDataRepository;
        _orderSpecialDetailRepository = orderSpecialDetailRepository;
        _orderSecondaryHandlingApplication = orderSecondaryHandlingApplication;
        _orderCopyRepository = orderCopyRepository;
        _externalCitizensRepository = externalCitizensRepository;
        _orderModifyingRecordsRepository = orderModifyingRecordsRepository;
    }

    #region 工单发布

    /// <summary>
    /// 查询（工单发布）
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("publish")]
    public async Task<PagedDto<PublishDto>> PublishOrderList([FromQuery] QueryOrderPublishDto dto)
    {
        var (total, items) = await _orderRepository.Queryable()
            .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 == dto.No)
            .WhereIF(dto.PubState == EPubState.Pub, d => d.Status >= EOrderStatus.Published)
            .WhereIF(dto.PubState == EPubState.NoPub, d => d.Status < EOrderStatus.Published)
            //.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.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.OrderPublish.CreationTime >= dto.CreationTimeStart)
            .WhereIF(dto.FiledTimeEnd.HasValue, d => d.OrderPublish.CreationTime <= dto.CreationTimeEnd)
            .WhereIF(dto.QuerySelf.HasValue && dto.QuerySelf.Value, d => d.WaitForPublisherId == _sessionContext.RequiredUserId)
            .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)
    {
        foreach (var item in dto.Ids)
        {
            var order = await _orderRepository.GetAsync(item, HttpContext.RequestAborted);
            if (order != null)
            {
                try
                {
                    OrderPublish orderPublish = new OrderPublish();
                    orderPublish.OrderId = order.Id;
                    orderPublish.No = order.No;
                    orderPublish.PublishState = false;//当前写死为false
                    orderPublish.ArrangeTitle = order.Title;
                    orderPublish.ArrangeContent = order.Content;
                    orderPublish.ArrangeOpinion = order.ActualOpinion;
                    orderPublish.ProPublishState = false;
                    orderPublish.FeedBackPhone = order.Contact;
                    orderPublish.CreatorName = _sessionContext.UserName;
                    await _orderPublishRepository.AddAsync(orderPublish);
                    order.Publish(orderPublish.PublishState);
                    await _orderRepository.UpdateAsync(order);
                    //推省上
                    var publishPublishOrder = _mapper.Map<PublishPublishOrderDto>(orderPublish);
                    publishPublishOrder.Order = _mapper.Map<OrderDto>(order);
                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderPublishOrder, publishPublishOrder);

                    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 is { ProcessType: EProcessType.Zhiban, CounterSignType: null })
                    {
                        orderVisit.VisitState = EVisitState.Visited;
                    }

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

                    string visitId = await _orderVisitRepository.AddAsync(orderVisit);

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

                    var seatDetail = new OrderVisitDetail();
                    seatDetail.VisitId = visitId;
                    seatDetail.VisitTarget = EVisitTarget.Seat;


                    var orgDetail = new OrderVisitDetail();
                    orgDetail.VisitId = visitId;
                    orgDetail.VisitOrgCode = order.ActualHandleOrgCode;
                    orgDetail.VisitOrgName = order.ActualHandleOrgName;
                    orgDetail.VisitTarget = EVisitTarget.Org;
                    if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null })
                    {
                        var satisfy = new Kv() { Key = "4", Value = "满意" };
                        orgDetail.OrgProcessingResults = satisfy;
                        orgDetail.OrgHandledAttitude = satisfy;
                    }
                    visitedDetail.Add(orgDetail);

                    if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null })
                    {
                        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);
                }
                catch { }
            }
        }
    }

    /// <summary>
    /// 发布工单
    /// </summary>
    /// <returns></returns>
    [Permission(EPermission.PublishOrder)]
    [HttpPost("publish")]
    [LogFilter("发布工单")]
    public async Task PublishOrder([FromBody] PublishOrderDto dto)
    {
        //验证订单
        var order = await _orderRepository.GetAsync(dto.Id, HttpContext.RequestAborted);

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

        //新增发布工单
        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);
        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderPublishOrder, publishPublishOrder);

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

        if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null })
        {
            orderVisit.VisitState = EVisitState.Visited;
        }

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

        string visitId = await _orderVisitRepository.AddAsync(orderVisit);

        //新增回访信息
        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 (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null })
            {
                var satisfy = new Kv() { Key = "4", Value = "满意" };
                orgDetail.OrgProcessingResults = satisfy;
                orgDetail.OrgHandledAttitude = satisfy;
            }

            visitedDetail.Add(orgDetail);
        }

        if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null })
        {
            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);
        //推送回访信息
        //推门户
        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.ActualOpinion,
            NetizenEvaluateType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.NetizenEvaluateType).Select(x => new Kv { Key = x.DicDataValue, Value = x.DicDataName }).ToList()
        };
        var (idName, idNames) =
            await _workflowDomainService.GetUnvisitOrgsAsync(order.WorkflowId, HttpContext.RequestAborted);
        res.ActualHandleOrgName = idName;
        res.idNames = idNames.ToList();
        return res;
    }

    /// <summary>
    /// 已发布列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("published")]
    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 == dto.No!)
            .WhereIF(dto.Resolve.HasValue, x => x.Resolve == dto.Resolve)
            .OrderBy(d => d.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

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

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

        return pubentity;
    }

    /// <summary>
    /// 修改发布内容
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [Permission(EPermission.PublishedModify)]
    [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)
            .Where(d => d.Roles.Any(x => roles.Contains(x.Name)))
            .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);
    }

    #endregion

    #region 工单回访

    /// <summary>
    /// 回访列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("visit")]
    public async Task<PagedDto<OrderVisitDto>> QueryOrderVisitList([FromQuery] QueryOrderVisitDto dto)
    {
        var (total, items) = await _orderVisitRepository.Queryable()
            .Includes(x => x.Order)
            .Includes(x => x.Employee)
            .Includes(x => x.OrderVisitDetails)
            .WhereIF(dto.VisitState == EVisitStateQuery.NoVisit,
                x => (x.VisitState == EVisitState.WaitForVisit ||
                      x.VisitState == EVisitState.NoSatisfiedWaitForVisit) &&
                     x.Order.IsProvince == false)
            .WhereIF(dto.VisitState == EVisitStateQuery.Visited, x => x.VisitState == EVisitState.Visited)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Order.Title.StartsWith(dto.Keyword!))
            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No)
            .WhereIF(dto.VisitType != null, x => x.VisitType == dto.VisitType)
            .WhereIF(dto.FiledType != null && dto.FiledType == FiledType.CenterFiled, d => d.Order.ProcessType == EProcessType.Zhiban)
            .WhereIF(dto.FiledType != null && dto.FiledType == FiledType.OrgFiled, d => d.Order.ProcessType == EProcessType.Jiaoban)
            .WhereIF(dto.IsCountersign != null && dto.IsCountersign == true, d => d.Order.CounterSignType != null)
            .WhereIF(dto.IsCountersign != null && dto.IsCountersign == false, d => d.Order.CounterSignType == null)
            .WhereIF(dto.QuerySelf.HasValue && dto.QuerySelf.Value, d => d.EmployeeId == _sessionContext.RequiredUserId)
            .OrderByDescending(x => x.PublishTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderVisitDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDto>>(items));
    }

    /// <summary>
    /// 回访查询基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("visit/basedata")]
    public async Task<object> VisitBaseData()
    {
        var rsp = new
        {
            VisitType = EnumExts.GetDescriptions<EVisitType>(),
        };
        return rsp;
    }

    /// <summary>
    /// 回访详情
    /// </summary>
    /// <returns></returns>
    [HttpGet("visit/{id}")]
    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>();
        var visitSatisfaction = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction).Where(x => x.DicDataValue != "-1");
        var dissatisfiedReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.DissatisfiedReason);
        var visitManner = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitManner).Where(x => x.DicDataValue != "-1");
        //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 = "";
        if (callRecord != null)
        {
            recordingFileUrl = callRecord.RecordingFileUrl;
            recordingBaseAddress = callRecord.RecordingBaseAddress;
            recordingAbsolutePath = callRecord.RecordingAbsolutePath;
        }

        return 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,
        };
    }

    /// <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>
    [Permission(EPermission.Visit)]
    [HttpPost("visit")]
    [LogFilter("工单回访")]
    public async Task Visit([FromBody] VisitDto dto)
    {
        //var visit = await _orderVisitRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        var visit = await _orderVisitRepository.Queryable()
            .Includes(d => d.Order)
            .Includes(d => d.OrderVisitDetails)
            .FirstAsync(d => d.Id == dto.Id, HttpContext.RequestAborted);
        if (visit is null)
            throw UserFriendlyException.SameMessage("未知回访信息");

        if (visit.VisitState == EVisitState.Visited)
            throw UserFriendlyException.SameMessage("已回访，不能重复回访");

        var first = dto.VisitDetails.FirstOrDefault(x => x.VisitTarget == EVisitTarget.Org);

        visit.IsPutThrough = dto.IsPutThrough;
        visit.AgainState = dto.IsAgain ? EAgainState.NeedAgain : EAgainState.NoAgain;
        visit.EmployeeId = _sessionContext.UserId;
        visit.CallId = dto.CallId;
        if (first != null)
        {
            visit.NowEvaluate = first.OrgProcessingResults;
        }

        //update order
        //if (dto.IsPutThrough)
        //{
        visit.VisitState = Share.Enums.Order.EVisitState.Visited;
        visit.VisitTime = DateTime.Now;
        if (!string.IsNullOrEmpty(visit.CallId))
        {
            visit.VisitType = EVisitType.CallVisit;
        }
        if (visit.VisitType is null)
        {
            visit.VisitType = EVisitType.ArtificialVisit;
        }
        if (first != null)
        {
            visit.Order.Visited(first.OrgProcessingResults.Key, first.OrgProcessingResults.Value);
        }
        visit.OrgJudge = dto.OrgJudge;
        visit.SeatJudge = dto.SeatJudge;

        if (visit.OrgJudge == true || visit.SeatJudge == true)
        {
            visit.JudgeState = EJudgeState.Judging;
        }
        //_mapper.Map(dto.VisitDetails,visit.OrderVisitDetails);
        for (int i = 0; i < visit.OrderVisitDetails.Count; i++)
        {
            var detail = visit.OrderVisitDetails[i];
            var detaildto = dto.VisitDetails.FirstOrDefault(x => x.Id == detail.Id);
            if (detaildto != null)
            {
                if (visit.Order.SourceChannelCode != "RGDH" && detaildto.VisitTarget == EVisitTarget.Seat)
                {
                    detaildto.SeatEvaluate = ESeatEvaluate.DefaultSatisfied;
                }
                _mapper.Map(detaildto, visit.OrderVisitDetails[i]);
            }
        }

        await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted);
        await _orderVisitedDetailRepository.UpdateRangeAsync(visit.OrderVisitDetails, HttpContext.RequestAborted);
        await _orderRepository.UpdateAsync(visit.Order, HttpContext.RequestAborted);
        var orderDto = _mapper.Map<OrderDto>(visit.Order);
        if (first != null)
        {
            //推省上
            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisited,
                    new PublishVisitDto()
                    {
                        Order = orderDto,
                        No = visit.No,
                        VisitType = visit.VisitType,
                        VisitName = visit.CreatorName,
                        VisitTime = visit.VisitTime,
                        VisitRemark = string.IsNullOrEmpty(first.VisitContent) ? first.OrgProcessingResults?.Value : first.VisitContent,
                        AreaCode = visit.Order.AreaCode!,
                        SubjectResultSatifyCode = first.OrgProcessingResults.Key,
                        FirstSatisfactionCode = visit.Order.FirstVisitResultCode!,
                        ClientGuid = ""
                    }, cancellationToken: HttpContext.RequestAborted);

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

        if (first != null)
        {
            //写入质检
            await _qualityApplication.AddQualityAsync(EQualitySource.Visit, visit.Order.Id, visit.Id,
                HttpContext.RequestAborted);
        }
        //}
        //else
        //{
        //    await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted);
        //}
    }

    /// <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 _orderVisitRepository.Queryable()
            .Includes(x => x.Order)
            .Includes(x => x.Employee)
            .Where(x => x.VisitState == EVisitState.Visited)
            .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No == dto.No)
            .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Order.Title.Contains(dto.Title))
            .WhereIF(!string.IsNullOrEmpty(dto.VisitUserName), x => x.Employee.Name.Contains(dto.VisitUserName))
            .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.Order.AcceptTypeCode)) //受理类型
            .WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.Order.HotspotId)) //热点类型
            .WhereIF(dto.OrgCodes.Any(), d => dto.OrgCodes.Contains(d.Order.ActualHandleOrgCode)) //接办部门
            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.Order.AcceptorName.Contains(dto.NameOrNo!) || d.Order.AcceptorStaffNo.Contains(dto.NameOrNo!)) //受理人/坐席
             .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
            .WhereIF(dto.ActualHandleTimeStart.HasValue, d => d.Order.ActualHandleTime >= dto.ActualHandleTimeStart) //办结时间开始
            .WhereIF(dto.ActualHandleTimeEnd.HasValue, d => d.Order.ActualHandleTime <= dto.ActualHandleTimeEnd) //办结时间结束
            .WhereIF(dto.VisitTimeStart.HasValue, d => d.VisitTime >= dto.VisitTimeStart) //回访开始时间
            .WhereIF(dto.VisitTimeEnd.HasValue, d => d.VisitTime <= dto.VisitTimeEnd)
            .WhereIF(dto.IsIng == true, d => d.JudgeState == EJudgeState.Judging)
            .WhereIF(dto.IsIng == false, d => d.JudgeState != EJudgeState.Judging)
            .WhereIF(dto.JudgeState != null, d => d.JudgeState == dto.JudgeState)
            .WhereIF(dto.OrgJudge != null, d => d.OrgJudge == dto.OrgJudge)
            .WhereIF(dto.SeatJudge != null, d => d.SeatJudge == dto.SeatJudge)
            .OrderByDescending(x => x.VisitTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderVisitDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDto>>(items));
    }

    /// <summary>
    /// 扭转满意度
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("visit/judge")]
    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")]
    public async Task VisitMigrationBatch([FromBody] DistributionVisitDto dto)
    {
        var visits = await _orderVisitRepository.Queryable()
            .Where(d => d.VisitState == EVisitState.WaitForVisit && dto.Ids.Contains(d.Id))
            .ToListAsync(HttpContext.RequestAborted);

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

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

    #endregion

    #region 二次回访申请

    /// <summary>
    /// 可二次回访申请列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [Permission(EPermission.OrderVisitAgainList)]
    [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>
    [Permission(EPermission.ApplyOrderVisit)]
    [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>
    [Permission(EPermission.ExaminOrderVisit)]
    [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);
        //TODO 处理通过后的业务
        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>
    [Permission(EPermission.VisitApplyList)]
    [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>
    //[Permission(EPermission.ApplyDelay)]
    [HttpPost("delay")]
    [LogFilter("新增工单延期申请")]
    public async Task ApplyDelay([FromBody] DelayStartFlowDto 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("该存在延期申请正在审核");
        //验证延期次数
        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.DelayNum);
        if (int.Parse(setting?.SettingValue[0]) != 0)
        {
            int count = await _orderDelayRepository.CountAsync(x => x.OrderId == delaydto.OrderId && x.ApplyOrgCode == _sessionContext.RequiredOrgId && x.DelayState == EDelayState.Pass);
            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)
        {
            model.AfterDelay = _timeLimitDomainService
                .CalcEndTime(model.BeforeDelay.Value, 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;
            string workFlowId = await _workflowApplication.StartWorkflowAsync(startDto, _sessionContext, model.Id,
                    cancellationToken: HttpContext.RequestAborted);
            //model.WorkflowId = workFlowId;
            //await _orderDelayRepository.UpdateAsync(model, HttpContext.RequestAborted);
        }
        catch (Exception ex)
        {
            await _orderDelayRepository.RemoveAsync(model.Id, false, HttpContext.RequestAborted);
            throw new UserFriendlyException($"工单延期流程失败!, {ex.Message}", "工单延期流程失败");
        }
    }


    /// <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);
        await _orderDelayRepository.UpdateAsync(delay, HttpContext.RequestAborted);
        try
        {
            dto.NextWorkflow.WorkflowId = delay.WorkflowId;
            await _workflowApplication.NextAsync(dto.NextWorkflow, _sessionContext,
                cancellationToken: HttpContext.RequestAborted);
        }
        catch (Exception e)
        {
            throw new UserFriendlyException($"工单延期下一步流程失败!, {e.Message}", "工单延期下一步流程失败");
        }
    }

    /// <summary>
    ///  延期查询流程办理下一步可选节点
    /// </summary>
    /// <param name="workflowId"></param>
    /// <returns></returns>
    [HttpGet("delay/{workflowId}/nextsteps")]
    public async Task<NextStepsDto> OrderDelayNextsteps(string workflowId)
    {
        var workflow = await _workflowRepository.GetAsync(workflowId, HttpContext.RequestAborted);
        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 == "省审批"));
                    }
                }
                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>
    //[Permission(EPermission.DelayList)]
    [HttpGet("delay")]
    public async Task<PagedDto<OrderDelayDto>> DelayList([FromQuery] DelayListDto dto)
    {
        var (total, items) = await _orderDelayRepository.Queryable(canView: true)
            .Includes(d => d.Order)
            .Includes(d => d.Workflow)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
            .WhereIF(dto.IsApply == true, d => d.DelayState != EDelayState.Examining)
            .WhereIF(dto.IsApply == false, d => d.DelayState == EDelayState.Examining)
            .WhereIF(dto.DelayState != null, d => d.DelayState == dto.DelayState)
            .OrderByDescending(d => d.ApplyDelayTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

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

    /// <summary>
    /// 延期列表
    /// </summary>
    /// <returns></returns>
    //[Permission(EPermission.DelayList)]
    [HttpGet("wait_delay")]
    public async Task<PagedDto<OrderDelayDto>> WaitDelayList([FromQuery] DelayListDto dto)
    {
        var isHandled = dto.IsApply.HasValue && dto.IsApply.Value;
        var (total, items) = await _orderDelayRepository
            .Queryable(hasHandled: !isHandled)
            .Includes(d => d.Order)
            .Includes(d => d.Workflow)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                d => d.Order.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
            //.WhereIF(dto.IsApply == true, d => d.DelayState != EDelayState.Examining)
            .WhereIF(dto.IsApply == false, d => d.DelayState == EDelayState.Examining)
            //.WhereIF(dto.DelayState != null, x => x.DelayState == dto.DelayState)
            //.Where(x=>x.DelayState == EDelayState.Examining)
            .OrderByDescending(d => d.ApplyDelayTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

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

    /// <summary>
    /// 延期详情
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    //[Permission(EPermission.DelayEntity)]
    [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)
    {
        return _timeLimitDomainService.CalcEndTime(dto.BeginTime, dto.DelayUnit, dto.DelayNum, 0);
    }

    /// <summary>
    /// 查询工单延期流程开启参数
    /// </summary>
    /// <returns></returns>
    [HttpGet("delay/startflow")]
    public async Task<NextStepsDto> GetDelayFlowStartOptions()
    {
        return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.OrderDelay,
            HttpContext.RequestAborted);
    }

    /// <summary>
    /// 延期页面基础信息
    /// </summary>
    /// <returns></returns>
    [HttpGet("delay/basedata")]
    public async Task<object> DelayBaseData()
    {
        var rsp = new
        {
            DelayState = EnumExts.GetDescriptions<EDelayState>(),
            TimeType = EnumExts.GetDescriptions<ETimeType>()
        };
        return rsp;
    }

    #endregion

    #region 工单甄别

    /// <summary>
    /// 工单甄别待申请列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [Permission(EPermission.CanOrderScreen)]
    [HttpGet("mayscreen")]
    public async Task<PagedDto<OrderVisitDetailDto>> MayScreenList([FromQuery] MayScreenListDto dto)
    {
        dto.CreationTimeEnd = DateTime.Now;
        dto.CreationTimeStart = DateTime.Now;
        if (dto.IsHomePage != null && dto.IsHomePage == true)
        {
            dto.CreationTimeStart = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5);
        }

        var query = _orderVisitedDetailRepository.Queryable(false, true)
            .Includes(x => x.OrderVisit)
            .Includes(x => x.OrderVisit, y => y.Order)
            .Includes(x => x.OrderVisit, y => y.Employee)
            .LeftJoin<OrderScreen>((x, s) => x.Id == s.VisitDetailId && (int)s.Status < 2 && s.IsDeleted == false)
            .Where((x, s) => s.Id == null)
            .WhereIF(dto.IsHomePage.HasValue && dto.IsHomePage == true, x => x.OrderVisit.VisitTime < dto.CreationTimeEnd && x.OrderVisit.VisitTime > dto.CreationTimeStart)
            .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.OrderVisit.Order!.No!.Contains(dto.No!))
            .WhereIF(dto.IsProvince.HasValue, x => x.OrderVisit.Order!.IsProvince == dto.IsProvince)
            .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.OrderVisit.Order!.Title!.Contains(dto.Title!))
            .WhereIF(!string.IsNullOrEmpty(dto.SourceChannel), x => x.OrderVisit.Order!.SourceChannelCode! == dto.SourceChannel!)
            .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), x => x.OrderVisit.Order!.AcceptTypeCode! == dto.AcceptType!)
            .WhereIF(dto.CounterSignType.HasValue, x => x.OrderVisit.Order!.CounterSignType == dto.CounterSignType)
            .WhereIF(!string.IsNullOrEmpty(dto.OrgLevelOneName), x => x.OrderVisit.Order!.OrgLevelOneName!.Contains(dto.OrgLevelOneName!))
            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), x => x.OrderVisit.Order!.ActualHandleOrgName!.Contains(dto.ActualHandleOrgName!))
            .WhereIF(dto.ActualHandleTime.HasValue && dto.EndActualHandleTime.HasValue, x => x.OrderVisit.Order!.ActualHandleTime >= dto.ActualHandleTime && x.OrderVisit.Order!.ActualHandleTime <= dto.EndActualHandleTime)
            .WhereIF(dto.FiledTime.HasValue && dto.EndFiledTime.HasValue, x => x.OrderVisit.Order!.FiledTime == dto.FiledTime && x.OrderVisit.Order!.FiledTime <= dto.EndFiledTime)
            .WhereIF(dto.CreationTime.HasValue && dto.EndCreationTime.HasValue, x => x.OrderVisit.Order!.CreationTime == dto.CreationTime && x.OrderVisit.Order!.CreationTime <= dto.EndCreationTime)
            .WhereIF(dto.VisitTime.HasValue && dto.EndVisitTime.HasValue, x => x.OrderVisit.VisitTime == dto.VisitTime && x.OrderVisit.VisitTime <= dto.EndVisitTime)
            .WhereIF(!string.IsNullOrEmpty(dto.VisitOrgName), x => x.VisitOrgName!.Contains(dto.VisitOrgName!))
            .WhereIF(!string.IsNullOrEmpty(dto.OrgProcessingResults), x => SqlFunc.JsonField(x.OrgProcessingResults, "Key") == dto.OrgProcessingResults)
            .WhereIF(!string.IsNullOrEmpty(dto.OrgHandledAttitude), x => SqlFunc.JsonListObjectAny(x.OrgHandledAttitude, "Key", dto.OrgHandledAttitude))
            .WhereIF(!string.IsNullOrEmpty(dto.OrgNoSatisfiedReason), x => SqlFunc.JsonField(x.OrgNoSatisfiedReason, "Key") == dto.OrgNoSatisfiedReason)
            .Where((x, s) => x.OrderVisit.VisitState != EVisitState.None && x.OrderVisit.IsCanHandle);
        if (_sessionContext.OrgId != null && !_sessionContext.OrgIsCenter)
        {
            query.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                    (x, s) => x.OrderVisit.Order.Title.Contains(dto.Keyword!) ||
                              x.OrderVisit.Order.No.Contains(dto.Keyword!))
                .Where((x, s) => x.VisitTarget == EVisitTarget.Org && x.VisitOrgCode == _sessionContext.OrgId && (
                    SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "1" ||
                    SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "2" ||
                    SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "1" ||
                    SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "2"
                ));
        }
        else
        {
            query.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                    (x, s) => x.OrderVisit.Order.Title.Contains(dto.Keyword!) ||
                              x.OrderVisit.Order.No.Contains(dto.Keyword!))
                .Where((x, s) => x.VisitTarget == EVisitTarget.Org && (
                    SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "1" ||
                    SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "2" ||
                    SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "1" ||
                    SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "2"
                ));
        }

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


    /// <summary>
    /// 工单甄别列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("screen")]
    public async Task<PagedDto<OrderScreenListDto>> ScreenList([FromQuery] ScreenListDto dto)
    {
        var view = dto.source == 1;
        var handler = dto.source == 1 && dto.Status is EScreenStatus.Apply;

        var query = _orderScreenRepository.Queryable(canView: view, hasHandled: handler)
            .Includes(d => d.Order)
            .Includes(d => d.VisitDetail)
            .Includes(d => d.Visit, v => v.Order)
            .Includes(d => d.Workflow)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                d => d.Visit.Order.Title.Contains(dto.Keyword!) || d.Visit.Order.No.Contains(dto.Keyword!));
        if (dto.Status is EScreenStatus.Apply)
        {
            query.Where(d => (d.Status == EScreenStatus.Apply || d.Status == EScreenStatus.Approval));
        }
        if (dto.Status.HasValue && dto.Status == EScreenStatus.MyHandle)
        {
            query.Where(d => (d.Status != EScreenStatus.Apply));
        }
        var (total, items) = await query
            //.WhereIF(dto.Status.HasValue && dto.Status == EScreenStatus.MyHandle,
            //    x => x.Status != EScreenStatus.Apply && x.CreatorId == _sessionContext.UserId)
            .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart)
            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd)
            .WhereIF(!string.IsNullOrEmpty(dto.OrderId), d => d.OrderId == dto.OrderId)
            .OrderByDescending(d => d.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderScreenListDto>(total, _mapper.Map<IReadOnlyList<OrderScreenListDto>>(items));
    }


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

        var isNoPass = await _orderScreenRepository.AnyAsync(x => x.Status == EScreenStatus.Refuse && 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.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);
        var endTime = _timeLimitDomainService
            .CalcEndTime(visit.VisitTime.Value, ETimeType.WorkDay, int.Parse(setting?.SettingValue[0]), 0).EndTime;
        if (DateTime.Now > endTime && int.Parse(setting?.SettingValue[0]) > 0)
            throw UserFriendlyException.SameMessage("甄别申请时限已超过系统预定设置，不能申请");

        var model = _mapper.Map<OrderScreen>(dto.Data);
        model.Status = EScreenStatus.Apply;
        model.ApplyEndTime = endTime;
        model.TimeConsuming = _timeLimitDomainService.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);
        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;
            workflowId = await _workflowApplication.StartWorkflowAsync(startDto, _sessionContext, model.Id,
                    cancellationToken: HttpContext.RequestAborted);
            //var screen = await _orderScreenRepository.GetAsync(model.Id, HttpContext.RequestAborted);
            //if (screen != null)
            //{
            //    screen.WorkflowId = workflowId;
            //    await _orderScreenRepository.UpdateAsync(screen, 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);
        _mapper.Map(dto.Data, screen);
        if (dto.Data.Files.Any())
            screen.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, screen.Id, "", HttpContext.RequestAborted);
        await _orderScreenRepository.UpdateAsync(screen, HttpContext.RequestAborted);
        try
        {
            dto.NextWorkflow.WorkflowId = screen.WorkflowId;
            await _workflowApplication.NextAsync(dto.NextWorkflow, _sessionContext,
                    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);

        return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.OrderScreen,
            HttpContext.RequestAborted);
    }

    /// <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 _workflowRepository.GetAsync(workflowId, HttpContext.RequestAborted);
        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 == "省审批"));
                    }
                }
                return result;
            }
        }
        return null;
    }

    /// <summary>
    /// 列表页面基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("screen/base")]
    public async Task<object> ScreenBaseData()
    {
        var rsp = new
        {
            ScreenStatus = EnumExts.GetDescriptions<EScreenStatus>(),
            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),
        };
        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.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;
        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;
    }

    #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),
                d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
            .WhereIF(dto.SuperviseState > -1, x => x.State == dto.SuperviseState)
            .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart)
            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd)
            .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="dto"></param>
    /// <returns></returns>
    [Permission(EPermission.ApplySupervise)]
    [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
                {
                    //查询部门所有账号
                    var userlist = await _userRepository.Queryable().Where(x => x.OrgId == model.OrgId && !string.IsNullOrEmpty(x.PhoneNo) && x.Roles.Any(d => d.Id == "08dae71e-0eca-4bc4-89fe-7eaefae8a98e")).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.PhoneNo,
                            TemplateCode = "1003",
                            Params = new List<string>() { order.No },
                            TelNumber = user.PhoneNo,

                        };
                        await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
                    }

                }
                catch { }
            }

            //推省上
            if (!string.IsNullOrEmpty(model.Id) && ("001171".Equals(model.OrgId) || "001178".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("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),
                d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
            .WhereIF(dto.UrgeState > -1, x => x.State == dto.UrgeState)
            .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart)
            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd)
            .Where(x => x.OrgId == _sessionContext.OrgId)
            .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>
    [Permission(EPermission.ApplyUrge)]
    [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("无效工单");

        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);
            await _orderUrgeRepository.AddAsync(model, HttpContext.RequestAborted);
            if (dto.AcceptSms)
            {
                try
                {
                    //查询部门所有账号
                    var userlist = await _userRepository.Queryable().Where(x => x.OrgId == model.OrgId && !string.IsNullOrEmpty(x.PhoneNo) && x.Roles.Any(d => d.Id == "08dae71e-0eca-4bc4-89fe-7eaefae8a98e")).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.PhoneNo,
                            TemplateCode = "1002",
                            Params = new List<string>() { order.No },
                            TelNumber = user.PhoneNo,
                        };
                        await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
                    }
                }
                catch { }
            }

            //推省上
            if (!string.IsNullOrEmpty(model.Id) && ("001171".Equals(model.OrgId) || "001178".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);
        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;
    }

    #endregion

    #region 工单办理

    /// <summary>
    /// 工单列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet]
    public async Task<PagedDto<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));
    }

    [HttpPost("order/export")]
    public async Task<FileStreamResult> ExportOrders([FromBody] ExportExcelDto<QueryOrderDto> dto)
    {
        var query = _orderApplication.QueryOrders(dto.QueryDto);
        List<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 orderDtos = _mapper.Map<ICollection<OrderDto>>(orders);

        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(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<OrderDto>> Query([FromQuery] QueryOrderHistoryDto dto)
    {
        var (total, items) = await _orderRepository.Queryable()
            .Where(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);
        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.OrderScreens)
            .Includes(d => d.OrderVisits, x => x.OrderVisitDetails)
            .Includes(d => d.OrderVisits, x => x.Employee)
            .FirstAsync(d => d.Id == id);
        if (order == null)
            return new();

        var dto = _mapper.Map<OrderDto>(order);

        if (!string.IsNullOrEmpty(order.WorkflowId))
        {
            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;

            await _mediator.Publish(new GetOrderDetailNotify(result.Workflow,
                _sessionContext.RequiredUserId, _sessionContext.UserName,
                _sessionContext.RequiredOrgId, _sessionContext.OrgName,
                _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName));
        }

        //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.IsCanCancelDelay = order.OrderDelays.Any(x => x.DelayState == EDelayState.Examining && x.ApplyOrgCode == _sessionContext.RequiredOrgId);

        var delayModel = order.OrderDelays.MaxBy(x => x.AfterDelay);
        if (delayModel != null)
        {
            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.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;
        }

        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;
        return dto;
    }

    /// <summary>
    /// 新增工单
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [Permission(EPermission.OrderAdd)]
    [HttpPost]
    [LogFilter("新增工单")]
    public async Task<string> Add([FromBody] AddOrderDto dto)
    {
        dto.InitAddress();
        //todo dto validation
        //交通工单校验
        var valid = await _orderDomainService.OrderValidation(dto, HttpContext.RequestAborted);
        if (valid.Validation)
            throw UserFriendlyException.SameMessage(valid.Result);

        if (!string.IsNullOrEmpty(dto.CallId))
        {
            var exists = await _orderRepository.AnyAsync(d => d.CallId == dto.CallId, HttpContext.RequestAborted);
            if (exists)
                throw UserFriendlyException.SameMessage("来电已保存工单");
        }

        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);
        await _orderDomainService.AddAsync(order, true, 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);
        }

        //内容分词
        await _orderApplication.OrderParticiple(dto.Content, order.Id, HttpContext.RequestAborted);
        //敏感分词
        await _orderApplication.OrderSensitiveParticiple(dto.Content, order.Id, 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);
        }
        // 副本工单
        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 order.Id;
    }

    /// <summary>
    /// 提供ds调用
    /// </summary>
    [HttpPost("add-anonymous")]
    [AllowAnonymous]
    public async Task<AddOrderResponse> AddAnonymous([FromBody] AddOrderDto dto)
    {
        return await _orderApplication.ReceiveOrderFromExternalAsync(dto, _sessionContext, 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>
    [Permission(EPermission.OrderUpdate)]
    [HttpPut]
    [LogFilter("更新工单")]
    public async Task Update([FromBody] UpdateOrderDto dto)
    {
        dto.InitAddress();
        //交通工单校验
        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 (order.Status > EOrderStatus.SpecialToUnAccept)
            throw UserFriendlyException.SameMessage("工单已发起流程，不可编辑");

        if (order.Content != dto.Content)
            await _orderApplication.OrderParticiple(dto.Content, dto.Id, 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);
            }
        }

        _mapper.Map(dto, order);
        if (dto.Files.Any())
            order.FileJson = await _fileRepository.AddFileAsync(dto.Files, order.Id, "", HttpContext.RequestAborted);
        await _orderRepository.UpdateNav(order).Include(d => d.OrderExtension).ExecuteCommandAsync();
        //敏感分词
        await _orderApplication.OrderSensitiveParticiple(dto.Content, order.Id, 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.InitId();
        await _orderCopyRepository.AddAsync(copy, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 开始工单办理流程
    /// </summary>
    [HttpPost("startflow")]
    public async Task StartFlow([FromBody] OrderStartFlowDto dto)
    {
        ExpiredTimeWithConfig expiredTimeConfig;
        if (dto.Workflow.NextHandlers.Any(d => d.Key == "001171" || d.Key == "001178"))
        {
            var timeResult = _timeLimitDomainService.CalcEndTime(DateTime.Now, ETimeType.WorkDay, 45, 80);
            expiredTimeConfig = new ExpiredTimeWithConfig
            {
                Count = 45,
                TimeType = ETimeType.WorkDay,
                TimeText = "45个工作日",
                ExpiredTime = timeResult.EndTime,
                NearlyExpiredTime = timeResult.NearlyExpiredTime
            };
        }
        //else if (dto.Workflow.FlowDirection == EFlowDirection.CenterToCenter)
        //{
        // var timeResult = _timeLimitDomainService.CalcEndTime(DateTime.Now, ETimeType.WorkDay, 1, 0);
        // expiredTimeConfig = new ExpiredTimeWithConfig
        // {
        //  Count = 1,
        //  TimeType = ETimeType.WorkDay,
        //  TimeText = "1个工作日",
        //  ExpiredTime = timeResult.EndTime,
        //  NearlyExpiredTime = timeResult.NearlyExpiredTime
        // };
        //}
        else
        {
            //期满时间
            expiredTimeConfig = _timeLimitDomainService.CalcExpiredTime(DateTime.Now, EFlowDirection.CenterToOrg, dto.Data.AcceptTypeCode);
        }
        _mapper.Map(expiredTimeConfig, dto.Data);

        var id = dto.Data.Id;
        var isAdd = string.IsNullOrEmpty(dto.Data.Id);
        if (isAdd)
        {
            id = await Add(dto.Data);
        }
        else
        {
            await Update(dto.Data);
        }

        try
        {
            // 平均派单
            var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
            if (dto.Workflow.BusinessType == EBusinessType.Send && averageSendOrder)
            {
                var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
                dto.Workflow.NextHandlers = new List<FlowStepHandler> { handler };
            }
            //是否市州互转
            if (dto.Data.Transpond.HasValue && dto.Data.Transpond.Value)
            {
                var order = await _orderRepository.GetAsync(id, HttpContext.RequestAborted);
                var orderDto = _mapper.Map<OrderDto>(order);
                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderTranspondCity, orderDto);
                //保存本地数据
                TranspondCityRawData cityRawData = new TranspondCityRawData
                {
                    OrderCode = order.No,
                    TransferOutTime = DateTime.Now,
                    CityName = order.TranspondCityName,
                    Direction = ETranspondDirection.Out
                };

                await _transpondCityRawDataRepository.AddAsync(cityRawData, HttpContext.RequestAborted);

            }

            var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
            startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderHandle;
            startDto.Title = dto.Data.Title;
            await _workflowApplication.StartWorkflowAsync(startDto, _sessionContext, id, dto.Data.ExpiredTime, HttpContext.RequestAborted);
        }
        catch (Exception e)
        {
            if (isAdd)
                await Remove(id);
            throw new UserFriendlyException($"工单开启流程失败!, {e.Message}, {e.StackTrace}", "工单开启流程失败");
        }
    }

    /// <summary>
    /// 查询工单办理流程开启参数
    /// </summary>
    /// <returns></returns>
    [HttpGet("startflow")]
    public async Task<NextStepsDto> GetFlowStartOptions()
    {
        return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.OrderHandle,
            HttpContext.RequestAborted);
    }

    /// <summary>
    /// 工单办理
    /// </summary>
    [HttpPost("handle")]
    public async Task Handle([FromBody] NextWorkflowDto dto)
    {
        var order = await _orderRepository.Queryable()
            .FirstAsync(d => d.WorkflowId == dto.WorkflowId, HttpContext.RequestAborted);
        if (order is null)
            throw new UserFriendlyException("无效工单编号");
        //if (await _orderDelayRepository.AnyAsync(x => x.OrderId == order.Id && x.DelayState == EDelayState.Examining, HttpContext.RequestAborted))
        //{
        //    throw UserFriendlyException.SameMessage("该工单存在正在审核中的延期，不能办理");
        //}
        if (await _orderSendBackAuditRepository.AnyAsync(x => x.OrderId == order.Id && x.State == ESendBackAuditState.Apply, HttpContext.RequestAborted))
        {
            throw UserFriendlyException.SameMessage("该工单存在正在审核中的退回，不能办理");
        }

        ExpiredTimeWithConfig? expiredTimeConfig = null;
        if (dto.NextHandlers.Any(d => d.Key == "001171" || d.Key == "001178"))
        {
            var timeResult = _timeLimitDomainService.CalcEndTime(DateTime.Now, ETimeType.WorkDay, 45, 80);
            expiredTimeConfig = new ExpiredTimeWithConfig
            {
                Count = 45,
                TimeType = ETimeType.WorkDay,
                TimeText = "45个工作日",
                ExpiredTime = timeResult.EndTime,
                NearlyExpiredTime = timeResult.NearlyExpiredTime
            };
            var canUpdateOrderSender = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.CanUpdateOrderSender).SettingValue[0]);
            order.CenterToOrg(
                expiredTimeConfig.TimeText, expiredTimeConfig.Count,
                expiredTimeConfig.TimeType, expiredTimeConfig.ExpiredTime,
                expiredTimeConfig.NearlyExpiredTime, dto.Opinion,
                _sessionContext.RequiredUserId, _sessionContext.UserName,
                canUpdateOrderSender);
        }
        else if (dto.FlowDirection is EFlowDirection.CenterToOrg)
        {
            expiredTimeConfig = _timeLimitDomainService.CalcExpiredTime(DateTime.Now, EFlowDirection.CenterToOrg, order.AcceptTypeCode);
            var canUpdateOrderSender = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.CanUpdateOrderSender).SettingValue[0]);
            order.CenterToOrg(
                expiredTimeConfig.TimeText, expiredTimeConfig.Count,
                expiredTimeConfig.TimeType, expiredTimeConfig.ExpiredTime,
                expiredTimeConfig.NearlyExpiredTime, dto.Opinion,
                _sessionContext.RequiredUserId, _sessionContext.UserName,
                canUpdateOrderSender);
            //写入质检
            await _qualityApplication.AddQualityAsync(EQualitySource.Send, order.Id, HttpContext.RequestAborted);
        }
        else if (dto.FlowDirection is EFlowDirection.CenterToCenter)
        {
            expiredTimeConfig = _timeLimitDomainService.CalcExpiredTime(DateTime.Now, EFlowDirection.CenterToCenter, order.AcceptTypeCode);
            order.CenterToCenter(expiredTimeConfig.TimeText, expiredTimeConfig.Count,
                expiredTimeConfig.TimeType, expiredTimeConfig.ExpiredTime, expiredTimeConfig.NearlyExpiredTime);
        }

        _mapper.Map(expiredTimeConfig, order);
        await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
        var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
        // 平均派单
        if (dto.BusinessType == EBusinessType.Send && averageSendOrder)
        {
            var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
            dto.NextHandlers = new List<FlowStepHandler> { handler };
        }

        await _workflowApplication.NextAsync(dto, _sessionContext, order.ExpiredTime, 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;
        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)
    {
        var workflow = await _workflowDomainService.TerminalCountersignAsync(dto.CountersignId, HttpContext.RequestAborted);
        var order = await _orderRepository.GetAsync(d => d.WorkflowId == workflow.Id, HttpContext.RequestAborted);
        if (order is null)
            throw new UserFriendlyException($"工单未开启流程, workflowId: {workflow.Id}");
        _mapper.Map(workflow, order);
        await _orderRepository.UpdateAsync(order, 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.OrgToCenter => _timeLimitDomainService.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>()
        };
        return rsp;
    }

    /// <summary>
    /// 新增页面基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("base-data-add")]
    public async Task<object> BaseDataAdd()
    {
        var rsp = new
        {
            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),
        };
        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);
    }
    #endregion

    #region 工单待办

    /// <summary>
    /// 查询待办工单
    /// </summary>
    [HttpGet("waited")]
    public async Task<PagedDto<OrderDto>> QueryWaited([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.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.HasValue)
        //    .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 && 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)
        //    .OrderByDescending(d => d.StartTime)
        //    .ToPagedListAsync(dto, HttpContext.RequestAborted);

        if (!isHandled)
        {
            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.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.HasValue)
                .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 && 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)
                .OrderByDescending(d => d.StartTime)
                .ToPagedListAsync(dto, HttpContext.RequestAborted);
            return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
        }
        else
        {
            var (total, items) = await _orderRepository.Queryable()
                .Where(d => SqlFunc.Subqueryable<WorkflowStep>()
                    .Where(step => step.ExternalId == d.Id &&
                                                                 ((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.Status == EWorkflowStepStatus.Handled).Any())
                .Includes(d => d.OrderSpecials)
                .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(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
                .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == false, d => !d.CounterSignType.HasValue)
                .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 && 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)
                .OrderByDescending(d => d.StartTime)

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

    }

    /// <summary>
    /// 查询坐席待办
    /// </summary>
    [HttpGet("waited/sign")]
    public async Task<PagedDto<OrderDto>> QueryWaitedForSeat([FromQuery] QueryOrderWaitedDto dto)
    {
        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
                    : d is EOrderStatus.WaitForAccept or EOrderStatus.BackToUnAccept or EOrderStatus.SpecialToUnAccept)
            .ToArray();
        if (dto.EndTime.HasValue)
            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);

        //var (total, items) = await _orderRepository.Queryable(canView: false)
        //    .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.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.HasValue)
        //    .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 => (string.IsNullOrEmpty(d.WorkflowId) && (string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId)))
        //    .Where(d => string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId)
        //    .Where(x => x.Source < ESource.MLSQ || x.Source > ESource.WZSC)
        //    .Where(x => x.Status != EOrderStatus.BackToProvince && x.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)
        //    .ToPagedListAsync(dto, HttpContext.RequestAborted);

        var (total, items) = 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.HasValue)
            .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);

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


    /// <summary>
    /// 查询中心待办
    /// </summary>
    [HttpGet("waited/center")]
    public async Task<PagedDto<OrderDto>> QueryWaitedForCenter([FromQuery] QueryOrderWaitedCenterDto dto)
    {
        if (dto.EndCreationTime.HasValue)
            dto.EndCreationTime = dto.EndCreationTime.Value.AddDays(1).AddSeconds(-1);
        if (dto.StartTimeEnd.HasValue)
            dto.StartTimeEnd = dto.StartTimeEnd.Value.AddDays(1).AddSeconds(-1);

        var (total, items) = await _orderRepository.Queryable(canView: false)
            .Where(x => x.Workflow.Steps.Any(s => s.Status < EWorkflowStepStatus.Handled && s.HandlerOrgId == OrgSeedData.CenterId))
            .Where(x => x.Source < ESource.MLSQ || x.Source > ESource.WZSC)
            .Where(x => x.Status != EOrderStatus.BackToProvince && x.Status < EOrderStatus.Filed)
            .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No!.Contains(dto.No!))
            .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title!.Contains(dto.Title!))
            .WhereIF(dto is { StCreationTime: not null, EndCreationTime: not null }, x => x.CreationTime >= dto.StCreationTime && x.CreationTime <= dto.EndCreationTime)
            .WhereIF(dto is { StartTimeSt: not null, StartTimeEnd: not null }, x => x.StartTime >= dto.StartTimeSt && x.StartTime <= dto.StartTimeEnd)
            .WhereIF(!string.IsNullOrEmpty(dto.StepName), x => x.Workflow.Steps.Any(s => s.Name == dto.StepName))
            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), x => x.ActualHandleOrgName!.Contains(dto.ActualHandleOrgName!))
            .WhereIF(dto.Status.HasValue, x => x.Status == dto.Status)
            .WhereIF(!string.IsNullOrEmpty(dto.AcceptorName), x => x.AcceptorName!.Contains(dto.AcceptorName!))
            .WhereIF(dto.ExpiredStatus is EExpiredStatus.Normal, x => DateTime.Now < x.NearlyExpiredTime)
            .WhereIF(dto.ExpiredStatus is EExpiredStatus.GoingToExpired, x => DateTime.Now > x.NearlyExpiredTime && DateTime.Now < x.ExpiredTime)
            .WhereIF(dto.ExpiredStatus is EExpiredStatus.Expired, x => DateTime.Now >= x.ExpiredTime)
            .OrderBy(x => x.Status)
            .OrderBy(x => x.CreationTime, 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<object> WaitedForCenterBaseData()
    {
        var rsp = new
        {
            OrderStatus = EnumExts.GetDescriptions<EOrderStatus>(),
            ExpiredStatus = EnumExts.GetDescriptions<EExpiredStatus>(),
            StepNames = new string[] { "话务部", "派单组" }
        };
        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.HasValue)
            .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
                    : d is EOrderStatus.WaitForAccept or EOrderStatus.BackToUnAccept or EOrderStatus.SpecialToUnAccept)
            .ToArray();

        var (total2, items2) = await _orderRepository.Queryable(canView: false)
            .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.No.Contains(dto.Keyword!) || d.Title.Contains(dto.Keyword!))
            .Where(d => string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId)
            .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
            .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == false, d => !d.CounterSignType.HasValue)
            .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(x => x.Source < ESource.MLSQ || x.Source > ESource.WZSC)
            .Where(x => x.Status != EOrderStatus.BackToProvince && x.Status < EOrderStatus.Filed)
            .OrderBy(d => d.Status)
            .OrderByIF(dto.IsHandled == true, d => d.StartTime, OrderByType.Asc)
            .OrderByIF(dto.IsHandled == false, d => d.CreationTime, OrderByType.Desc)
            .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 == workflow.ExternalId);
        if (oneSendBack || twoSendBack)
        {
            var (currentStep, prevStep, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync(
                dto.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles, HttpContext.RequestAborted);
            var sendBack = await _orderSendBackAuditRepository.Queryable().Where(x => x.OrderId == workflow.ExternalId && x.State == ESendBackAuditState.Apply).AnyAsync();
            if (sendBack)
                throw UserFriendlyException.SameMessage("当前工单已经生成退回记录");

            var specialAny = await _orderSpecialRepository.Queryable().Where(x => x.OrderId == dto.OrderId && x.State == 0)
                .AnyAsync();
            if (specialAny) throw UserFriendlyException.SameMessage("工单已存在待审批特提信息！");


            if (order.Workflow.IsInCountersign) throw UserFriendlyException.SameMessage("工单会签中，无法进行退回！");
            if ((oneSendBack && isOrgToCenter) || (twoSendBack && isSecondToFirstOrgLevel))
            {

                var audit = new OrderSendBackAudit
                {
                    OrderId = workflow.ExternalId,
                    State = ESendBackAuditState.Apply,
                    Content = dto.Opinion,
                    SendBackData = dto,
                    ApplyOrgId = currentStep.AcceptorOrgId,
                    ApplyOrgName = currentStep!.AcceptorOrgName,
                    SendBackOrgId = prevStep.HandlerOrgId,//prevStep.AcceptorOrgId,
                    SendBackOrgName = prevStep.HandlerOrgName,//prevStep!.AcceptorOrgName,
                    WorkflowOrgId = _sessionContext.RequiredOrgId,
                    WorkflowUserId = _sessionContext.RequiredUserId,
                    WorkflowRoleIds = _sessionContext.Roles.ToList()
                };
                await _orderSendBackAuditRepository.AddAsync(audit, HttpContext.RequestAborted);
            }
            else
            {
                var flowDirection = await _workflowApplication.PreviousAsync(dto, HttpContext.RequestAborted);
                var processType = flowDirection == EFlowDirection.OrgToCenter || flowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
                await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType })
                    .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                //发送短信TODO
            }
        }
        else
        {
            var flowDirection = await _workflowApplication.PreviousAsync(dto, HttpContext.RequestAborted);
            var processType = flowDirection == EFlowDirection.OrgToCenter || flowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType })
                .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
            //发送短信TODO
        }
    }

    /// <summary>
    /// 工单业务退回审批
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
	[Permission(EPermission.OrderPreviousAudit)]
    [HttpPost("order_previous_audit")]
    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)
        {
            //string applicantId, string applicantOrgId, string[] applicantRoleIds,
            //    ISessionContext current, CancellationToken cancellationToken);
            var flowDirection = await _workflowApplication.PreviousAsync(sendBack.SendBackData, sendBack.WorkflowUserId,
                sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(), _sessionContext, HttpContext.RequestAborted);
            //var flowDirection = await _workflowApplication.PreviousAsync(sendBack.SendBackData, sendBack.WorkflowUserId, HttpContext.RequestAborted);
            var processType = flowDirection == EFlowDirection.OrgToCenter || flowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType })
                .Where(o => o.Id == sendBack.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
            //发送短信TODO

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

    /// <summary>
    /// 工单业务批量退回审批
    /// </summary>
    /// <returns></returns>
	[HttpPost("order_previous_audit_batch")]
    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 flowDirection = await _workflowApplication.PreviousAsync(sendBack.SendBackData,
                    sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(),
                    _sessionContext, HttpContext.RequestAborted);
                //var flowDirection = await _workflowApplication.PreviousAsync(sendBack.SendBackData, sendBack.WorkflowUserId, HttpContext.RequestAborted);
                var processType = flowDirection == EFlowDirection.OrgToCenter || flowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
                await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType })
                    .Where(o => o.Id == sendBack.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
                //发送短信TODO

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

    }

    /// <summary>
    /// 工单业务退回审批列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [Permission(EPermission.OrderPreviousList)]
    [HttpGet("order_previous_list")]
    public async Task<PagedDto<SendBackDto>> AuditList([FromQuery] SendBackListDto dto)
    {
        var query = _orderSendBackAuditRepository.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.AuditState == 1, d => d.State == ESendBackAuditState.Apply)
             .WhereIF(dto.AuditState == 2 && !dto.State.HasValue, d => d.State > ESendBackAuditState.Apply)
             .WhereIF(dto.AuditState == 2 && dto.State.HasValue, d => d.State == dto.State)
             .WhereIF(_sessionContext.Roles.Contains("role_sysadmin") == false, x => x.SendBackOrgId == _sessionContext.OrgId);// 123 系统管理员

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

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

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

    #endregion

    #region 省工单退回

    /// <summary>
    /// 工单退回列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [Permission(EPermission.SendBackOrder)]
    [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.SpecialToUnAccept)
            {
                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>
    [Permission(EPermission.ApplySendBack)]
    [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.SpecialToUnAccept)
            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>
    [Permission(EPermission.AuditSendBack)]
    [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>
    [Permission(EPermission.ApplySpecial)]
    [HttpPost("special")]
    [LogFilter("新增工单特提")]
    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 screen = await _orderScreenRepository.Queryable().Where(x => x.OrderId == dto.OrderId && (int)x.Status < 2).AnyAsync();
        if (screen) throw UserFriendlyException.SameMessage("工单存在甄别中的信息！");

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

        var order = await _orderRepository
            .Queryable()
            .Includes(d => d.Workflow)
            .FirstAsync(d => d.Id == dto.OrderId);
        if (order.Workflow.IsInCountersign) throw UserFriendlyException.SameMessage("工单会签中，无法进行特提！");

        var model = _mapper.Map<OrderSpecial>(dto);
        var orgs = order.HandlerOrgs;
        model.OrgId = orgs != null && orgs.Count > 0 ? orgs[0].Key : "";
        model.OrgName = orgs != null && orgs.Count > 0 ? orgs[0].Value : "";
        var step = await _workflowDomainService.FindLastStepAsync(model.WorkflowId, HttpContext.RequestAborted);
        model.StepName = step.Name;
        model.StepCode = step.Code;

        //if (!dto.Audit) model.State = 1;
        //取消根据进入界面判断是否审批  最新按照系统配置设定
        var audit = true;
        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;
        }
        if (!audit) model.State = 1;

        model.InitId();
        if (dto.Files.Any())
            model.FileJson = await _fileRepository.AddFileAsync(dto.Files, model.Id, "", HttpContext.RequestAborted);
        await _orderSpecialRepository.AddAsync(model, HttpContext.RequestAborted);
        if (model.State == 1)
        {
            var recall = new RecallDto
            {
                WorkflowId = dto.WorkflowId!,
                NextStepCode = dto.NextStepCode,
                NextStepName = dto.NextStepName,
                NextHandlers = dto.NextHandlers,
                Opinion = dto.Cause,
                FlowDirection = dto.FlowDirection,
                HandlerType = dto.HandlerType,
                BusinessType = dto.BusinessType
            };
            // 计算期满时间
            //if (dto.AlterTime)
            //{
            var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
            var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
            //var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now,
            //	ETimeType.WorkDay,
            //	dto.TimeLimit.Value, order.AcceptTypeCode);
            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, ProcessType = processType })
                .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
            var orderDto = _mapper.Map<OrderDto>(order);
            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted);
            //}
            await _workflowApplication.RecallAsync(recall, expiredTime.ExpiredTime, HttpContext.RequestAborted);
            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);
            }

            if (order != null && ("001171".Equals(model.OrgId) ||
                                  "001178".Equals(model.OrgId) ||
                                  "001180".Equals(model.OrgId)))
            {
                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowRecalled,
               new PublishSpecialDto { Order = _mapper.Map<OrderDto>(order), Special = _mapper.Map<OrderSpecialDto>(model) }, cancellationToken: HttpContext.RequestAborted);

                //try
                //{
                //    await _provinceService.RevokeOrder(
                //        new PublishSpecialDto
                //        { Order = _mapper.Map<OrderDto>(order), Special = _mapper.Map<OrderSpecialDto>(model) },
                //        HttpContext.RequestAborted);
                //}
                //catch (Exception e)
                //{
                //    _logger.LogError("_provinceService.RevokeOrder throw exception: {ex}", e.Message);
                //}
            }
        }
    }

    /// <summary>
    /// 工单重办信息
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [Permission(EPermission.ApplySpecial)]
    [HttpPost("re_transact")]
    [LogFilter("工单重办")]
    public async Task Add([FromBody] OrderReTransactDto dto)
    {
        var specialAny = await _orderSpecialRepository.Queryable().Where(x => x.OrderId == dto.OrderId && x.State == 0)
            .AnyAsync();
        if (specialAny) throw UserFriendlyException.SameMessage("工单已存在待审批特提信息！");

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

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

        var order = await _orderRepository
            .Queryable()
            .Includes(d => d.Workflow)
            .FirstAsync(d => d.Id == dto.OrderId);
        if (order.Workflow.IsInCountersign) throw UserFriendlyException.SameMessage("工单会签中，无法进行重办！");

        var model = _mapper.Map<OrderSpecial>(dto);
        var orgs = order.HandlerOrgs;
        model.OrgId = orgs != null && orgs.Count > 0 ? orgs[0].Key : "";
        model.OrgName = orgs != null && orgs.Count > 0 ? orgs[0].Value : "";
        var step = await _workflowDomainService.FindLastStepAsync(model.WorkflowId, HttpContext.RequestAborted);
        model.StepName = step.Name;
        model.StepCode = step.Code;
        model.State = 1;
        model.ESpecialType = ESpecialType.ReTransact;

        model.InitId();
        if (dto.Files.Any())
            model.FileJson = await _fileRepository.AddFileAsync(dto.Files, model.Id, "", HttpContext.RequestAborted);
        await _orderSpecialRepository.AddAsync(model, HttpContext.RequestAborted);
        if (dto.ReTransactError.Any())
        {
            List<OrderSpecialDetail> details = new();
            foreach (var item in dto.ReTransactError)
            {
                var detail = new OrderSpecialDetail();
                _mapper.Map(item, detail);
                detail.SpecialId = model.Id;
                details.Add(detail);
            }
            await _orderSpecialDetailRepository.AddRangeAsync(details, HttpContext.RequestAborted);
        }

        if (model.State == 1)
        {
            var recall = new RecallDto
            {
                WorkflowId = dto.WorkflowId!,
                NextStepCode = dto.NextStepCode,
                NextStepName = dto.NextStepName,
                NextHandlers = dto.NextHandlers,
                Opinion = dto.Cause,
                FlowDirection = dto.FlowDirection,
                HandlerType = dto.HandlerType,
                BusinessType = dto.BusinessType
            };
            DateTime endTime = order.ExpiredTime!.Value;
            // 计算期满时间
            if (dto.AlterTime)
            {
                var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now,
                    ETimeType.WorkDay,
                    dto.TimeLimit.Value, order.AcceptTypeCode);
                endTime = expiredTime.EndTime;
                await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ExpiredTime = expiredTime.EndTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime })
                    .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                var orderDto = _mapper.Map<OrderDto>(order);
                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted);
            }
            var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType })
                .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
            await _workflowApplication.RecallAsync(recall, endTime, HttpContext.RequestAborted);
            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 reTransactNum = order.ReTransactNum.HasValue ? order.ReTransactNum.Value + 1 : 1;
            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ReTransactNum = reTransactNum }).Where(o => o.Id == order.Id).ExecuteCommandAsync(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);
            }
        }
    }

    /// <summary>
    /// 审批工单特提信息
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [Permission(EPermission.AuditSpecial)]
    [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);
        await _orderSpecialRepository.UpdateAsync(special, HttpContext.RequestAborted);
        var order = await _orderRepository.GetAsync(x => x.Id == special.OrderId);
        if (special.State == 1)
        {
            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.AlterTime)
            //    recall.External = new External { TimeLimit = dto.TimeLimit, TimeLimitUnit = dto.TimeLimitUnit };
            //if (dto.Files.Any()) recall.Files = dto.Files;
            // 计算期满时间
            //if (dto.AlterTime)
            //{
            var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
            var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, ProcessType = processType })
                .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
            var orderDto = _mapper.Map<OrderDto>(order);
            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted);
            //}

            //todo 特提重办，按审批通过时间依据中心派至部门的规则计算期满时间，更新order

            await _workflowApplication.RecallAsync(recall, expiredTime.ExpiredTime, HttpContext.RequestAborted);
            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);
            }

            if (order != null && ("001171".Equals(special.OrgId) ||
                                  "001178".Equals(special.OrgId) ||
                                  "001180".Equals(special.OrgId)))
            {
                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowRecalled,
             new PublishSpecialDto { Order = _mapper.Map<OrderDto>(order), Special = _mapper.Map<OrderSpecialDto>(special) }, cancellationToken: HttpContext.RequestAborted);

                //try
                //{
                //    await _provinceService.RevokeOrder(
                //        new PublishSpecialDto
                //        { Order = _mapper.Map<OrderDto>(order), Special = _mapper.Map<OrderSpecialDto>(special) },
                //        HttpContext.RequestAborted);
                //}
                //catch (Exception e)
                //{
                //    _logger.LogError("_provinceService.RevokeOrder throw exception: {ex}", e.Message);
                //}
            }
        }
    }

    /// <summary>
    /// 批量审批工单特提
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [HttpPut("special_batch")]
    [LogFilter("批量审批工单特提")]
    public async Task UpdateBatch([FromBody] BatchAuditOrderSpecialDto dto)
    {
        foreach (string id in dto.ids)
        {
            var special = await _orderSpecialRepository
            .Queryable()
            .Includes(d => d.Order)
            .FirstAsync(d => d.Id == 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);
            await _orderSpecialRepository.UpdateAsync(special, HttpContext.RequestAborted);
            var order = await _orderRepository.GetAsync(x => x.Id == special.OrderId);
            if (special.State == 1)
            {
                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.AlterTime)
                //    recall.External = new External { TimeLimit = dto.TimeLimit, TimeLimitUnit = dto.TimeLimitUnit };
                //if (dto.Files.Any()) recall.Files = dto.Files;
                // 计算期满时间
                //if (dto.AlterTime)
                //{
                var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
                var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
                await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, ProcessType = processType })
                    .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                var orderDto = _mapper.Map<OrderDto>(order);
                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted);
                //}

                //todo 特提重办，按审批通过时间依据中心派至部门的规则计算期满时间，更新order

                await _workflowApplication.RecallAsync(recall, expiredTime.ExpiredTime, HttpContext.RequestAborted);
                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);
                }

                if (order != null && ("001171".Equals(special.OrgId) ||
                                      "001178".Equals(special.OrgId) ||
                                      "001180".Equals(special.OrgId)))
                {
                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowRecalled,
                 new PublishSpecialDto { Order = _mapper.Map<OrderDto>(order), Special = _mapper.Map<OrderSpecialDto>(special) }, cancellationToken: HttpContext.RequestAborted);

                    //try
                    //{
                    //    await _provinceService.RevokeOrder(
                    //        new PublishSpecialDto
                    //        { Order = _mapper.Map<OrderDto>(order), Special = _mapper.Map<OrderSpecialDto>(special) },
                    //        HttpContext.RequestAborted);
                    //}
                    //catch (Exception e)
                    //{
                    //    _logger.LogError("_provinceService.RevokeOrder throw exception: {ex}", e.Message);
                    //}
                }
            }
        }

    }

    /// <summary>
    /// 获取工单特提信息列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [Permission(EPermission.AuditSpecialOrderList)]
    [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>
   // [Permission(EPermission.AuditSpecialOrderList)]
    [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)
              .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,
                  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(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptType))
            .WhereIF(dto.Channels.Any(), d => dto.Channels.Contains(d.SourceChannel))
            .WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.HotspotId))
            .WhereIF(!string.IsNullOrEmpty(dto.TransferPhone), d => d.TransferPhone.Contains(dto.TransferPhone!))
            .WhereIF(dto.OrgCodes.Any(), d => dto.OrgCodes.Contains(d.Workflow.ActualHandleOrgCode))
            .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(dto.ExpiredTimeStart.HasValue, d => d.ExpiredTime >= dto.ExpiredTimeStart)
            .WhereIF(dto.ExpiredTimeEnd.HasValue, d => d.ExpiredTime <= dto.ExpiredTimeEnd)
            .WhereIF(dto.Statuses.Any(), d => dto.Statuses.Contains(d.Status))
            .WhereIF(dto.Statuses.Any(d => d == EOrderStatus.BackToUnAccept),
                d => d.Status <= EOrderStatus.SpecialToUnAccept);
        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 baseTypeId = string.Empty;
        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 rsp = new
        {
            SpecialTimeType = EnumExts.GetDescriptions<ETimeType>(),
            SpecialReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SpecialReason),
            Step = step,
            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);
        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);
        //获取部门信息
        var rsp = new
        {
            SpecialTimeType = EnumExts.GetDescriptions<ETimeType>(),
            SpecialReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SpecialReason),
            ReTransactErrorType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ReTransactErrorType),
            Step = step,
            Orgs = orgs,
        };
        return rsp;
    }

    #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>
    [Permission(EPermission.DeleteCitizen)]
    [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>
    [Permission(EPermission.UpdateCitizen)]
    [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>
    [Permission(EPermission.CitizenList)]
    [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 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);
        }
        //关注诉求
        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>
    [Permission(EPermission.UpdateRepeatableEvent)]
    [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>
    [Permission(EPermission.AddOrderWord)]
    [HttpPost("order_word")]
    [LogFilter("新增工单词库")]
    public async Task Add([FromBody] OrderWordAddDto dto)
    {
        var word = _mapper.Map<OrderWord>(dto);
        await _orderWrodRepository.AddAsync(word, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 删除工单词库
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [Permission(EPermission.DeleteOrderWord)]
    [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>
    [Permission(EPermission.UpdateOrderWord)]
    [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("无效工单词库");
        _mapper.Map(dto, word);
        word.LastModificationName = _sessionContext.UserName;
        await _orderWrodRepository.UpdateAsync(word, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 获取工单词库列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [Permission(EPermission.OrderWordList)]
    [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="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>
    [Permission(EPermission.AddOrderObserve)]
    [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 (total, items) = await _orderObserveRepository.Queryable()
            .Includes(x => x.Order)
            .WhereIF(dto.IsProvince.HasValue, x => x.Order.IsProvince == dto.IsProvince)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                x => x.Order.No.Contains(dto.Keyword!) || x.Order.Title.Contains(dto.Keyword!))
            //.WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Order.Title.Contains(dto.Title!))
            //.WhereIF(!string.IsNullOrEmpty(dto.No), x => x.Order.No.Contains(dto.No!))
            .OrderByDescending(x => x.CreationTime)
            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
        return new PagedDto<OrderObserveDto>(total, _mapper.Map<IReadOnlyList<OrderObserveDto>>(items));
    }

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

    #endregion

    #region 工单终结

    /// <summary>
    /// 新增工单终结
    /// </summary>
    /// <param name="dtos"></param>
    /// <returns></returns>
    [Permission(EPermission.AddOrderFinality)]
    [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(dto.IsProvince.HasValue, x => x.Order.IsProvince == dto.IsProvince)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                x => x.Order.No.Contains(dto.Keyword!) || x.Order.Title.Contains(dto.Keyword!))
            //.WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Order.Title.Contains(dto.Title!))
            //.WhereIF(!string.IsNullOrEmpty(dto.No), x => x.Order.No.Contains(dto.No!))
            .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>
    /// <returns></returns>
    [HttpPost("order/about_expire/_export")]
    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(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")]
    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(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 new UserFriendlyException("该工单已被签收");
        order.Sign(_sessionContext.RequiredUserId, _sessionContext.UserName);

        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>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("enterprise/list")]
    [LogFilter("查询企业列表")]
    public async Task<YbEnterprisePaged> QueryYbEnterprises([FromQuery] PagedKeywordRequest dto)
    {
        return await _enterpriseService.QueryYbEnterprisesAsync(dto.Keyword!, dto.PageIndex, dto.PageSize, 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>ExternalId
    /// 导入工单
    /// </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;
            if (list != null && list.Count > 0)
            {
                count = list.Count;
                foreach (var item in list)
                {
                    try
                    {

                        if (item.Source != "麻辣社区" || item.Source != "人民网" || item.Source != "省长信箱" || item.Source != "问政四川")
                        //if (item.Source < ESource.MLSQ || item.Source > ESource.WZSC)
                        {
                            errorCount++;
                            continue;
                        }
                        int SourceCode = 0;

                        switch (item.Source)
                        {
                            case "麻辣社区":
                                SourceCode = 500;
                                break;
                            case "人民网":
                                SourceCode = 501;
                                break;
                            case "省长信箱":
                                SourceCode = 502;
                                break;
                            case "问政四川":
                                SourceCode = 529;
                                break;
                            default:
                                break;
                        }
                        var order = await _orderRepository.GetAsync(x => x.ExternalId == item.ExternalId && x.Source == (ESource)SourceCode, HttpContext.RequestAborted);

                        order = _mapper.Map<Orders.Order>(item);
                        #region 处理数据开始
                        order.Source = (ESource)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.Address = $"{order.Province}{order.City}{order.County}{order.Town}";
                        order.FullAddress = $"{order.Address}{order.Street}";

                        #endregion
                        if (order is null)
                        {
                            //order.Source = item;
                            var id = await _orderRepository.AddAsync(order, 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 };
        }
    }

    /// <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("二次办理审批")]
    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("二次办理批量审批")]
    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")]
    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(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")]
    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(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));
    }

    #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));
    }


    #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")]
    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, 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>
    /// 获取修改记录
    /// </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);
    }
    #endregion

    #region 工单平移

    /// <summary>
    /// 查询工单平移待办理人
    /// </summary>
    /// <returns></returns>
    [HttpGet("migration/{orderId}")]
    public async Task<GetOrderMigrationDto> Migration(string orderId)
    {
        var steps = await _workflowStepRepository.Queryable()
            .Where(d => d.ExternalId == orderId && d.Status != EWorkflowStepStatus.Handled)
            .ToListAsync(HttpContext.RequestAborted);

        if (!steps.Any())
            throw new UserFriendlyException("未查询到待办理节点");
        if (steps.Count > 1)
            throw new UserFriendlyException("多个待办理节点暂不支持平移");
        var step = steps.First();
        if (step.BusinessType is not EBusinessType.Center and not EBusinessType.Send)
            throw UserFriendlyException.SameMessage("当前办理节点非中心暂不支持平移");

        var setting = step.BusinessType is EBusinessType.Center
            ? _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,
            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()
        };
    }

    #endregion
}