using DotNetCore.CAP;
using Hotline.Api.Filter;
using Hotline.Application.Bulletin;
using Hotline.Application.ExportExcel;
using Hotline.Application.ExportWord;
using Hotline.Application.FlowEngine;
using Hotline.Application.Knowledge;
using Hotline.Application.Systems;
using Hotline.Application.Tools;
using Hotline.Caching.Interfaces;
using Hotline.Configurations;
using Hotline.File;
using Hotline.FlowEngine.WorkflowModules;
using Hotline.FlowEngine.Workflows;
using Hotline.KnowledgeBase;
using Hotline.KnowledgeBase.Notifies;
using Hotline.Pdf;
using Hotline.Repository.SqlSugar.Extensions;
using Hotline.Repository.SqlSugar.Ts;
using Hotline.Settings;
using Hotline.Settings.Hotspots;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.FlowEngine;
using Hotline.Share.Dtos.FlowEngine.Workflow;
using Hotline.Share.Dtos.Knowledge;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Enums.Article;
using Hotline.Share.Enums.FlowEngine;
using Hotline.Share.Enums.KnowledgeBase;
using Hotline.Share.Mq;
using Hotline.Share.Tools;
using Hotline.Users;
using Mapster;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using MiniExcelLibs;
using NPOI.SS.Formula.Functions;
using SqlSugar;
using System.Text;
using XF.Domain.Authentications;
using XF.Domain.Exceptions;
using XF.Domain.Repository;
using XF.Utility.EnumExtensions;

namespace Hotline.Api.Controllers
{
    public class KnowledgeController : BaseController
    {

        #region 注入
        private readonly IExportApplication _exportApplication;
        private readonly IRepository<KnowledgeHotWord> _knowledgeHotWordRepository;
        private readonly IRepository<KnowledgeApprove> _knowledgeApproRepository;
        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
        private readonly IPdfManager _pdfManager;
        private readonly IRepository<KnowledgeWord> _knowledgeWordRepository;
        private readonly IWordHelperService _wordHelperService;
        private readonly BaseDataApplication _baseDataApplication;
        private readonly IKnowledgeRepository _knowledgeRepository;
        private readonly ISessionContext _sessionContext;
        private readonly IKnowledgeDomainService _knowledgeDomainService;
        private readonly IMapper _mapper;
        private readonly IKnowApplication _knowApplication;
        private readonly IMediator _mediator;
        private readonly IWorkflowApplication _workflowApplication;
        private readonly IWorkflowDomainService _workflowDomainService;
        private readonly IKnowledgeWorkFlowRepository _knowledgeWorkFlowRepository;
        private readonly IRepository<User> _userRepository;
        private readonly IRepository<KnowledgeType> _knowledgeTypeRepository;
        private readonly IRepository<Hotspot> _hotspotTypeRepository;
        private readonly IRepositoryTextSearch<KnowledgeTs> _repositoryts;
        private readonly IRepository<KnowledgeWord> _knowledgeWrodRepository;
        private readonly IRepository<KnowledgeQuestions> _knowledgeQuestionsRepository;
        private readonly IRepository<KnowledgeCorrection> _knowledgeCorrectionRepository;
        private readonly IRepository<KnowledgeCollect> _knowledgeCollectRepository;
        private readonly ISystemDomainService _systemDomainService;
        private readonly IRepository<KnowledgeComment> _knowledgeCommentRepository;
        private readonly ISystemOrganizeRepository _systemOrganizeRepository;
        private readonly IFileRepository _fileRepository;
        private readonly ICapPublisher _capPublisher;
        private readonly IBulletinApplication _bulletinApplication;
        private readonly IRepository<KnowledgeCollectGroup> _knowledgeCollectGroupRepository;
        private readonly IRepository<KnowledgePv> _knowledgePvepository;
        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;


        public KnowledgeController(
            IKnowledgeRepository knowledgeRepository,
            ISessionContext sessionContext,
            IKnowledgeDomainService knowledgeDomainService,
            IMapper mapper,
            IKnowApplication knowApplication,
            IMediator mediator,
            IWorkflowApplication workflowApplication,
            IWorkflowDomainService workflowDomainService,
            IKnowledgeWorkFlowRepository knowledgeWorkFlowRepository,
            IRepository<User> userRepository,
            IRepository<KnowledgeType> knowledgeTypeRepository,
            IRepository<Hotspot> hotspotTypeRepository,
            IRepositoryTextSearch<KnowledgeTs> repositoryts,
            IRepository<KnowledgeWord> knowledgeWrodRepository,
            IRepository<KnowledgeQuestions> knowledgeQuestionsRepository,
            IRepository<KnowledgeCorrection> knowledgeCorrectionRepository,
            IRepository<KnowledgeCollect> knowledgeCollectRepository,
            ISystemDomainService systemDomainService,
            IRepository<KnowledgeComment> knowledgeCommentRepository,
            ISystemOrganizeRepository systemOrganizeRepository,
            IFileRepository fileRepository,
            ICapPublisher capPublisher,
            IBulletinApplication bulletinApplication,
            IRepository<KnowledgeCollectGroup> knowledgeCollectGroupRepository,
            IExportApplication exportApplication,
            BaseDataApplication baseDataApplication,
            IWordHelperService wordHelperService,
            IRepository<KnowledgePv> knowledgePvepository,
            IRepository<KnowledgeWord> knowledgeWordRepository,
            IRepository<KnowledgeHotWord> knowledgeWordHotRepository,
            IOptionsSnapshot<AppConfiguration> appOptions,
            IRepository<KnowledgeHotWord> knowledgeHotWordRepository,
            IRepository<KnowledgeApprove> knowledgeApproRepository,
            ISystemSettingCacheManager _systemSettingCacheManager,
            IPdfManager pdfManager)
        {
            _knowledgeRepository = knowledgeRepository;
            _sessionContext = sessionContext;
            _knowledgeDomainService = knowledgeDomainService;
            _mapper = mapper;
            _knowApplication = knowApplication;
            _mediator = mediator;
            _workflowApplication = workflowApplication;
            _workflowDomainService = workflowDomainService;
            _knowledgeWorkFlowRepository = knowledgeWorkFlowRepository;
            _userRepository = userRepository;
            _knowledgeTypeRepository = knowledgeTypeRepository;
            _hotspotTypeRepository = hotspotTypeRepository;
            _repositoryts = repositoryts;
            _knowledgeWrodRepository = knowledgeWrodRepository;
            _knowledgeQuestionsRepository = knowledgeQuestionsRepository;
            _knowledgeCorrectionRepository = knowledgeCorrectionRepository;
            _knowledgeCollectRepository = knowledgeCollectRepository;
            _systemDomainService = systemDomainService;
            _knowledgeCommentRepository = knowledgeCommentRepository;
            _systemOrganizeRepository = systemOrganizeRepository;
            _fileRepository = fileRepository;
            _capPublisher = capPublisher;
            _bulletinApplication = bulletinApplication;
            _knowledgeCollectGroupRepository = knowledgeCollectGroupRepository;
            _exportApplication = exportApplication;
            _baseDataApplication = baseDataApplication;
            _wordHelperService = wordHelperService;
            _knowledgePvepository = knowledgePvepository;
            _knowledgeWordRepository = knowledgeWordRepository;
            _knowledgeHotWordRepository = knowledgeHotWordRepository;
            _knowledgeApproRepository = knowledgeApproRepository;
            this._systemSettingCacheManager = _systemSettingCacheManager;
            _pdfManager = pdfManager;
            _appOptions = appOptions;
        }

        #endregion

        #region 知识管理

        /// <summary>
        /// 知识库-新增
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("add")]
        [LogFilter("知识新增")]
        public async Task<string> AddKnowledge([FromBody] AddStartFlowDto dto)
        {
            //var addDto = _mapper.Map<AddKnowledgeDto>(dto.Data);
            var kn = _mapper.Map<Knowledge>(dto.Data);
            kn.SourceOrganizeId = _sessionContext.RequiredOrgId;
            var any = await _knowledgeRepository.Queryable().Where(x => x.Status == EKnowledgeStatus.OnShelf && x.Title == kn.Title).AnyAsync();
            if (any) throw UserFriendlyException.SameMessage("当前知识标题存在重复标题！");

            //Code为空，从新生成Code
            if (string.IsNullOrEmpty(kn.Code))
                kn.Code = Convert.ToInt64((DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds).ToString();

            kn.Status = EKnowledgeStatus.Drafts;
            kn.InitId();
            if (dto.Data.Files.NotNullOrEmpty()) kn.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, kn.Id, "", HttpContext.RequestAborted);
            await _knowledgeRepository.AddAsync(kn, HttpContext.RequestAborted);

            if (dto.Data.KnowledgeType.Any())
            {
                List<KnowledgeRelationType> types = _mapper.Map<List<KnowledgeRelationType>>(dto.Data.KnowledgeType);
                types.ForEach(x => x.KnowledgeId = kn.Id);
                //await _knowledgeRelationTypeRepository.AddRangeAsync(types, HttpContext.RequestAborted);
            }
            if (dto.Workflow != null && !string.IsNullOrEmpty(kn.Id))
            {
                var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
                startDto.DefinitionModuleCode = WorkflowModuleConsts.KnowledgeAdd;
                startDto.Title = "知识库新增";
                //await _workflowApplication.StartWorkflowAsync(startDto, _sessionContext, kn.Id, cancellationToken: HttpContext.RequestAborted);

                await StartFlow(kn.Id, WorkflowModuleConsts.KnowledgeAdd, EKnowledgeApplyType.Add, startDto);
                //var knowledge = await _knowledgeRepository.GetAsync(kn.Id);
                //knowledge.Status = EKnowledgeStatus.Auditing;
                //await _knowledgeRepository.UpdateAsync(knowledge, HttpContext.RequestAborted);
            }

            return kn.Id;
        }

        /// <summary>
        /// 知识库-新增(new)
        /// </summary>
        [HttpPost]
        public async Task<string> Add([FromBody] AddKnowledgeDto dto)
        {
            var kn = await _knowledgeDomainService.AddKnowledgeAsync(dto, HttpContext.RequestAborted);
            return kn.Id;
        }

        /// <summary>
        /// 知识库-新增并发起审批(new)
        /// </summary>
        [HttpPost("add-and-approve")]
        public async Task<string> AddAndApprove([FromBody] AddKnowledgeDto dto)
        {
            var kn = await _knowledgeDomainService.AddKnowledgeAsync(dto, HttpContext.RequestAborted);

            var approve = await _knowledgeDomainService.AddKnowledgeApproveAsync(EKnowledgeApproveType.Add, kn, null,
                HttpContext.RequestAborted);

            return approve.Id;
        }

