using Hotline.Application.FlowEngine;
using Hotline.FlowEngine.Definitions;
using Hotline.FlowEngine.Workflows;
using Hotline.Identity.Roles;
using Hotline.Permissions;
using Hotline.Repository.SqlSugar.Extensions;
using Hotline.Settings;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.FlowEngine;
using Hotline.Share.Enums.FlowEngine;
using Hotline.Users;
using MapsterMapper;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using Hotline.FlowEngine.WorkflowModules;
using XF.Domain.Authentications;
using XF.Domain.Exceptions;
using XF.Domain.Extensions;
using XF.Utility.EnumExtensions;
using XF.Domain.Repository;
using Hotline.Share.Dtos.FlowEngine.Workflow;
using Hotline.Caching.Interfaces;
using Hotline.File;
using Hotline.Orders;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Dtos.FlowEngine.Definition;
using Hotline.Settings.TimeLimits;
using Hotline.SeedData;
using Hotline.Tools;
using Hotline.Share.Enums.Order;
using Hotline.Api.Filter;
using Hotline.Settings.CommonOpinions;
using Hotline.Share.Dtos.Settings;

namespace Hotline.Api.Controllers;

/// <summary>
/// 工作流管理
/// </summary>
public class WorkflowController : BaseController
{
    private readonly IDefinitionDomainService _definitionDomainService;
    private readonly IRepository<WorkflowDefinition> _definitionRepository;
    private readonly IWorkflowApplication _workflowApplication;
    private readonly IWorkflowDomainService _workflowDomainService;
    private readonly IWorkflowRepository _workflowRepository;
    private readonly IRepository<User> _userRepository;
    private readonly ISystemOrganizeRepository _organizeRepository;
    private readonly IRepository<Role> _roleRepository;
    private readonly ISystemDomainService _systemDomainService;
    private readonly IWfModuleDomainService _wfModuleDomainService;
    private readonly IRepository<WorkflowStep> _workflowStepRepository;
    private readonly IRepository<WorkflowModule> _wfModuleRepository;
    private readonly IRepository<WorkflowTrace> _workflowTraceRepository;
    private readonly IRepository<WorkflowCountersign> _workflowCountersignRepository;
    private readonly IRepository<WorkflowCountersignMember> _workflowCountersignMemberRepository;
    private readonly ISessionContext _sessionContext;
    private readonly IMapper _mapper;
    private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
    private readonly IFileRepository _fileRepository;
    private readonly ISystemDicDataCacheManager _sysDicDataCacheManager;
    private readonly ISystemSettingCacheManager _systemSettingCacheManager;

    public WorkflowController(
        IDefinitionDomainService definitionDomainService,
        IRepository<WorkflowDefinition> definitionRepository,
        IWorkflowApplication workflowApplication,
        IWorkflowDomainService workflowDomainService,
        IWorkflowRepository workflowRepository,
        IRepository<User> userRepository,
        ISystemOrganizeRepository organizeRepository,
        IRepository<Role> roleRepository,
        ISystemDomainService systemDomainService,
        IWfModuleDomainService wfModuleDomainService,
        IRepository<WorkflowStep> workflowStepRepository,
        IRepository<WorkflowModule> wfModuleRepository,
        IRepository<WorkflowTrace> workflowTraceRepository,
        IRepository<WorkflowCountersign> workflowCountersignRepository,
        ISessionContext sessionContext,
        IMapper mapper,
        ISystemDicDataCacheManager systemDicDataCacheManager,
        IFileRepository fileRepository,
        IRepository<WorkflowCountersignMember> workflowCountersignMemberRepository,
        ISystemDicDataCacheManager sysDicDataCacheManager,
        ISystemSettingCacheManager systemSettingCacheManager
    )
    {
        _definitionDomainService = definitionDomainService;
        _definitionRepository = definitionRepository;
        _workflowApplication = workflowApplication;
        _workflowDomainService = workflowDomainService;
        _workflowRepository = workflowRepository;
        _userRepository = userRepository;
        _organizeRepository = organizeRepository;
        _roleRepository = roleRepository;
        _systemDomainService = systemDomainService;
        _wfModuleDomainService = wfModuleDomainService;
        _workflowStepRepository = workflowStepRepository;
        _wfModuleRepository = wfModuleRepository;
        _sessionContext = sessionContext;
        _mapper = mapper;
        _workflowTraceRepository = workflowTraceRepository;
        _workflowCountersignRepository = workflowCountersignRepository;
        _systemDicDataCacheManager = systemDicDataCacheManager;
        _fileRepository = fileRepository;
        _workflowCountersignMemberRepository = workflowCountersignMemberRepository;
        _sysDicDataCacheManager = sysDicDataCacheManager;
        _systemSettingCacheManager = systemSettingCacheManager;
    }