        /// <summary>
        /// 知识库-知识下架
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        [HttpPut("offshelf")]
        [LogFilter("知识下架")]
        public async Task KnowledgeOffShelf([FromBody] OffShelfStartFlowDto dto)
        {
            var know = await _knowledgeRepository.GetAsync(dto.Data.Id, HttpContext.RequestAborted);
            if (know != null && know.Status == EKnowledgeStatus.OnShelf)
            {
                if (_sessionContext.OrgIsCenter || !_appOptions.Value.IsYiBin)
                {
                    know.Status = EKnowledgeStatus.OffShelf;
                    know.OnShelfTime = null;
                    know.OffShelfTime = DateTime.Now;
                    await _knowledgeRepository.UpdateAsync(know, HttpContext.RequestAborted);

                    var pushKnowledge = _mapper.Map<KnowledgeSendDto>(know);
                    pushKnowledge.CategoryCode = "01";
                    pushKnowledge.CategoryName = "公共服务";
                    //推省上
                    await _capPublisher.PublishAsync(EventNames.HotlineKnowledgeRemove, pushKnowledge, cancellationToken: HttpContext.RequestAborted);
                }
                else
                {
                    know.Status = EKnowledgeStatus.Auditing;
                    await _knowledgeRepository.UpdateAsync(know, HttpContext.RequestAborted);

                    var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
                    startDto.DefinitionModuleCode = WorkflowModuleConsts.KnowledgeOffshelf;
                    startDto.Opinion = dto.Data.Opinion;
                    startDto.Title = "知识库下架";
                    await StartFlow(know.Id, WorkflowModuleConsts.KnowledgeOffshelf, EKnowledgeApplyType.Offshelf, startDto);
                }
            }
            else
                throw UserFriendlyException.SameMessage("知识下架失败");
        }

        /// <summary>
        /// 知识库-知识下架(new)
        /// </summary>
        [HttpPost("offshelf")]
        [LogFilter("知识下架")]
        public Task OffShelf([FromBody] OffShelfKnowledgeDto dto) =>
            _knowledgeDomainService.OffShelfAsync(dto, HttpContext.RequestAborted);

        /// <summary>
        /// 知识库-知识下架并发起审批(new)
        /// </summary>
        [HttpPost("offshelf-and-approve")]
        [LogFilter("知识下架并发起审批")]
        public async Task OffShelfAndApprove([FromBody] OffShelfKnowledgeDto dto)
        {
            var kn = await _knowledgeDomainService.OffShelfAsync(dto, HttpContext.RequestAborted);

            await _knowledgeDomainService.AddKnowledgeApproveAsync(EKnowledgeApproveType.OffShelf,
                kn, dto.Opinion, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 知识库-知识上架
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        [HttpPut("ontheshelf")]
        [LogFilter("知识上架")]
        public async Task KnowledgeOnTheShelf(string Id)
        {
            var know = await _knowledgeRepository.GetAsync(Id, HttpContext.RequestAborted);
            if (know != null && know.Status == EKnowledgeStatus.OffShelf)
            {
                var any = await _knowledgeRepository.Queryable().Where(x => x.Status == EKnowledgeStatus.OnShelf && x.Title == know.Title && x.Id != know.Id).AnyAsync();
                if (any) throw UserFriendlyException.SameMessage("当前知识标题存在重复标题！");
                if (know.ExpiredTime < DateTime.Now) throw UserFriendlyException.SameMessage("知识已过期不能上架！");

                know.Status = EKnowledgeStatus.OnShelf;
                know.OnShelfTime = DateTime.Now;
                know.OffShelfTime = null;
                await _knowledgeRepository.UpdateAsync(know, HttpContext.RequestAborted);
            }
            else
                throw UserFriendlyException.SameMessage("知识上架失败");
        }

        /// <summary>
        /// 批量上架
        /// </summary>
        /// <returns></returns>
        [HttpPost("ontheshelfbatch")]
        [LogFilter("批量上架")]
        public async Task KnowledgeOnTheShelfBatch([FromBody] UnshelveBatchRequest request)
        {
            var kns = request.KnowledgeIds.Select(d => new Knowledge
            {
                Id = d,
                Status = EKnowledgeStatus.OnShelf,
                OnShelfTime = DateTime.Now,
                OffShelfTime = null
            }).ToList();
            await _knowledgeRepository.Updateable(kns)
                .UpdateColumns(d => d.Status)
                .Where(d => d.Status == EKnowledgeStatus.OffShelf)
                .ExecuteCommandAsync(HttpContext.RequestAborted);
        }


        /// <summary>
        /// 知识库-标题
        /// </summary>
        /// <param name="title"></param>
        /// <returns></returns>
        [HttpGet("title")]
        public async Task<bool> KnowledgeTitle([FromQuery] KnowledgeTitleDto dto)
        {
            var count = await _knowledgeRepository.Queryable()
                .WhereIF(!string.IsNullOrEmpty(dto.Id), x => x.Id != dto.Id)
                .Where(x => x.Title == dto.Title && x.Status == EKnowledgeStatus.OnShelf).CountAsync();
            return count > 0;
        }

        /// <summary>
        /// 知识库-修改
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("update")]
        [LogFilter("知识修改")]
        public async Task UpdateKnowledge([FromBody] UpdateStartFlowDto dto)
        {
            var knowledge = await _knowledgeRepository.GetAsync(dto.Data.Id);
            if (knowledge == null)
                throw UserFriendlyException.SameMessage("知识库数据错误");
            if ((knowledge.Status == EKnowledgeStatus.OnShelf || knowledge.Status == EKnowledgeStatus.Auditing) && (knowledge.ExpiredTime.HasValue && knowledge.ExpiredTime.Value > DateTime.Now))
                throw UserFriendlyException.SameMessage("知识库数据不可修改");

            var any = await _knowledgeRepository.Queryable().Where(x => x.Status == EKnowledgeStatus.OnShelf && x.Title == dto.Data.Title && x.Id != dto.Data.Id).AnyAsync();
            if (any) throw UserFriendlyException.SameMessage("当前知识标题存在重复标题！");
            _mapper.Map(dto.Data, knowledge);
            knowledge.HotspotId = dto.Data.HotspotId;
            knowledge.HotspotExternal = dto.Data.HotspotExternal;

            if (dto.Data.Files.Any())
                knowledge.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, knowledge.Id, "", HttpContext.RequestAborted);
            else
                knowledge.FileJson = new List<Share.Dtos.File.FileJson>();
            if (dto.Workflow != null) knowledge.Renewaln = knowledge.Status != EKnowledgeStatus.Drafts;
            if (_appOptions.Value.IsYiBin)
            {
                //临时处理 修改后提交修改基本信息
                if (!_sessionContext.OrgIsCenter)
                {
                    knowledge.Attribution = "部门知识库";
                }
                knowledge.CreatorId = _sessionContext.UserId;
                knowledge.CreatorName = _sessionContext.UserName;
                knowledge.CreatorOrgId = _sessionContext.OrgId;
                knowledge.CreatorOrgName = _sessionContext.OrgName;
                knowledge.CreatorOrgLevel = _sessionContext.OrgLevel;
            }

            await _knowledgeRepository.UpdateNullAsync(knowledge, HttpContext.RequestAborted);
            if (dto.Data.KnowledgeType.Any())
            {
                //var anyRelationTypes = await _knowledgeRelationTypeRepository.Queryable().Where(x => x.KnowledgeId == knowledge.Id).ToListAsync();
                //if (anyRelationTypes.Any())
                //    await _knowledgeRelationTypeRepository.RemoveRangeAsync(anyRelationTypes);
                //List<KnowledgeRelationType> types = _mapper.Map<List<KnowledgeRelationType>>(dto.Data.KnowledgeType);
                //types.ForEach(x => x.KnowledgeId = dto.Data.Id);
                //await _knowledgeRelationTypeRepository.AddRangeAsync(types, HttpContext.RequestAborted);
            }
            if (dto.Workflow != null)
            {
                if (knowledge.Status == EKnowledgeStatus.Drafts)
                {
                    var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
                    startDto.DefinitionModuleCode = WorkflowModuleConsts.KnowledgeAdd;
                    startDto.Title = "知识库新增";
                    //await _workflowApplication.StartWorkflowAsync(startDto, _sessionContext, knowledge.Id, cancellationToken: HttpContext.RequestAborted);
                    await StartFlow(knowledge.Id, WorkflowModuleConsts.KnowledgeAdd, EKnowledgeApplyType.Add, startDto);
                }
                else
                {
                    var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
                    startDto.DefinitionModuleCode = WorkflowModuleConsts.KnowledgeUpdate;
                    startDto.Title = "知识库修改";
                    //await _workflowApplication.StartWorkflowAsync(startDto, _sessionContext, knowledge.Id, cancellationToken: HttpContext.RequestAborted);
                    await StartFlow(knowledge.Id, WorkflowModuleConsts.KnowledgeUpdate, EKnowledgeApplyType.Update, startDto);
                }
            }

        }

        /// <summary>
        /// 知识库-修改(new)
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut]
        [LogFilter("知识修改")]
        public Task Update([FromBody] UpdateKnowledgeDto dto) =>
            _knowledgeDomainService.UpdateKnowledgeAsync(dto, HttpContext.RequestAborted);

        /// <summary>
        /// 知识库-修改(new)
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("update-and-approve")]
        [LogFilter("知识修改")]
        public async Task UpdateAndApprove([FromBody] UpdateKnowledgeAndApproveDto dto)
        {
            var kn = await _knowledgeDomainService.UpdateKnowledgeAsync(dto, HttpContext.RequestAborted);

            var exists = await _knowledgeApproRepository.Queryable()
                .AnyAsync(d => d.KnowledgeId == dto.Id && d.KnowledgeApproveStatus == EKnowledgeApproveStatus.Unhandle,
                    HttpContext.RequestAborted);
            if (exists)
                throw new UserFriendlyException($"该知识存在待审批申请, knId: {dto.Id}", "该知识存在待审批申请, 请先审批");

            if (kn.Status == EKnowledgeStatus.Drafts)
            {
                await _knowledgeDomainService.AddKnowledgeApproveAsync(EKnowledgeApproveType.Add, kn, null,
                    HttpContext.RequestAborted);
            }
            else
            {
                await _knowledgeDomainService.AddKnowledgeApproveAsync(EKnowledgeApproveType.Update, kn, dto.Opinion,
                    HttpContext.RequestAborted);
            }
        }

        /// <summary>
        /// 知识库-修改(new)
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("update-and-approve-batch")]
        [LogFilter("知识修改批量")]
        public async Task UpdateAndApproveBatch([FromBody] UpdateKnowledgeAndApproveBatchDto dto)
        {
            foreach (var item in dto.KnowledgeIds)
            {
                var knowledge = await _knowledgeRepository.GetAsync(d => d.Id == item && d.Status == EKnowledgeStatus.Drafts);
                UpdateKnowledgeAndApproveDto ukaa = _mapper.Map<UpdateKnowledgeAndApproveDto>(knowledge);
                ukaa.Opinion = dto.Opinion;

                var kn = await _knowledgeDomainService.UpdateKnowledgeAsync(ukaa, HttpContext.RequestAborted);

                var exists = await _knowledgeApproRepository.Queryable()
                    .AnyAsync(d => d.KnowledgeId == item && d.KnowledgeApproveStatus == EKnowledgeApproveStatus.Unhandle,
                        HttpContext.RequestAborted);
                if (!exists)
                {
                    if (kn.Status == EKnowledgeStatus.Drafts)
                    {
                        await _knowledgeDomainService.AddKnowledgeApproveAsync(EKnowledgeApproveType.Add, kn, null,
                            HttpContext.RequestAborted);
                    }
                    else
                    {
                        await _knowledgeDomainService.AddKnowledgeApproveAsync(EKnowledgeApproveType.Update, kn, dto.Opinion,
                            HttpContext.RequestAborted);
                    }
                }
            }
        }

        /// <summary>
        /// 批量更新公开状态(new)
        /// </summary>
        /// <returns></returns>
        [HttpPost("publish-batch")]
        public async Task PublishBatch([FromBody] PublishBatchRequest request)
        {
            var kns = request.KnowledgeIds.Select(d => new Knowledge
            {
                Id = d,
                IsPublic = request.IsPublic
            }).ToList();
            await _knowledgeRepository.Updateable(kns)
                .UpdateColumns(d => d.IsPublic)
                .Where(d => d.Status == EKnowledgeStatus.OnShelf)
                .ExecuteCommandAsync(HttpContext.RequestAborted);
        }

        /// <summary>
        /// 批量下架
        /// </summary>
        /// <returns></returns>
        [HttpPost("unshelve-batch")]
        public async Task UnshelveBatch([FromBody] UnshelveBatchRequest request)
        {
            var kns = request.KnowledgeIds.Select(d => new Knowledge
            {
                Id = d,
                Status = EKnowledgeStatus.OffShelf
            }).ToList();
            await _knowledgeRepository.Updateable(kns)
                .UpdateColumns(d => d.Status)
                .ExecuteCommandAsync(HttpContext.RequestAborted);
        }


        /// <summary>
        /// 批量审核
        /// </summary>
        /// <returns></returns>
        [HttpPost("batch_audit")]
        public async Task<string> KnowledgeBatchAuditAsync([FromBody] KnowledgeBatchAuditInDto dto)
        {
            var result = new StringBuilder();
            var fail = 0;
            var success = 0;
            var nextWorkflowDto = new NextWorkflowDto
            {
                IsSms = dto.IsSms,
                ReviewResult = dto.IsPass ? EReviewResult.Approval : EReviewResult.Failed,
                Opinion = dto.Opinion
            };
            foreach (var knowledgeId in dto.KnowledgeIds)
            {
                try
                {
                    var knowledge = await _knowledgeDomainService.KnowledgeInfo(knowledgeId, HttpContext.RequestAborted);
                    nextWorkflowDto.WorkflowId = knowledge.WorkflowId;
                    NextStepsWithOpinionDto<NextStepOption> next = null;
                    try
                    {
                        next = await _workflowApplication.GetNextStepsAsync(knowledge.WorkflowId, HttpContext.RequestAborted);
                    }
                    catch (UserFriendlyException e)
                    {
                        if (e.Message.Contains("未找到对应节点"))
                        {
                            result.Append("无权审核:" + knowledge.Title);
                            fail++;
                        }
                        else
                        {
                            throw;
                        }
                    }
                    if (next == null) continue;
                    nextWorkflowDto.StepId = next.StepId;
                    nextWorkflowDto.NextStepCode = next.Steps.First().Key;
                    nextWorkflowDto.NextStepName = next.Steps.First().Value;
                    if (dto.IsPass)
                        await _workflowDomainService.NextAsync(nextWorkflowDto,
                            cancellationToken: HttpContext.RequestAborted);
                    else
                    {
                        var reject = nextWorkflowDto.Adapt<RejectDto>();
                        await _workflowApplication.RejectAsync(reject, HttpContext.RequestAborted);
                    }
                    success++;
                }
                catch (UserFriendlyException e)
                {
                    result.Append(e.Message);
                    fail++;
                }
            }
            return $"总共: {dto.KnowledgeIds.Length}, 成功: {success}, 失败: {fail}, 失败原因: {result.ToString()}";
        }

        /// <summary>
        /// 根据知识标题自动分词并保存到关键词表中
        /// </summary>
        /// <param name="title"></param>
        /// <returns></returns>
        [HttpGet("participle")]
        public async Task<IList<KnowledgeWordOutDto>> KnowledgeKeyWord([FromQuery] string title)
        {
            return await _knowApplication.TitleParticiple(title);
        }

        /// <summary>
        /// 删除知识
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete]
        [LogFilter("删除知识")]
        public async Task Remove([FromBody] DeleteStartFlowDto dto)
        {
            //var delete = _mapper.Map<KnowledgeDto>(dto.Data);
            var knowledge = await _knowledgeRepository.GetAsync(dto.Data.Id, HttpContext.RequestAborted);
            if (knowledge == null)
                throw UserFriendlyException.SameMessage("无效知识库数据");
            if ((knowledge.Status == EKnowledgeStatus.OnShelf && knowledge.ExpiredTime >= DateTime.Now) || knowledge.Status == EKnowledgeStatus.Auditing)
                throw UserFriendlyException.SameMessage("知识库数据不可删除");
            if (knowledge.Status == EKnowledgeStatus.Drafts || knowledge.Status == EKnowledgeStatus.Revert)
            {
                await _knowledgeRepository.RemoveAsync(knowledge, false, HttpContext.RequestAborted);
            }
            else
            {
                var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
                startDto.DefinitionModuleCode = WorkflowModuleConsts.KnowledgeDelete;
                startDto.Title = "知识库删除";
                //await _workflowApplication.StartWorkflowAsync(startDto, _sessionContext, knowledge.Id, cancellationToken: HttpContext.RequestAborted);
                await StartFlow(dto.Data.Id, WorkflowModuleConsts.KnowledgeDelete, EKnowledgeApplyType.Delete, startDto);
            }
        }

        /// <summary>
        /// 删除知识（new）
        /// </summary>
        [HttpDelete("remove")]
        [LogFilter("删除知识")]
        public async Task Remove([FromBody] DeleteKnowledgeDto dto)
        {
            var knowledge = await _knowledgeRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
            if (knowledge == null)
                throw UserFriendlyException.SameMessage("无效知识库数据");
            if ((knowledge.Status == EKnowledgeStatus.OnShelf && knowledge.ExpiredTime >= DateTime.Now) || knowledge.Status == EKnowledgeStatus.Auditing)
                throw UserFriendlyException.SameMessage("知识库数据不可删除");

            if (knowledge.Status == EKnowledgeStatus.Drafts || knowledge.Status == EKnowledgeStatus.Revert)
            {
                await _knowledgeRepository.RemoveAsync(knowledge, false, HttpContext.RequestAborted);
            }
            else
            {
                var exists = await _knowledgeApproRepository.Queryable()
                    .AnyAsync(d => d.KnowledgeId == dto.Id && d.KnowledgeApproveStatus == EKnowledgeApproveStatus.Unhandle,
                        HttpContext.RequestAborted);
                if (exists)
                    throw new UserFriendlyException($"该知识存在待审批申请, knId: {dto.Id}", "该知识存在待审批申请, 请先审批");

                await _knowledgeDomainService.AddKnowledgeApproveAsync(EKnowledgeApproveType.Delete, knowledge, dto.Opinion,
                    HttpContext.RequestAborted);
            }
        }

        /// <summary>
        /// 增加搜索量
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("search_num")]
        [LogFilter("知识搜索")]
        public async Task SearchNum([FromBody] KnowledgeSearchNumDto dto)
        {

            var knowledge = await _knowledgeRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
            if (knowledge == null)
                throw UserFriendlyException.SameMessage("无效知识库数据");
            knowledge.SearchNum++;
            await _knowledgeRepository.UpdateAsync(knowledge, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 搜索量列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("search_num/list")]
        public async Task<PagedDto<KnowledgeDto>> SearchNumList([FromQuery] KnowledgeCollectListDto dto)
        {
            var query = _knowledgeRepository.Queryable()
                .Where(x => x.Status == EKnowledgeStatus.OnShelf)
                .Where(x => (x.ExpiredTime != null && x.ExpiredTime >= DateTime.Now) || x.ExpiredTime == null)
                .OrderByIF(_appOptions.Value.IsZiGong == true, p => p.PageView, OrderByType.Desc)
                .OrderByIF(_appOptions.Value.IsZiGong == false, p => p.SearchNum, OrderByType.Desc);

            if (_sessionContext.OrgIsCenter == false)
            {
                query = query.Where(m => m.KnowledgeTypes.Any(a => a.IsDeleted == false && a.Orgs
                .Any(k => k.Id.StartsWith(_sessionContext.RequiredOrgId))));
                query = query.Where(m => m.Attribution == "部门知识库");
            }
            var (total, items) = await query.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<KnowledgeDto>(total, _mapper.Map<IReadOnlyList<KnowledgeDto>>(items));
        }

        /// <summary>
        /// 知识库-知识修改-查询详情
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        [Obsolete("请调用info/{Id}")]
        [HttpGet("updateinfo/{Id}")]
        public async Task<KnowledgeInfoDto> KnowledgeUpdateInfo(string Id)
        {
            //var know = await _knowledgeRepository.GetAsync(Id, HttpContext.RequestAborted);
            var know = await _knowledgeDomainService.KnowledgeInfo(Id, HttpContext.RequestAborted);
            if (know is null)
                throw UserFriendlyException.SameMessage("知识查询失败！");

            var knowledgeInfoDto = _mapper.Map<KnowledgeInfoDto>(know);
            if (knowledgeInfoDto != null && !string.IsNullOrEmpty(knowledgeInfoDto.Content))
                knowledgeInfoDto.Content = _bulletinApplication.GetSiteUrls(knowledgeInfoDto.Content);
            //分类
            //var type = await _knowledgeTypeRepository.GetAsync(know.KnowledgeTypeId, HttpContext.RequestAborted);
            //if (type != null)
            //	knowledgeInfoDto.KnowledgeTypeName = type.SpliceName;

            //热点
            var hot = await _hotspotTypeRepository.GetAsync(know.HotspotId, HttpContext.RequestAborted);
            if (hot != null)
                knowledgeInfoDto.HotspotName = hot.HotSpotFullName;
            //收藏
            var collect = await _knowledgeCollectRepository.GetAsync(x => x.KnowledgeId == Id && x.CreatorId == _sessionContext.UserId);
            if (collect != null)
                knowledgeInfoDto.Collect = _mapper.Map<KnowledgeCollectDto>(collect);

            return knowledgeInfoDto;
        }

        /// <summary>
        /// 知识库-查询详情-增加浏览量
        /// </summary>
        /// <param name="Id">知识Id</param>
        /// <param name="IsAddPv">默认不增加，false不增加，true增加浏览量</param>
        /// <returns></returns>
        [HttpGet("info/{Id}")]
        public async Task<KnowledgeDto> KnowledgeInfo(string Id, bool? IsAddPv)
        {
            var knowledge = await _knowledgeRepository.Queryable()
                .Includes(x => x.SourceOrganize)
                .Includes(x => x.KnowledgeTypes)
                .Includes(x => x.KnowledgeOrganizes)
                .Includes(x => x.HotspotType)
                .FirstAsync(p => p.Id == Id, HttpContext.RequestAborted);
            if (knowledge is null)
                throw UserFriendlyException.SameMessage("知识查询失败！");

            //转化
            var knowledgeShowInfoDto = _mapper.Map<KnowledgeDto>(knowledge);

            if (knowledgeShowInfoDto != null && !string.IsNullOrEmpty(knowledgeShowInfoDto.Content))
                knowledgeShowInfoDto.Content = _bulletinApplication.GetSiteUrls(knowledgeShowInfoDto.Content);

            //var type = await _knowledgeTypeRepository.GetAsync(knowledge.KnowledgeTypeId, HttpContext.RequestAborted);
            //if (type != null)
            //{
            //	knowledgeShowInfoDto.KnowledgeTypeName = type.SpliceName;
            //	knowledgeShowInfoDto.KnowledgeType = _mapper.Map<KnowledgeTypeDto>(type);
            //}
            //var hot = await _hotspotTypeRepository.GetAsync(knowledge.HotspotId, HttpContext.RequestAborted);
            //if (hot != null)
            //    knowledgeShowInfoDto.HotspotName = hot.HotSpotFullName;
            //收藏
            var collect = await _knowledgeCollectRepository.GetAsync(x => x.KnowledgeId == Id && x.CreatorId == _sessionContext.UserId);
            if (collect != null)
                knowledgeShowInfoDto.Collect = _mapper.Map<KnowledgeCollectDto>(collect);
            //关联知识
            var knowledges = await _knowledgeRepository.Queryable().In(x => x.Id, knowledge.Knowledges).Where(x => x.Status == EKnowledgeStatus.OnShelf && ((x.ExpiredTime != null && x.ExpiredTime >= DateTime.Now) || x.ExpiredTime == null)).ToListAsync();
            if (knowledges.Any())
                knowledgeShowInfoDto.KnowledgeDtos = _mapper.Map<List<KnowledgeDto>>(knowledges);
            //关键词
            var knowledgeWords = await _knowledgeWrodRepository.Queryable().In(x => x.Id, knowledge.Keywords).ToListAsync();
            if (knowledgeWords.Any())
                knowledgeShowInfoDto.KeywordsDto = _mapper.Map<List<KnowledgeWordDto>>(knowledgeWords);

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

            //var files = await _fileRepository.Queryable().Where(x => x.Key == knowledge.Id).ToListAsync();
            //         if (files.Any()) knowledgeShowInfoDto.Files = _mapper.Map<List<FileDto>>(files);

            if (IsAddPv == true)
                _mediator.Publish(new GetKnowledgeInfoNotify(knowledge));
            return knowledgeShowInfoDto;
        }

        /// <summary>
        /// 知识详情--导出
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("info/export")]
        [LogFilterAlpha("导出日志")]
        public async Task<IActionResult> KnowledgeInfoExport([FromBody] KnowledgeInfoExportInDto dto)
        {
            if (dto.Ids.Length > 1)
            {
                var streams = await _knowApplication.KnowledgeInfoListExportAsync(dto, HttpContext.RequestAborted);
                byte[] fileBytes = _wordHelperService.ConvertZipStream(streams);
                var name = DateTime.Now.ToString("yyyyMMddHHmmss");
                return File(fileBytes, "application/octet-stream", $"{name}.zip");
            }

            var info = await _knowledgeRepository.GetAsync(dto.Ids[0]) ?? throw UserFriendlyException.SameMessage("知识不存在");
            return info.Content.HtmlToStream(dto.FileType, info.Title, _pdfManager).GetFileStreamResult(dto.FileType, info.Title, false);
        }

        /// <summary>
        /// 知识申请-关联知识-获取知识列表
        /// </summary>
        /// <returns></returns>
        [HttpGet("getknowledge")]
        public async Task<IReadOnlyList<KnowledgeCreateBMDataDto>> GetKnowledge()
        {
            var temp = await _knowledgeRepository
               .Queryable()
               .LeftJoin<SystemOrganize>((o, sys) => o.CreatorOrgId == sys.Id)
               //重新构建数据
               .Select((o, sys) => new
               {
                   index = SqlFunc.RowNumber($"{o.Version} desc ", $"{o.Code}"),
                   DepartmentId = sys.Id,
                   Department = sys.Name,
                   o.Id,
                   o.Title,
                   o.Status,
                   o.Code,
                   o.IsDeleted,
                   o.ExpiredTime
               })
           //将结果合并成一个表
           .MergeTable()
           //取第一条数据
           .Where(x => x.IsDeleted == false)
           .Where(x => (x.ExpiredTime != null && x.ExpiredTime >= DateTime.Now) || x.ExpiredTime == null)
           .Where(d => d.index == 1 && d.Status == EKnowledgeStatus.OnShelf)
          .ToListAsync();
            //返回数据
            return _mapper.Map<IReadOnlyList<KnowledgeCreateBMDataDto>>(temp);

        }

        /// <summary>
        /// 我的草稿箱
        /// </summary>
        /// <param name="pagedDto"></param>
        /// <returns></returns>
        [HttpGet("mydraftslist")]
        public async Task<PagedDto<KnowledgeDataDto>> MyDraftsList([FromQuery] MyDraftsListPagedDto pagedDto)
        {
            var (total, items) = await _knowledgeRepository
             .Queryable()
             .Includes(it => it.User)
             .Where(p => p.CreatorId == _sessionContext.RequiredUserId && p.Status == EKnowledgeStatus.Drafts)
             .WhereIF(!string.IsNullOrEmpty(pagedDto.Keyword), d => d.Title.Contains(pagedDto.Keyword!))
             .WhereIF(pagedDto.StartTime != null, d => d.CreationTime >= pagedDto.StartTime)
             .WhereIF(pagedDto.EndTime != null, d => d.CreationTime <= pagedDto.EndTime)
             .OrderByDescending(p => p.CreationTime)
             .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize, HttpContext.RequestAborted);

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

        /// <summary>
        /// 知识库列表页面枚举值
        /// </summary>
        /// <returns></returns>
        [HttpGet("knowledge-status-data")]
        public Dictionary<string, dynamic> KnowledgeStatus()
        {
            var tabNames = new List<KeyValuePair<int, string>>
            {
                new KeyValuePair<int, string>(3, "已上架"),
                new KeyValuePair<int, string>(4, "已下架"),
                new KeyValuePair<int, string>(1, "审核中"),
                new KeyValuePair<int, string>(8, "草稿"),
                new KeyValuePair<int, string>(-1, "全部")
            };
            //var tabNames = EnumExts.GetDescriptions<EKnowledgeStatusRequest>();

            var tabNewDraftsNames = new List<KeyValuePair<int, string>>
            {
                new KeyValuePair<int, string>(-1, "全部"),
                new KeyValuePair<int, string>(0, "待提交"),
                new KeyValuePair<int, string>(5, "审核不通过"),
            };
            //var tabNewDraftsNames = EnumExts.GetDescriptions<EKnowledgeDraftTypeRequest>();


            var tabAuditingNames = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("", "全部"),
                new KeyValuePair<string, string>("add", "新增审核"),
                new KeyValuePair<string, string>("update", "修改审核"),
                new KeyValuePair<string, string>("delete", "删除审核"),
                new KeyValuePair<string, string>("offshelf", "下架审核"),
            };

            //return _baseDataApplication
            //    .FileType(EFileType.excel | EFileType.pdf)
            //    .Build();
            var ignoreFileType = EFileType.excel;//| EFileType.pdf;
            var items = EnumExts.GetDescriptions<EFileType>();
            var filteredDictionary = items
                 .Where(kvp => (ignoreFileType & (EFileType)kvp.Key) == 0)
                 .ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
                 .ToList();

            return new Dictionary<string, dynamic>
            {
                { "fileType", filteredDictionary},
                { "tabNames", tabNames },
                { "tabNewDraftsNames", tabNewDraftsNames },
                { "tabAuditingNames", tabAuditingNames }
            };
        }

        /// <summary>
        /// 知识查询
        /// </summary>
        /// <param name="pagedDto"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<PagedDto<KnowledgeDataDto>> GetKnowList([FromQuery] KnowPagedListDto pagedDto)
        {
            return (await _knowApplication.GetKnowList(pagedDto, HttpContext.RequestAborted))
                .ToPaged();
        }

        /// <summary>
        /// 知识查询-导出
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("export")]
        public async Task<IActionResult> GetKnowListExportAsync([FromBody] ExportExcelDto<KnowPagedListDto> dto)
        {
            var items = (await _knowApplication.GetKnowList(dto.QueryDto, HttpContext.RequestAborted)).Item2;
            return _exportApplication.GetExcelFile(dto, items, "知识明细导出");
        }

        /// <summary>
        /// 来电弹窗知识检索
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("knowretrieval")]
        public async Task<PagedDto<KnowledgeRetrievalDataDto>> KnowRetrievalWindow([FromBody] KnowledgeRetrievalPagedListDto dto)
        {
            return (await _knowApplication.KnowRetrievalAsync(dto)).ToPaged();
        }

        /// <summary>
        /// 知识检索
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("knowretrieval")]
        public async Task<PagedDto<KnowledgeRetrievalDataDto>> KnowRetrieval([FromQuery] KnowledgeRetrievalPagedListDto dto)
        {
            return (await _knowApplication.KnowRetrievalAsync(dto)).ToPaged();
        }

        /// <summary>
        /// 知识检索页面基础数据
        /// </summary>
        /// <returns></returns>
        [HttpGet("knowretrieval/base_data")]
        public Dictionary<string, dynamic> GetKnowretrievalBaseData()
        {
            //return _baseDataApplication
            //    .KnowledgeRetrievalType(new[] { 3, 4 })
            //    .Build();
            var ignoreFileType = new[] { 3, 4 };
            return new Dictionary<string, dynamic>
            {
                { "knowledgeRetrievalType", EnumExts.GetDescriptions<EKnowledgeRetrievalType>().Where(m => !ignoreFileType.Contains(m.Key)).ToList() }
            };
        }

        /// <summary>
        /// 获取知识审批信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("audit_log")]
        public async Task<PagedDto<KnowledgeWorkFlowDto>> KnowRetrieval([FromQuery] AuditLogListPagedDto pagedDto)
        {
            var (total, temp) = await _knowledgeWorkFlowRepository
                .Queryable()
                .Includes(x => x.User)
                .Includes(x => x.SystemOrganize)
                .Includes(x => x.Workflow)
                .Where(x => x.KnowledgeId == pagedDto.id)
                .Where(x => x.IsDeleted == false)
                .OrderBy(x => x.CreationTime)
                .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize);
            return new PagedDto<KnowledgeWorkFlowDto>(total, _mapper.Map<IReadOnlyList<KnowledgeWorkFlowDto>>(temp));
        }

        /// <summary>
        /// 知识查重
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpPost("finding_duplicate")]

        public async Task<bool> FindingDuplicate([FromBody] KnowledgeFindingDuplicateDto dto)
        {
            var any = await _knowledgeRepository.Queryable().Where(x => x.Status == EKnowledgeStatus.Auditing || x.Status >= EKnowledgeStatus.OnShelf)
                .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title.Equals(dto.Title))
                .WhereIF(!string.IsNullOrEmpty(dto.Summary), x => x.Summary.Equals(dto.Summary))
                .WhereIF(!string.IsNullOrEmpty(dto.Content), x => x.Content.Equals(dto.Content))
                .WhereIF(!string.IsNullOrEmpty(dto.Id), x => x.Id != dto.Id)
                .AnyAsync();
            return any;
        }

        /// <summary>
        /// 下载知识导入模板（new）
        /// </summary>
        /// <returns></returns>
        [HttpGet("dl-template")]
        public IActionResult DownLoadKnowledgeTemplate()
        {
            return _exportApplication.ExportData(new List<KnowledgeImportTemplate>
            {
                new ()
            }, "知识模板.xlsx");
        }

        /// <summary>
        /// 导入知识(new)
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        [HttpPost("import-knowledge")]
        public async Task<string> ImportKnowledge(IFormFile file)
        {
            using var stream = new MemoryStream();
            await file.CopyToAsync(stream);
            var items = stream.Query<KnowledgeImportTemplate>().ToList();
            if (items == null || !items.Any()) throw new UserFriendlyException("未读取到数据");

            if (items.Any(d => d.Attribution != "中心知识库" && d.Attribution != "部门知识库"))
                throw UserFriendlyException.SameMessage("请正确输入知识归属");
            if (items.Any(d => !string.IsNullOrEmpty(d.IsPublic) && d.IsPublic != "是" && d.IsPublic != "否"))
                throw UserFriendlyException.SameMessage("请正确输入是否公开");
            if (items.Any(d => string.IsNullOrEmpty(d.Title)))
                throw UserFriendlyException.SameMessage("请输入标题");
            if (items.Any(d => string.IsNullOrEmpty(d.Content)))
                throw UserFriendlyException.SameMessage("请输入内容");

            var titles = items.Select(d => d.Title).ToList();
            var exists = await _knowledgeRepository.Queryable()
                .Where(d => titles.Contains(d.Title))
                .ToListAsync(HttpContext.RequestAborted);
            if (exists.Any())
                throw UserFriendlyException.SameMessage($"重复标题：{string.Join(',', exists.Select(d => d.Title))}");

            var inputLevelOneTypes = items.Select(d => d.KnowledgeTypeLevelOne)
                .Distinct().ToList();
            var levelOneTypes = await _knowledgeTypeRepository.Queryable()
                .Where(d => d.IsEnable && string.IsNullOrEmpty(d.ParentId))
                .ToListAsync(HttpContext.RequestAborted);
            var existLevelOneNames = levelOneTypes.Select(d => d.Name);
            var notExists = inputLevelOneTypes.Except(existLevelOneNames).ToList();
            if (notExists.Any())
                throw UserFriendlyException.SameMessage($"不存在的一级分类名称：{string.Join(',', notExists)}");

            var sb = new StringBuilder();
            var kns = new List<Knowledge>();
            foreach (var item in items)
            {
                var kn = _mapper.Map<Knowledge>(item);
                kn.SourceOrganizeId = _sessionContext.RequiredOrgId;
                var knType = levelOneTypes.FirstOrDefault(d => d.Name == item.KnowledgeTypeLevelOne);
                if (knType is null)
                {
                    sb.Append($"错误一级分类：{item.KnowledgeTypeLevelOne}");
                    continue;
                }
                kn.KnowledgeTypes = new List<KnowledgeType> { knType };
                kn.IsPublic = item.IsPublic == "是";
                kns.Add(kn);
            }

            await _knowledgeRepository.AddNav(kns)
                .Include(d => d.KnowledgeTypes)
                .ExecuteCommandAsync();

            var err = sb.ToString();
            return string.IsNullOrEmpty(err)
                ? $"导入{items.Count}条，成功{kns.Count}条"
                : $"导入{items.Count}条，成功{kns.Count}条，{err}";
        }

        /// <summary>
        /// 导出知识（new）
        /// </summary>
        [HttpGet("export-knowledge")]
        public async Task<IActionResult> ExportKnowledge([FromQuery] ExportKnowledgeRequest request)
        {
            if (string.IsNullOrEmpty(request.Id))
                throw new UserFriendlyException("无效知识编号");
            var kn = await _knowledgeRepository.GetAsync(request.Id, HttpContext.RequestAborted);
            if (kn is null)
                throw new UserFriendlyException("无效知识编号");
            var content = kn.Content
                  .Replace("&nbsp;", " ")
                  .Replace("&amp;", "&")
                  .Replace("&quot;", "\"")
                  .Replace("&gt;", ">")
                  .Replace("&lt;", "<")
                  ;


            switch (request.ExportType)
            {
                case "pdf":
                    var fileName = $"{kn.Title}.pdf";
                    var stream = new MemoryStream();
                    _pdfManager.GeneratePdf(kn.Title, content, stream);
                    stream.Seek(0, SeekOrigin.Begin);
                    return new FileStreamResult(stream, "application/pdf")
                    {
                        FileDownloadName = fileName ?? DateTime.Now.ToString("yyyyMMddhhmmss") + ".pdf"
                    };

                    break;
            }


            return null;
        }

        #endregion

        #region 我的知识删除列表
        /// <summary>
        /// 我的知识删除列表页面枚举值
        /// </summary>
        /// <returns></returns>
        [HttpGet("delete-status-data")]
        public async Task<object> DeleteApplyStatus()
        {
            return EnumExts.GetDescriptions<EKnowledgeWorkFlowStatus>();
        }

        /// <summary>
        /// 我的知识删除列表
        /// </summary>
        /// <param name="pagedDto"></param>
        /// <returns></returns>
        [HttpGet("deletelist")]
        public async Task<PagedDto<KnowledgeDeleteApplyDataDto>> GetDeleteApplyList([FromQuery] KnowledgeDeletelPagedListDto pagedDto)
        {
            var (total, items) = await _knowledgeWorkFlowRepository
               .Queryable(includeDeleted: true)
               .Includes(it => it.Knowledge)
               .Includes(it => it.User)
               .Includes(it => it.SystemOrganize)
               .Includes(it => it.Knowledge, it => it.KnowledgeType)
               .Includes(it => it.Knowledge, it => it.HotspotType)
               .Includes(it => it.Workflow)
               .Where(d => d.CreatorId == _sessionContext.RequiredUserId && d.WorkflowModuleStatus == EKnowledgeApplyType.Delete && d.WorkflowId != null)
               .WhereIF(pagedDto.EKnowledgeWorkFlowStatus.HasValue, d => d.WorkFlowApplyStatus == pagedDto.EKnowledgeWorkFlowStatus)
               .WhereIF(pagedDto.StartApplyTime.HasValue, d => d.CreationTime >= pagedDto.StartApplyTime)
               .WhereIF(pagedDto.EndApplyTime.HasValue, d => d.CreationTime <= pagedDto.EndApplyTime)
               .WhereIF(!string.IsNullOrEmpty(pagedDto.Keyword), d => d.Knowledge.User.Name.Contains(pagedDto.Keyword!)
               || d.Knowledge.SystemOrganize.Name.Contains(pagedDto.Keyword!)
               || d.Knowledge.Title.Contains(pagedDto.Keyword!))

               .OrderByDescending(p => p.CreationTime)
               .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize, HttpContext.RequestAborted);

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

        /// <summary>
        /// 审核管理页面枚举值
        /// </summary>
        /// <returns></returns>
        [HttpGet("approval-base-data")]
        public async Task<object> ApprovalBaseData()
        {
            return new
            {
                EKnowledgeWorkFlowStatus = EnumExts.GetDescriptions<EKnowledgeWorkFlowStatus>(),
                EKnowledgeApplyType = EnumExts.GetDescriptions<EKnowledgeApplyType>()
            };
        }

        /// <summary>
        /// 审核管理
        /// </summary>
        /// <param name="pagedDto"></param>
        /// <returns></returns>
        [HttpGet("approvedlist")]
        public async Task<PagedDto<KnowledgeApprovalDataDto>> ApprovedList([FromQuery] KnowledgeApprovalPagedListDto pagedDto)
        {
            var (total, items) = await _knowledgeWorkFlowRepository
                .Queryable(includeDeleted: true)
                .Includes(it => it.Knowledge)
                .Includes(it => it.User)
                .Includes(it => it.SystemOrganize)
                .Includes(it => it.Workflow, d => d.Steps)
                .Where(it => it.WorkflowId != null)
                .WhereIF(pagedDto.EKnowledgeApplyType.HasValue, d => d.WorkflowModuleStatus == pagedDto.EKnowledgeApplyType)
                .WhereIF(pagedDto.EKnowledgeWorkFlowStatus.HasValue, d => d.WorkFlowApplyStatus == pagedDto.EKnowledgeWorkFlowStatus)
                .WhereIF(!string.IsNullOrEmpty(pagedDto.Keyword), d => d.Knowledge.User.Name.Contains(pagedDto.Keyword!)
                || d.Knowledge.SystemOrganize.Name.Contains(pagedDto.Keyword!)
                || d.Knowledge.Title.Contains(pagedDto.Keyword!))

                .OrderByDescending(p => p.CreationTime)
                .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize, HttpContext.RequestAborted);

            foreach (var item in items)
            {
                if (item.Workflow != null)
                    //item.CanHandle = item.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
                    item.CanHandle = item.Workflow.IsCanHandle(
                        _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles);

            }
            //处理是否可以办理
            //items.ForEach(d => d.CanHandle = d.Workflow.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgCode));

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

        /// <summary>
        /// 工单受理知识检索
        /// </summary>
        /// <param name="pagedDto"></param>
        /// <returns></returns>
        [HttpGet("knowpopscreen")]
        public async Task<PagedDto<KnowledgeRetrievalDataDto>> KnowPopScreen([FromQuery] KnowledgePopScreenPagedListDto pagedDto)
        {
            var orgid = string.Empty;
            if (pagedDto.RetrievalType == EKnowledgeRetrievalType.Org && !string.IsNullOrEmpty(pagedDto.Keyword))
            {
                var organize = await _systemOrganizeRepository.GetAsync(x => x.Name == pagedDto.Keyword);
                orgid = organize?.Id;
            }
            var (total, temp) = await _knowledgeRepository.Queryable()
                .Includes(x => x.SourceOrganize)
               .Where(d => d.Status == EKnowledgeStatus.OnShelf)
               .WhereIF(pagedDto.RetrievalType == EKnowledgeRetrievalType.Title && !string.IsNullOrEmpty(pagedDto.Keyword), d => d.Title.Contains(pagedDto.Keyword!))
               .WhereIF(pagedDto.RetrievalType == EKnowledgeRetrievalType.Content && !string.IsNullOrEmpty(pagedDto.Keyword), d => d.Content.Contains(pagedDto.Keyword!))
               .WhereIF(!string.IsNullOrEmpty(orgid) && pagedDto.RetrievalType == EKnowledgeRetrievalType.Org, x => x.CreatorOrgId.EndsWith(orgid!))
               .WhereIF(!string.IsNullOrEmpty(pagedDto.HotspotId), p => p.HotspotId == pagedDto.HotspotId)
               .OrderByDescending(p => p.CreationTime)
               .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize);
            return new PagedDto<KnowledgeRetrievalDataDto>(total, _mapper.Map<IReadOnlyList<KnowledgeRetrievalDataDto>>(temp));
        }

        ///// <summary>
        ///// 新增-开始流程
        ///// </summary>
        ///// <param name="id">知识id</param>
        ///// <param name="dto">流程开启参数</param>
        ///// <returns></returns>
        //[HttpPost("{id}/add-startflow")]
        //public async Task AddStartFlow(string id, [FromBody] StartWorkflowDto dto)
        //{
        //	await StartFlow(id, WorkflowModuleConsts.AddKnowledgeAsync, EKnowledgeApplyType.Add, dto);
        //}

        ///// <summary>
        ///// 删除-开始流程
        ///// </summary>
        ///// <param name="id">知识id</param>
        ///// <param name="dto">流程开启参数</param>
        ///// <returns></returns>
        //[HttpPost("{id}/remove-startflow")]
        //public async Task RemoveStartFlow(string id, [FromBody] StartWorkflowDto dto)
        //{
        //	await StartFlow(id, WorkflowModuleConsts.KnowledgeDelete, EKnowledgeApplyType.Delete, dto);
        //}

        /// <summary>
        /// 查询知识库办理流程开启参数-新增
        /// </summary>
        /// <returns></returns>
        [HttpGet("add-flow-start")]
        public async Task<NextStepsDto> GetAddFlowStartOptionsAsync()
        {
            return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.KnowledgeAdd,
                HttpContext.RequestAborted);
        }

        /// <summary>
        /// 查询知识库办理流程开启参数-新增
        /// </summary>
        /// <returns></returns>
        [HttpGet("update-flow-start")]
        public async Task<NextStepsDto> GetUpdateFlowStartOptionsAsync()
        {
            return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.KnowledgeUpdate,
                HttpContext.RequestAborted);
        }

        /// <summary>
        /// 查询知识库办理流程开启参数-删除
        /// </summary>
        /// <returns></returns>
        [HttpGet("remove-flow-start")]
        public async Task<NextStepsDto> GetRemoveFlowStartOptionsAsync()
        {
            return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.KnowledgeDelete,
                HttpContext.RequestAborted);
        }

        /// <summary>
        /// 查询知识库办理流程开启参数-下架
        /// </summary>
        /// <returns></returns>
        [HttpGet("offshelf-flow-start")]
        public async Task<NextStepsDto> GetOffshelfFlowStartOptionsAsync()
        {
            return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.KnowledgeOffshelf,
                HttpContext.RequestAborted);
        }

        /// <summary>
        /// 开始流程
        /// </summary>
        /// <param name="id">知识ID</param>
        /// <param name="moduleCode">知识模板编号</param>
        /// <param name="eKnowledgeApplyType">申请类型</param>
        /// <param name="dto">流程开启参数</param>
        /// <returns></returns>
        private async Task<string> StartFlow(string id, string moduleCode, EKnowledgeApplyType eKnowledgeApplyType, StartWorkflowDto dto)
        {
            var knowledge = await _knowledgeRepository.GetAsync(id, HttpContext.RequestAborted);
            if (knowledge == null)
                throw UserFriendlyException.SameMessage("无效知识编号");

            if (eKnowledgeApplyType == EKnowledgeApplyType.Delete)
            {
                if (knowledge.IsDeleted == true)
                    throw UserFriendlyException.SameMessage("知识删除失败");
            }

            //知识审批主表
            await _knowledgeDomainService.AddWorkFlowAsync(id, eKnowledgeApplyType, HttpContext.RequestAborted);

            dto.DefinitionModuleCode = moduleCode;
            //dto.Title = knowledge.Title;
            //return await _workflowApplication.StartWorkflowAsync(dto, id, cancellationToken: HttpContext.RequestAborted);
            // var result = await _workflowDomainService.StartAsync(dto, id, cancellationToken: HttpContext.RequestAborted);
            var result = await _workflowDomainService.StartToFirstStepAsync(dto, id, cancellationToken: HttpContext.RequestAborted);
            return result.First().WorkflowId;
        }
        #endregion

        #region 知识库词库
        /// <summary>
        /// 新增知识库词库
        /// </summary>
        /// <param name="dtos"></param>
        /// <returns></returns>
        [HttpPost("knowledge_word")]
        [LogFilter("新增知识库词库")]
        public async Task Add([FromBody] KnowledgeWordAddDto dto)
        {
            var word = _mapper.Map<KnowledgeWord>(dto);
            await _knowledgeWrodRepository.AddAsync(word, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 删除知识库词库
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpDelete("knowledge_word")]
        [LogFilter("删除知识库词库")]
        public async Task Delete([FromBody] KnowledgeWordDeleteDto dto)
        {
            await _knowledgeRepository.RemoveKnowledgeWrodBatchAsync(dto.Ids, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 更新知识库词库
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("knowledge_word")]
        [LogFilter("更新知识库词库")]
        public async Task Update([FromBody] KnowledgeWordUpdateDto dto)
        {
            var word = await _knowledgeWrodRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
            if (word is null)
                throw UserFriendlyException.SameMessage("无效知识库词库");
            _mapper.Map(dto, word);
            word.LastModificationName = _sessionContext.UserName;
            await _knowledgeWrodRepository.UpdateAsync(word, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 获取知识库词库列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("knowledge_word/list")]
        public async Task<PagedDto<KnowledgeWordDto>> List([FromQuery] KnowledgeWordListDto dto)
        {
            var (total, items) = await _knowledgeWrodRepository.Queryable()
                .WhereIF(!string.IsNullOrEmpty(dto.Tag), x => x.Tag == dto.Tag!)
                .WhereIF(!string.IsNullOrEmpty(dto.Classify), x => x.Classify == dto.Classify!)
                .WhereIF(dto.IsEnable.HasValue, x => x.IsEnable == dto.IsEnable)
                .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<KnowledgeWordDto>(total, _mapper.Map<IReadOnlyList<KnowledgeWordDto>>(items));
        }

        /// <summary>
        /// 获取知识库词库
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("knowledge_word/{id}")]
        public async Task<KnowledgeWord> WordEntity(string id)
        {
            return await _knowledgeWrodRepository.Queryable()
                .FirstAsync(x => x.Id == id);
        }

        /// <summary>
        /// 获取知识库词库基本信息
        /// </summary>
        /// <returns></returns>
        [HttpGet("knowledge_word/base")]
        public async Task<object> Base()
        {
            var rsp = new
            {
                KnowledgeWordClassify = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.KnowledgeWordClassify),
            };
            return rsp;
        }
        #endregion

        #region 知识纠错
        /// <summary>
        /// 新增知识纠错
        /// </summary>
        /// <param name="dtos"></param>
        /// <returns></returns>
        [HttpPost("knowledge_correction")]
        [LogFilter("新增知识纠错")]
        public async Task Add([FromBody] KnowledgeCorrectionAddDto dto)
        {
            var correction = _mapper.Map<KnowledgeCorrection>(dto);
            await _knowledgeCorrectionRepository.AddAsync(correction, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 删除知识纠错
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        //[HttpDelete("knowledge_correction")]
        //public async Task Delete([FromBody] KnowledgeCorrectionDeleteDto dto)
        //{
        //	await _knowledgeCorrectionRepository.RemoveAsync(x => x.Id == dto.Id);
        //}

        /// <summary>
        /// 更新知识纠错
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        //[HttpPut("knowledge_correction")]
        //public async Task Update([FromBody] KnowledgeCorrectionUpdateDto dto)
        //{
        //	var correction = await _knowledgeCorrectionRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        //	if (correction is null)
        //		throw UserFriendlyException.SameMessage("无效知识纠错");
        //	_mapper.Map(dto, correction);
        //	await _knowledgeCorrectionRepository.UpdateAsync(correction, HttpContext.RequestAborted);
        //}

        /// <summary>
        /// 答复知识纠错
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("knowledge_correction/Reply")]
        [LogFilter("答复知识纠错")]
        public async Task Reply([FromBody] KnowledgeCorrectionUpdateDto dto)
        {
            var correction = await _knowledgeCorrectionRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
            if (correction is null)
                throw UserFriendlyException.SameMessage("无效知识纠错");
            _mapper.Map(dto, correction);
            correction.ReplyTime = DateTime.Now;
            correction.ReplyUserName = _sessionContext.UserName;
            correction.State = ECorrectionState.AlreadyAnswered;
            await _knowledgeCorrectionRepository.UpdateAsync(correction, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 获取知识纠错列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("knowledge_correction/list")]
        public async Task<PagedDto<KnowledgeCorrectionDto>> List([FromQuery] KnowledgeCorrectionListDto dto)
        {
            var typeSpliceName = string.Empty;
            if (!string.IsNullOrEmpty(dto.KnowledgeTypeId))
            {
                var type = await _knowledgeTypeRepository.GetAsync(x => x.Id == dto.KnowledgeTypeId);
                typeSpliceName = type?.SpliceName;
            }
            var (total, items) = await _knowledgeCorrectionRepository.Queryable(includeDeleted: true)
                .Includes(x => x.Knowledge)
                .Where(m => m.IsDeleted == false && m.Knowledge.IsDeleted == false)
                //.WhereIF(!string.IsNullOrEmpty(dto.KnowledgeTypeId), x => x.Knowledge.KnowledgeTypeId == dto.KnowledgeTypeId!)
                .WhereIF(!string.IsNullOrEmpty(dto.CreatorName), x => x.CreatorName == dto.CreatorName!)
                 //.WhereIF(!string.IsNullOrEmpty(typeSpliceName), x => SqlFunc.JsonLike(x.Knowledge.KnowledgeType, typeSpliceName))
                 .WhereIF(!string.IsNullOrEmpty(typeSpliceName), x => x.Knowledge.KnowledgeType.Any(t => t.KnowledgeTypeSpliceName.EndsWith(typeSpliceName)))
                .Where(x => !string.IsNullOrEmpty(x.Knowledge.Id))
                .OrderByDescending(x => x.CreationTime)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<KnowledgeCorrectionDto>(total, _mapper.Map<IReadOnlyList<KnowledgeCorrectionDto>>(items));
        }

        /// <summary>
        /// 获取知识库纠错
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("knowledge_correction/{id}")]
        public async Task<KnowledgeCorrection> CorrectionEntity(string id)
        {
            return await _knowledgeCorrectionRepository.Queryable()
                .Includes(x => x.Knowledge)
                .FirstAsync(x => x.Id == id);
        }
        #endregion

        #region 知识提问
        /// <summary>
        /// 新增知识提问
        /// </summary>
        /// <param name="dtos"></param>
        /// <returns></returns>
        [HttpPost("knowledge_questions")]
        [LogFilter("新增知识提问")]
        public async Task Add([FromBody] KnowledgeQuestionsAddDto dto)
        {
            var questions = _mapper.Map<KnowledgeQuestions>(dto);
            await _knowledgeQuestionsRepository.AddAsync(questions, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 删除知识提问
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        //[HttpDelete("knowledge_questions")]
        //public async Task Delete([FromBody] KnowledgeQuestionsDeleteDto dto)
        //{
        //	await _knowledgeQuestionsRepository.RemoveAsync(x => x.Id == dto.Id);
        //}

        /// <summary>
        /// 更新知识提问
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        //[HttpPut("knowledge_questions")]
        //public async Task Update([FromBody] KnowledgeQuestionsUpdateDto dto)
        //{
        //	var questions = await _knowledgeQuestionsRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
        //	if (questions is null)
        //		throw UserFriendlyException.SameMessage("无效知识提问");
        //	_mapper.Map(dto, questions);
        //	await _knowledgeQuestionsRepository.UpdateAsync(questions, HttpContext.RequestAborted);
        //}

        /// <summary>
        /// 答复知识提问
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("knowledge_questions/Reply")]
        [LogFilter("答复知识提问")]
        public async Task Reply([FromBody] KnowledgeQuestionsUpdateDto dto)
        {
            var questions = await _knowledgeQuestionsRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
            if (questions is null)
                throw UserFriendlyException.SameMessage("无效知识提问");
            _mapper.Map(dto, questions);
            questions.ReplyTime = DateTime.Now;
            questions.ReplyUserName = _sessionContext.UserName;
            questions.State = ECorrectionState.AlreadyAnswered;
            await _knowledgeQuestionsRepository.UpdateAsync(questions, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 获取知识提问列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("knowledge_questions/list")]
        public async Task<PagedDto<KnowledgeQuestionsDto>> List([FromQuery] KnowledgeQuestionsListDto dto)
        {
            var typeSpliceName = string.Empty;
            if (!string.IsNullOrEmpty(dto.KnowledgeTypeId))
            {
                var type = await _knowledgeTypeRepository.GetAsync(x => x.Id == dto.KnowledgeTypeId);
                typeSpliceName = type?.SpliceName;
            }
            var (total, items) = await _knowledgeQuestionsRepository.Queryable()
                .Includes(x => x.Knowledge)
               //.WhereIF(!string.IsNullOrEmpty(dto.KnowledgeTypeId), x => x.Knowledge.KnowledgeTypeId == dto.KnowledgeTypeId!)
               //.WhereIF(!string.IsNullOrEmpty(typeSpliceName), x => SqlFunc.JsonLike(x.Knowledge.KnowledgeType, typeSpliceName))
               .WhereIF(!string.IsNullOrEmpty(typeSpliceName), x => x.Knowledge.KnowledgeType.Any(t => t.KnowledgeTypeSpliceName.EndsWith(typeSpliceName)))
                .WhereIF(!string.IsNullOrEmpty(dto.CreatorName), x => x.CreatorName == dto.CreatorName!)
                .Where(x => !string.IsNullOrEmpty(x.Knowledge.Id))
                .OrderByDescending(x => x.CreationTime)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<KnowledgeQuestionsDto>(total, _mapper.Map<IReadOnlyList<KnowledgeQuestionsDto>>(items));
        }

        /// <summary>
        /// 获取知识提问
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("knowledge_questions/{id}")]
        public async Task<KnowledgeQuestions> QuestionsEntity(string id)
        {
            return await _knowledgeQuestionsRepository.Queryable()
                .Includes(x => x.Knowledge)
                .FirstAsync(x => x.Id == id);
        }

        #endregion

        #region 知识收藏
        /// <summary>
        /// 知识收藏列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("knowledge_collect/list")]
        public async Task<PagedDto<KnowledgeCollectDto>> List([FromQuery] KnowledgeCollectListDto dto)
        {
            var (total, items) = await _knowledgeCollectRepository.Queryable()
                .Includes(x => x.Knowledge)
                .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Knowledge.Title.Contains(dto.Keyword!) || (x.Knowledge.Summary != null && x.Knowledge.Summary.Contains(dto.Keyword!)))
                .WhereIF(dto.KnowledgeCollectGroupId.NotNullOrEmpty(), x => x.KnowledgeCollectGroupId == dto.KnowledgeCollectGroupId)
                .Where(x => x.CreatorId == _sessionContext.UserId)
                .Where(x => !string.IsNullOrEmpty(x.Knowledge.Id))
                .Where(x => x.Collect!.Value)
                .OrderByDescending(x => x.CreationTime)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<KnowledgeCollectDto>(total, _mapper.Map<IReadOnlyList<KnowledgeCollectDto>>(items));
        }

        /// <summary>
        /// 新增知识收藏
        /// </summary>
        /// <param name="dtos"></param>
        /// <returns></returns>
        [HttpPost("knowledge_collect")]
        [LogFilter("知识收藏")]
        public async Task Add([FromBody] KnowledgeCollectAddDto dto)
        {
            var collect = await _knowledgeCollectRepository.GetAsync(x => x.KnowledgeId == dto.KnowledgeId && x.CreatorId == _sessionContext.UserId);
            if (collect != null)
            {
                collect.Collect = dto.Collect;
                await _knowledgeCollectRepository.UpdateAsync(collect, HttpContext.RequestAborted);
            }
            else
            {
                var collectNew = _mapper.Map<KnowledgeCollect>(dto);
                await _knowledgeCollectRepository.AddAsync(collectNew, HttpContext.RequestAborted);
            }
            var count = await _knowledgeCollectRepository.Queryable()
                .Where(m => m.KnowledgeId == dto.KnowledgeId && m.Collect == true).CountAsync();

            await _knowledgeRepository.Updateable()
                .Where(m => m.Id == dto.KnowledgeId)
                .SetColumns(m => m.CollectCount == count)
                .ExecuteCommandAsync();
        }

        /// <summary>
        /// 知识评分
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpDelete("knowledge_score")]
        [LogFilter("知识评分")]
        public async Task Delete([FromBody] KnowledgeCollectAddDto dto)
        {
            var collect = await _knowledgeCollectRepository.GetAsync(x => x.KnowledgeId == dto.KnowledgeId && x.CreatorId == _sessionContext.UserId);
            if (collect != null)
            {
                if (collect.Score > 0)
                    throw UserFriendlyException.SameMessage("当前知识已经评分");
                collect.Score = dto.Score;
                await _knowledgeCollectRepository.UpdateAsync(collect, HttpContext.RequestAborted);
            }
            else
            {
                var questions = _mapper.Map<KnowledgeCollect>(dto);
                await _knowledgeCollectRepository.AddAsync(questions, HttpContext.RequestAborted);
            }
            //计算总分
            var sugar = _knowledgeCollectRepository.Queryable().Where(x => x.KnowledgeId == dto.KnowledgeId);
            var count = await sugar.CountAsync();
            var collects = await sugar.SumAsync(x => x.Score);
            var score = collects / count;
            var knowledge = await _knowledgeRepository.GetAsync(x => x.Id == dto.KnowledgeId);
            if (knowledge != null)
            {
                knowledge.Score = decimal.Round(score.Value, 1);
                await _knowledgeRepository.UpdateAsync(knowledge, HttpContext.RequestAborted);
            }
        }
        #endregion

        #region 知识评论

        /// <summary>
        /// 新增知识评论
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("knowledge_comment")]
        public async Task Add([FromBody] KnowledgeCommentAddDto dto)
        {
            var model = _mapper.Map<KnowledgeComment>(dto);
            await _knowledgeCommentRepository.AddAsync(model, HttpContext.RequestAborted);
            if (!string.IsNullOrEmpty(dto.ReplyId))
            {
                var comment = await _knowledgeCommentRepository.GetAsync(dto.ReplyId);
                if (comment != null)
                {
                    comment.ReplyNum++;
                    await _knowledgeCommentRepository.UpdateAsync(comment, HttpContext.RequestAborted);
                }
            }
        }

        /// <summary>
        /// 删除知识评论
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpDelete("knowledge_comment")]
        public async Task Delete([FromBody] KnowledgeCommentDeleteDto dto)
        {
            var comment = await _knowledgeCommentRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
            if (comment is null)
                throw UserFriendlyException.SameMessage("无效评论");
            if (comment.CreatorId != _sessionContext.UserId)
                throw UserFriendlyException.SameMessage("只有评论者可以删除当前评论");
            await _knowledgeCommentRepository.RemoveAsync(x => x.Id == dto.Id);
        }

        /// <summary>
        /// 修改知识评论
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("knowledge_comment")]
        public async Task Update([FromBody] KnowledgeCommentUpdateDto dto)
        {
            var comment = await _knowledgeCommentRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
            if (comment is null)
                throw UserFriendlyException.SameMessage("无效评论");
            _mapper.Map(dto, comment);
            await _knowledgeCommentRepository.UpdateAsync(comment, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 知识评论列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("knowledge_comment/list")]
        public async Task<List<KnowledgeCommentDto>> List([FromQuery] KnowledgeCommentListDto dto)
        {
            var comments = await _knowledgeCommentRepository.Queryable()
                .WhereIF(!string.IsNullOrEmpty(dto.KnowledgeId), x => x.KnowledgeId == dto.KnowledgeId)
                .WhereIF(!string.IsNullOrEmpty(dto.ReplyId), x => x.ReplyId == dto.ReplyId)
                .WhereIF(dto.All.HasValue && dto.All == false, x => x.CreatorId == _sessionContext.UserId)
                .OrderByDescending(x => x.CreationTime)
                .ToListAsync();
            return new List<KnowledgeCommentDto>(_mapper.Map<IReadOnlyList<KnowledgeCommentDto>>(comments));
        }
        #endregion

        #region 收藏分组

        /// <summary>
        /// 增加收藏分组
        /// </summary>
        [HttpPost("group")]
        public async Task<KnowledgeCollectGroupOutDto> SaveKnowledgeCoolectGroupAsync([FromBody] KnowledgeCollectGroupInDto dto)
        {
            var entity = dto.Adapt<KnowledgeCollectGroup>();
            if (await _knowledgeCollectGroupRepository
                .Queryable()
                .Where(m => m.Name == dto.Name && m.CreatorId == _sessionContext.UserId)
                .AnyAsync() == true) throw UserFriendlyException.SameMessage("分组名重复, 请重新输入!");

            var key = await _knowledgeCollectGroupRepository.AddAsync(entity);
            if (key.IsNullOrEmpty()) throw UserFriendlyException.SameMessage("添加失败, 请重试");
            var outDto = dto.Adapt<KnowledgeCollectGroupOutDto>();
            outDto.Id = key;
            return outDto;
        }

        /// <summary>
        /// 删除收藏分组
        /// </summary>
        [HttpDelete("group")]
        public async Task DeleteKnowledgeCoolectGroupAsync([FromQuery] string id)
        {
            var entity = await _knowledgeCollectGroupRepository.Queryable()
                .Where(m => m.Id == id && m.CreatorId == _sessionContext.UserId)
                .FirstAsync() ?? throw new UserFriendlyException("数据不存在");

            entity.IsDeleted = true;
            await _knowledgeCollectGroupRepository.UpdateAsync(entity);
            await _knowledgeCollectRepository.Updateable()
                .Where(m => m.KnowledgeCollectGroupId == id && m.CreatorId == _sessionContext.UserId)
                .SetColumns(m => m.IsDeleted == true)
                .ExecuteCommandAsync();
        }

        /// <summary>
        /// 获取分组收藏列表
        /// </summary>
        /// <returns></returns>
        [HttpGet("group")]
        public async Task<PagedDto<KnowledgeCollectGroupOutDto>> GetKnowledgeCollectGroupListAsync([FromQuery] KnowledgeCollectGroupListInDto dto)
        {
            return (await _knowledgeCollectGroupRepository.Queryable()
                .WhereIF(dto.Keyword.NotNullOrEmpty(), m => m.Name.Contains(dto.Keyword))
                .Where(m => m.CreatorId == _sessionContext.UserId)
                .Select<KnowledgeCollectGroupOutDto>()
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted)
                ).ToPaged();
        }
        #endregion

        #region PageView 浏览记录
        /// <summary>
        /// 浏览记录集合
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("pageview")]
        public async Task<PagedDto<PageViewOutDto>> GetPageViewListAsync([FromQuery] PageViewInDto dto)
        {
            return (await _knowApplication.GetPageViewListAsync(dto, HttpContext.RequestAborted))
                .ToPaged();

        }

        /// <summary>
        /// 浏览记录集合-导出
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("pageview/export")]
        [LogFilterAlpha("导出日志")]
        public async Task<FileStreamResult> GetPageViewListAsync([FromBody] ExportExcelDto<PageViewInDto> dto)
        {
            var items = (await _knowApplication.GetPageViewListAsync(dto.QueryDto, HttpContext.RequestAborted))
                .Item2;
            return _exportApplication.GetExcelFile(dto, items, "浏览记录");
        }

        #endregion

        #region 热词

        /// <summary>
        /// 新增热词
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("hotword")]
        public async Task AddKnowledgeHotWordAsync([FromBody] AddKnowledgeHotWordInDto dto)
        {
            await _knowApplication.AddKnowledgeHotWordAsync(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 新增热词页面基础数据
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("hotword/basedata")]
        public Dictionary<string, dynamic> AddKnowledgeHotWordBaseDataAsync()
        {
            //return _baseDataApplication
            //    .KnowledgeHotWordType()
            //    .Build();
            return new Dictionary<string, dynamic>
            {
                { "knowledgeHotWordType", EnumExts.GetDescriptions<EKnowledgeHotWordType>() }
            };
        }

        /// <summary>
        /// 热词集合
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("hotword")]
        public async Task<PagedDto<KnowledgeHotWordOutDto>> GetKnowledgeHotWordListAsync([FromQuery] KnowledgeHotWordInDto dto)
        {
            return (await _knowApplication.GetKnowledgeHotWordListAsync(dto, HttpContext.RequestAborted))
                .ToPaged();
        }

        /// <summary>
        /// 修改热词
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("hotword")]
        public async Task UpdateKnowledgeHotWordAsync([FromBody] UpdateKnowledgeHotWordInDto dto)
        {
            await _knowApplication.UpdateKnowledgeHotWordAsync(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 删除热词
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete("hotword")]
        public async Task DeleteKnowledgeHotWordAsync([FromQuery] string id)
        {
            await _knowledgeHotWordRepository
                .RemoveAsync(id);
        }

        #endregion

        #region 知识审批

        /// <summary>
        /// 查询待审批列表(new)
        /// </summary>
        [HttpGet("approve-paged")]
        public async Task<PagedDto<KnowledgeApproveDto>> QueryKnowledgeApprovePaged([FromQuery] QueryKnowledgeApprovePagedRequest request)
        {
            var query = _knowledgeApproRepository.Queryable()
                .Includes(d => d.Knowledge, s => s.KnowledgeTypes)
                .WhereIF(request.KnowledgeApproveType.HasValue, d => d.KnowledgeApproveType == request.KnowledgeApproveType)
                .WhereIF(request.IsPublic.HasValue, d => d.Knowledge.IsPublic == request.IsPublic)
                .WhereIF(!string.IsNullOrEmpty(request.Keyword), d => d.CreatorName == request.Keyword
                || d.CreatorOrgName == request.Keyword
                || d.Knowledge.Title == request.Keyword
                || d.Knowledge.SourceOrganize.Name == request.Keyword)
                ;
            if (request.HasApproved)
            {
                //已审批
                query//.Includes(d => d.Approver)
                    .Where(d =>
                    d.ApproverId == _sessionContext.RequiredUserId
                    && d.KnowledgeApproveStatus != EKnowledgeApproveStatus.Unhandle);
            }
            else
            {
                //待审批
                query.Where(d => d.KnowledgeApproveStatus == EKnowledgeApproveStatus.Unhandle);
            }

            var (total, items) = await query.ToPagedListAsync(request, HttpContext.RequestAborted);

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

        /// <summary>
        /// 查询审核历史(new)
        /// </summary>
        /// <returns></returns>
        [HttpGet("approve-history/{knowledgeId}")]
        public async Task<IReadOnlyList<KnowledgeApproveDto>> QueryKnowledgeApproveByKnId(string knowledgeId)
        {
            var approves = await _knowledgeApproRepository.Queryable()
                .Includes(d => d.Approver)
                .Where(d => d.KnowledgeId == knowledgeId)
                .OrderByDescending(d => d.CreationTime)
                .ToListAsync(HttpContext.RequestAborted);

            return _mapper.Map<IReadOnlyList<KnowledgeApproveDto>>(approves);
        }

        /// <summary>
        /// 批量审核(new)
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost("approve-batch")]
        public async Task ApproveBatch([FromBody] ApproveBatchRequest request)
        {
            #region approve

            var approves = await _knowledgeApproRepository.Queryable()
                .Includes(d => d.Knowledge, x => x.KnowledgeTypes)
                .Includes(d => d.Knowledge, x => x.User)
                .Includes(d => d.Knowledge, x => x.SourceOrganize)
                .Where(d => request.ApproveIds.Contains(d.Id) && d.KnowledgeApproveStatus == EKnowledgeApproveStatus.Unhandle)
                .ToListAsync(HttpContext.RequestAborted);

            foreach (var approve in approves)
            {
                var kn = approve.Knowledge;
                switch (approve.KnowledgeApproveType)
                {
                    case EKnowledgeApproveType.Add:
                    case EKnowledgeApproveType.Update:
                        // t: 上架 f: 驳回
                        if (request.IsSuccess)
                        {
                            kn.OnShelf();
                        }
                        else
                        {
                            kn.Status = EKnowledgeStatus.Revert;
                        }
                        break;
                    case EKnowledgeApproveType.Delete:
                        // t: 先下架，再删除 f: 驳回
                        if (request.IsSuccess)
                        {
                            kn.OffShelf();
                            kn.SoftDelete();
                        }
                        else
                        {
                            kn.Status = EKnowledgeStatus.Revert;
                        }
                        break;
                    case EKnowledgeApproveType.OffShelf:
                        // t: 下架 f: 上架
                        if (request.IsSuccess)
                        {
                            kn.OffShelf();
                        }
                        else
                        {
                            kn.Status = EKnowledgeStatus.OnShelf;
                        }
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
                approve.Approve(_sessionContext.RequiredUserId, request.Opinion,
                    request.IsSuccess
                        ? EKnowledgeApproveStatus.Successed
                        : EKnowledgeApproveStatus.Failed);
            }

            //var kns = approves.Select(d => d.Knowledge).ToList();
            //await _knowledgeRepository.UpdateRangeAsync(kns, HttpContext.RequestAborted);

            await _knowledgeApproRepository.UpdateNav(approves)
                .Include(d => d.Knowledge)
                .ExecuteCommandAsync();

            #endregion

            #region push to ds

            var pushApproves = approves.Where(d => d.KnowledgeApproveType != EKnowledgeApproveType.OffShelf)
                  .ToList();
            if (!pushApproves.Any()) return;

            //高效办成一件事配置
            var cancelPublishOrderEnabled = _systemSettingCacheManager.GetSetting(SettingConstants.EfficientlyAccomplish)?.SettingValue[0];
            foreach (var pushApprove in pushApproves)
            {
                var pushKnowledge = _mapper.Map<KnowledgeSendDto>(pushApprove.Knowledge);
                pushKnowledge.CategoryCode = "01";
                pushKnowledge.CategoryName = "公共服务";

                if (!string.IsNullOrEmpty(cancelPublishOrderEnabled))
                {
                    var isEfficientlyAccomplish = pushApprove.Knowledge.KnowledgeTypes.Any(
                            d => d.SpliceName.StartsWith(cancelPublishOrderEnabled));
                    //是高效，处理默认值
                    if (isEfficientlyAccomplish)
                    {
                        pushKnowledge.CategoryCode = "25";
                        pushKnowledge.CategoryName = "高效办成一件事";
                    }
                }

                switch (pushApprove.KnowledgeApproveType)
                {
                    case EKnowledgeApproveType.Add:
                        await _capPublisher.PublishAsync(EventNames.HotlineKnowledgeAdd, pushKnowledge, cancellationToken: HttpContext.RequestAborted);
                        break;
                    case EKnowledgeApproveType.Update:
                        await _capPublisher.PublishAsync(EventNames.HotlineKnowledgeUpdate, pushKnowledge, cancellationToken: HttpContext.RequestAborted);
                        break;
                    case EKnowledgeApproveType.Delete:
                        await _capPublisher.PublishAsync(EventNames.HotlineKnowledgeRemove, pushKnowledge, cancellationToken: HttpContext.RequestAborted);
                        break;
                    case EKnowledgeApproveType.OffShelf:
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }

            #endregion

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

        #endregion
    }
}