    #region definition

    /// <summary>
    /// 分页查询最新版本号的模板
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("definition/latest")]
    public async Task<PagedDto<DefinitionDto>> QueryDefinitionLatest([FromQuery] QueryDefinitionDto dto)
    {
        var query2 = await _definitionRepository.Queryable()
            .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                d => d.Code.Contains(dto.Keyword) || d.Name.Contains(dto.Keyword))
            .Select(d => new { i = SqlFunc.RowNumber($"{d.Version} desc", d.Code), d })
            .MergeTable()
            .Where(d => d.i == 1)
            .ToListAsync();

        var items = query2.Select(d => d.d).ToList();

        return new PagedDto<DefinitionDto>(query2.Count, _mapper.Map<IReadOnlyList<DefinitionDto>>(items));
    }

    /// <summary>
    /// 分页查询流程模板
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("definition")]
    public async Task<PagedDto<DefinitionDto>> QueryDefinitions([FromQuery] QueryDefinitionDto dto)
    {
        #region old version:只查询草稿、禁用以及已启用模板的最新版本

        ////todo 数据量大需重构
        //var query1 = await _definitionRepository.Queryable()
        //    .Where(d => d.Status == EDefinitionStatus.Temporary)
        //    .ToListAsync();
        //var query2 = await _definitionRepository.Queryable()
        //    .Where(d => d.Status != EDefinitionStatus.Temporary)
        //    .Select(d => new { i = SqlFunc.RowNumber($"{d.Version} desc", d.Code), d })
        //    .MergeTable()
        //    .Where(d => d.i == 1)
        //    .ToListAsync();

        //var query = query1.Union(query2.Select(d => d.d));
        //var total = query.Count();
        //var items = query
        //    .OrderBy(d => d.Status)
        //    .ThenByDescending(d => d.CreationTime)
        //    .Skip(dto.Skip())
        //    .Take(dto.PageSize)
        //    .ToList();

        #endregion

        var (total, items) = await _definitionRepository.Queryable()
            .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                d => d.Code.Contains(dto.Keyword!) || d.Name.Contains(dto.Keyword!))
            .OrderBy(d => d.Status)
            .OrderBy(d => d.Code)
            .OrderByDescending(d => d.Version)
            .ToPagedListAsync(dto, HttpContext.RequestAborted);

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

    /// <summary>
    /// 分页查询流程模板导出
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("definition/export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> QueryDefinitionsExport([FromBody] ExportExcelDto<QueryDefinitionDto> dto)
    {
        var query = _definitionRepository.Queryable()
            .WhereIF(dto.QueryDto.Status.HasValue, d => d.Status == dto.QueryDto.Status)
            .WhereIF(!string.IsNullOrEmpty(dto.QueryDto.Keyword),
                d => d.Code.Contains(dto.QueryDto.Keyword!) || d.Name.Contains(dto.QueryDto.Keyword!))
            .OrderBy(d => d.Status)
            .OrderBy(d => d.Code)
            .OrderByDescending(d => d.Version);

        var total = 0;
        var items = new List<WorkflowDefinition>();
        if (dto.IsExportAll)
        {
            items = await query.ToListAsync(HttpContext.RequestAborted);
        }
        else
        {
            (total, items) = await query.ToPagedListAsync(dto.QueryDto.PageIndex, dto.QueryDto.PageSize, HttpContext.RequestAborted);
        }

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

        var dtos = _mapper.Map<ICollection<DefinitionDto>>(items)
                          .Select(stu => _mapper.Map(stu, typeof(DefinitionDto), dynamicClass))
                          .Cast<object>()
                          .ToList();

        var stream = ExcelHelper.CreateStream(dtos);
        return ExcelStreamResult(stream, "流程模板");
    }

    /// <summary>
    /// 查询流程模板
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("definition/{id}")]
    public async Task<DefinitionDto> GetDefinition(string id)
    {
        var definition = await _definitionRepository.GetAsync(id, HttpContext.RequestAborted);
        if (definition == null) return new();
        return _mapper.Map<DefinitionDto>(definition);
    }

    /// <summary>
    /// 新增流程模板草稿
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("definition")]
    public async Task<string> AddDefinition([FromBody] AddDefinitionDto dto)
    {
        return await _definitionDomainService.AddAsync(dto, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 更新流程模板草稿
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut("definition")]
    public async Task UpdateDefinition([FromBody] UpdateDefinitionDto dto)
    {
        var definition = await _definitionRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        if (definition == null)
            throw UserFriendlyException.SameMessage("无效模板编号");
        if (definition.Status == EDefinitionStatus.Temporary)
        {
            _mapper.Map(dto, definition);
            await _definitionRepository.UpdateAsync(definition, HttpContext.RequestAborted);
        }
        else
        {
            var newDefinition = _mapper.Map<WorkflowDefinition>(dto);
            await _definitionRepository.AddAsync(newDefinition, HttpContext.RequestAborted);
        }
    }

    /// <summary>
    /// 删除草稿
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    /// <exception cref="UserFriendlyException"></exception>
    [HttpDelete("definition/{id}")]
    public async Task RemoveDefinition(string id)
    {
        var definition = await _definitionRepository.GetAsync(id, HttpContext.RequestAborted);
        if (definition == null) return;
        if (definition.Status != EDefinitionStatus.Temporary)
            throw new UserFriendlyException("已发布模板不能删除");
        await _definitionRepository.RemoveAsync(id, false, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 发布（列表操作）
    /// </summary>
    /// <returns></returns>
    [HttpPost("definition/{id}/publish")]
    public async Task Publish(string id)
    {
        await _definitionDomainService.PublishAsync(id, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 发布（保存并发布）
    /// </summary>
    /// <returns></returns>
    [Obsolete]
    [HttpPost("definition/publish")]
    public async Task Publish([FromBody] AddDefinitionDto dto)
    {
        await _definitionDomainService.PublishAsync(dto, HttpContext.RequestAborted);
    }

    #endregion

    #region WorkflowModule

    /// <summary>
    /// 持久化新增工作流业务
    /// </summary>
    /// <returns></returns>
    [HttpGet("wfmodule/persistence")]
    public async Task PersistenceWfModule()
    {
        await _wfModuleDomainService.PersistenceModulesAsync(HttpContext.RequestAborted);
    }

    /// <summary>
    /// 查询所有工作流模块
    /// </summary>
    /// <returns></returns>
    [HttpGet("wfmodules")]
    public async Task<IReadOnlyList<WorkflowModule>> QueryWfModules()
    {
        return await _wfModuleRepository.Queryable()
            .Includes(d => d.Definition)
            .ToListAsync();
    }

    /// <summary>
    /// 查询所有工作流模块导出
    /// </summary>
    /// <returns></returns>
    [HttpPost("wfmodules/export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> QueryWfModulesExport([FromBody] ExportExcelDto<QueryCommonDto> dto)
    {
        var items = await _wfModuleRepository.Queryable().Includes(d => d.Definition).ToListAsync(HttpContext.RequestAborted);

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

        var dtos = _mapper.Map<ICollection<WorkflowModule>>(items)
                          .Select(stu => _mapper.Map(stu, typeof(WorkflowModule), dynamicClass))
                          .Cast<object>()
                          .ToList();

        var stream = ExcelHelper.CreateStream(dtos);
        return ExcelStreamResult(stream, "流程业务");
    }

    /// <summary>
    /// 为工作流业务匹配或取消流程模板
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut("wfmodule/match")]
    public async Task MatchDefinition([FromBody] MatchDefinitionDto dto)
    {
        if (string.IsNullOrEmpty(dto.DefinitionId))
        {
            //取消当前已配置模板
            await _wfModuleDomainService.MatchDefinitionAsync(dto, HttpContext.RequestAborted);
        }
        else
        {
            var definition = await _definitionRepository.GetAsync(dto.DefinitionId);
            if (definition == null)
                throw UserFriendlyException.SameMessage("无效模板编号");
            if (definition.Status != EDefinitionStatus.Enable)
                throw UserFriendlyException.SameMessage("该模板未发布");
            await _wfModuleDomainService.MatchDefinitionAsync(dto, HttpContext.RequestAborted);
        }
    }

    #endregion

    #region workflow

    /// <summary>
    /// 分页查询流程
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet]
    public async Task<PagedDto<WorkflowDto>> QueryPaged([FromQuery] QueryWorkflowPagedDto dto)
    {
        var (total, items) = await _workflowRepository.Queryable()
            .WhereIF(!string.IsNullOrEmpty(dto.ModuleCode), d => d.ModuleCode == dto.ModuleCode)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                d => d.Id.Contains(dto.Keyword!) || d.Title.Contains(dto.Keyword!))
            .OrderByDescending(d => d.CreationTime)
            .ToPagedListAsync(dto, HttpContext.RequestAborted);

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

    /// <summary>
    /// 查询流程办理下一步可选节点
    /// </summary>
    [HttpGet("{workflowId}/nextsteps")]
    public async Task<NextStepsDto> GetNextStepDefine(string workflowId)
    {
        return await _workflowApplication.GetNextStepsAsync(workflowId, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 办理节点
    /// </summary>
    [HttpPost("next")]
    [Obsolete("即将弃用")]
    [LogFilterAlpha("审核开始")]
    public async Task Next([FromBody] NextWorkflowDto dto)
    {
        await _workflowDomainService.NextAsync(dto, cancellationToken: HttpContext.RequestAborted);
    }

    /// <summary>
    /// 退回（返回前一节点）
    /// </summary>
    [HttpPost("previous")]
    [Obsolete("即将弃用")]
    [LogFilterAlpha("审核退回")]
    public async Task Previous([FromBody] PreviousWorkflowDto dto)
    {
        await _workflowDomainService.PreviousAsync(dto, cancellationToken: HttpContext.RequestAborted);
    }

    /// <summary>
    /// 获取撤回可选节点
    /// </summary>
    /// <param name="workflowId"></param>
    /// <returns></returns>
    [HttpGet("{workflowId}/recall")]
    public async Task<NextStepsDto<RecallStepOption>> GetRecallSteps(string workflowId)
    {
        return await _workflowApplication.GetRecallStepsAsync(workflowId, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 终止流程
    /// </summary>
    [HttpPost("terminate")]
    public async Task Terminate([FromBody] TerminateDto dto)
    {
        await _workflowDomainService.TerminateAsync(dto, HttpContext.RequestAborted);
    }

    ///// <summary>
    ///// 撤销流程
    ///// </summary>
    //[HttpPost("cancel")]
    //public async Task Cancel([FromBody] CancelDto dto)
    //{
    //    await _workflowDomainService.CancelAsync(dto, DateTime.Now, _sessionContext, HttpContext.RequestAborted);
    //}

    /// <summary>
    /// 否决
    /// </summary>
    [HttpPost("reject")]
    public async Task Reject([FromBody] RejectDto dto)
    {
        await _workflowApplication.RejectAsync(dto, HttpContext.RequestAborted);
    }

    // /// <summary>
    // /// 补充
    // /// </summary>
    // /// <param name="dto"></param>
    // /// <returns></returns>
    // [HttpPost("supplement")]
    // public async Task Supplement([FromBody] SupplementDto dto)
    // {
    //     var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId);
    //     await _workflowDomainService.SupplementAsync(workflow, dto, HttpContext.RequestAborted);
    // }

    /// <summary>
    /// 查询办理类型参数
    /// </summary>
    [HttpGet("handlerclassify/{handlerType}")]
    public async Task<List<KeyValuePair<string, string>>> GetHandlerClassifies(EHandlerType handlerType)
    {
        switch (handlerType)
        {
            case EHandlerType.Role:
                var roles = await _roleRepository.QueryAsync();
                return roles.Select(d => new KeyValuePair<string, string>(d.Name, d.DisplayName)).ToList();
            case EHandlerType.OrgLevel:
                var orgs1 = await _systemDomainService.QueryOrgLevelStringOptionsAsync(HttpContext.RequestAborted);
                return orgs1.ToList();
            case EHandlerType.OrgType:
                return EnumExts.GetDescriptions<EOrgType>()
                    .Select(d => new KeyValuePair<string, string>(d.Key.ToString(), d.Value)).ToList();
            case EHandlerType.AssignedOrg:
                var orgs = await _organizeRepository.GetOrgJson();
                return orgs.Select(d => new KeyValuePair<string, string>(d.Id, d.Name)).ToList();
            case EHandlerType.AssignedUser:
            default:
                throw new ArgumentOutOfRangeException(nameof(handlerType), handlerType, null);
        }
    }

    /// <summary>
    /// 查询流程流转记录
    /// </summary>
    /// <param name="workflowId"></param>
    /// <returns></returns>
    [HttpGet("{workflowId}/traces")]
    public async Task<WorkflowDto> GetWorkflowTraces(string workflowId)
    {
        var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withTracesTree: true,
            cancellationToken: HttpContext.RequestAborted);
        workflow.Traces = workflow.Traces.Where(d => d.TraceStyle == ETraceStyle.Flow).Where(d => d.HandleMode != EHandleMode.PreviousNoDisplay).ToList();

        var workflowDto = _mapper.Map<WorkflowDto>(workflow);
        if (workflowDto.Traces.Any())
        {
            workflowDto.Traces = await _fileRepository.WorkflowTraceRecursion(workflowDto.Traces, HttpContext.RequestAborted);
        }
        return workflowDto;
    }

    /// <summary>
    /// 查询被督办/催办部门
    /// </summary>
    /// <param name="workflowId"></param>
    /// <returns></returns>
    [HttpGet("{workflowId}/urge")]
    public async Task<IReadOnlyList<Kv>> GetUrgeOrgs(string workflowId)
    {
        /*
         * 非会签：当前部门上至一级部门（过期）
         * 中心会签：一级部门下至所有当前办理部门（遍历所有会签分支）（过期）
         */
        var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withSteps: true,
            cancellationToken: HttpContext.RequestAborted);

        //所有节点的待办对象
        return workflow.Steps
            .Where(d => d.StepType != EStepType.Start && d.StepType != EStepType.End)
            .SelectMany(d => d.Handlers)
            .DistinctBy(d => d.Key)
            .ToList();
    }

    [HttpGet("base-data")]
    public async Task<dynamic> BaseData()
    {
        var levels = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        var orgs = levels.Select(d => new KeyValuePair<string, string>(d.ToString(), $"{d.ToChinese()}级部门办理")).ToList();
        var center = new KeyValuePair<string, string>("0", "中心办理");
        var centerIsTop = new List<KeyValuePair<string, string>> { center };
        centerIsTop.AddRange(orgs);
        return new
        {
            ModuleOptions = WorkflowModuleConsts.AllModules.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)),
            HandlerTypeOptions = EnumExts.GetDescriptions<EHandlerType>(),
            BusinessTypeOptions = EnumExts.GetDescriptions<EBusinessType>(),
            StepPropertiesOptions = _systemDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.WorkflowStepComponent),
            //PathPolicyOptions = EnumExts.GetDescriptions<EPathPolicy>(),
            ExecuteModeOptions = EnumExts.GetDescriptions<EExecuteMode>(),
            InstanceModeOptions = EnumExts.GetDescriptions<EInstanceMode>(),
            StepTypeOptions = EnumExts.GetDescriptions<EStepType>().Where(d => d.Key != 1 && d.Key != 2),
            DynamicPolicyOptions = EnumExts.GetDescriptions<EDynamicPolicy>()
                .Select(d => new
                {
                    Key = d.Key,
                    Value = d.Value,
                    Items = d.Key is 0 or 2 or 4 or 6 ? centerIsTop : orgs
                }),
            CountersignPolicyOptions = EnumExts.GetDescriptions<ECountersignPolicy>()
                .Select(d => new
                {
                    Key = d.Key,
                    Value = d.Value,
                    Items = d.Key is 0 or 2 ? centerIsTop : orgs
                }),
            FlowTypeOptions = EnumExts.GetDescriptions<EFlowType>()
        };
    }

    /// <summary>
    /// 查询会签信息
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("countersign")]
    public async Task<PagedDto<WorkflowCountersignDto>> QueryWorkflowCountersigns([FromQuery] QueryWorkflowCountersignDto dto)
    {
        RefAsync<int> total = 0;
        var query = _workflowCountersignRepository.Queryable()
            .Includes(x => x.Members)
            .LeftJoin<Workflow>((c, w) => c.WorkflowId == w.Id)
            .InnerJoin<Order>((c, w, o) => w.ExternalId == o.Id)
            .WhereIF(!_sessionContext.OrgIsCenter, (c, w, o) => c.Members.Any(m => m.Key == _sessionContext.OrgId))
            .WhereIF(dto.IsProvince.HasValue, (c, w, o) => o.IsProvince == dto.IsProvince.Value)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                (c, w, o) => o.No.Contains(dto.Keyword) || o.Title.Contains(dto.Keyword));

        //if (dto.IsOnlyStarter)
        //    query = query.Where((c, w, o) => c.StarterId == _sessionContext.RequiredUserId);

        var items = await query
            .OrderByDescending((c, w, o) => o.ExpiredTime)
            .Select((c, w, o) => new { c, o })
            .ToPageListAsync(dto.PageIndex, dto.PageSize, total, HttpContext.RequestAborted);

        var dtos = items.Select(d =>
        {
            var dto = _mapper.Map<WorkflowCountersignDto>(d.c);
            dto.Order = _mapper.Map<OrderDto>(d.o);
            return dto;
        }).ToList();

        return new PagedDto<WorkflowCountersignDto>(total, dtos);
    }



    /// <summary>
    /// 查询会签信息
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpGet("order-countersign")]
    public async Task<PagedDto<WorkflowCountersignDto>> QueryOrderCountersigns([FromQuery] QueryOrderCountersignDto dto)
    {
        RefAsync<int> total = 0;

        var items = await _workflowApplication.QueryOrderCountersigns(dto, _sessionContext)
            .Select((c, w, o) => new { c, o })
            .ToPageListAsync(dto.PageIndex, dto.PageSize, total, HttpContext.RequestAborted);

        var dtos = items.Select(d =>
        {
            var dto = _mapper.Map<WorkflowCountersignDto>(d.c);
            dto.Order = _mapper.Map<OrderDto>(d.o);
            dto.CounterSignCount = _workflowCountersignRepository.Queryable().Where(p => p.WorkflowId == d.c.WorkflowId).CountAsync().GetAwaiter().GetResult();
            return dto;
        })
        .WhereIF(dto.CounterSignCount > 0, d => d.CounterSignCount == dto.CounterSignCount)
        .ToList();

        return new PagedDto<WorkflowCountersignDto>(total, dtos);
    }



    /// <summary>
    /// 会签信息导出
    /// </summary>
    /// <returns></returns>
    [HttpPost("order-countersign/_export")]
    [LogFilterAlpha("导出日志")]
    public async Task<FileStreamResult> ScreenListExport([FromBody] ExportExcelDto<QueryOrderCountersignDto> dto)
    {
        var query = _workflowApplication.QueryOrderCountersigns(dto.QueryDto, _sessionContext)
             .Select((c, w, o) => new WorkflowCountersign()
             {
                 Id = c.Id.SelectAll(),
                 Order = o,
             });
        List<WorkflowCountersign> data;

        if (dto.IsExportAll)
        {
            data = await query.ToListAsync(HttpContext.RequestAborted);
        }
        else
        {

            var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
            data = items;
        }

        var dataDtos = _mapper.Map<ICollection<WorkflowCountersignDto>>(data);

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

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

        var stream = ExcelHelper.CreateStream(dtos);

        return ExcelStreamResult(stream, "会签信息数据");
    }


    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    [HttpGet("order-countersign-base-data")]
    public async Task<object> QueryOrderCountersignsBaseData()
    {

        return new
        {
            CounterSignType = EnumExts.GetDescriptions<ECounterSignType>(),
            ChannelOptions = _sysDicDataCacheManager.GetSysDicDataCache(TimeLimitBaseDataConsts.SourceChannel),
            AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType),
            OrderStatus = EnumExts.GetDescriptions<EOrderStatus>(),
        };
    }

    /// <summary>
    /// 改变某节点办理人
    /// </summary>
    [HttpPost("change-handler")]
    public async Task ChangeHandler([FromBody] ChangeHandlerDto dto)
    {
        var step = await _workflowStepRepository.Queryable()
            .Includes(d => d.WorkflowTrace)
            .FirstAsync(d => d.Id == dto.StepId, HttpContext.RequestAborted);

        //.GetAsync(dto.StepId, HttpContext.RequestAborted);
        if (step is null)
            throw new UserFriendlyException("无效节点编号");
        await _workflowDomainService.ChangeHandlerBatchAsync(new List<(string userId, string username, string orgId, string orgName, string? roleId, string? roleName, ICollection<WorkflowStep> steps)>
            {
                new(dto.Handler.UserId,dto.Handler.Username,dto.Handler.OrgId,dto.Handler.OrgName,step.RoleId,step.RoleName, new List<WorkflowStep>{step})
            }, HttpContext.RequestAborted);
    }

    #endregion

}