using Hotline.Application.FlowEngine; using Hotline.Application.Knowledge; using Hotline.FlowEngine; using Hotline.KnowledgeBase; using Hotline.KnowledgeBase.Notifies; using Hotline.Permissions; using Hotline.Repository.SqlSugar.Extensions; using Hotline.Settings; using Hotline.Settings.Hotspots; using Hotline.Share.Dtos; using Hotline.Share.Dtos.FlowEngine; using Hotline.Share.Dtos.Knowledge; using Hotline.Share.Enums.KnowledgeBase; using Hotline.Users; using MapsterMapper; using MediatR; using Microsoft.AspNetCore.Mvc; using SqlSugar; using XF.Domain.Authentications; using XF.Domain.Exceptions; using XF.Utility.EnumExtensions; namespace Hotline.Api.Controllers { /// /// /// public class KnowledgeController : BaseController { #region 注入 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 IKnowledgeWorkFlowRepository _knowledgeWorkFlowRepository; private readonly IUserRepository _userRepository; private readonly IKnowledgeTypeRepository _knowledgeTypeRepository; private readonly IHotspotTypeRepository _hotspotTypeRepository; /// /// /// /// /// /// /// /// /// /// /// /// /// /// public KnowledgeController(IKnowledgeRepository knowledgeRepository, ISessionContext sessionContext, IKnowledgeDomainService knowledgeDomainService, IMapper mapper, IKnowApplication knowApplication, IMediator mediator, IWorkflowApplication workflowApplication, IKnowledgeWorkFlowRepository knowledgeWorkFlowRepository , IUserRepository userRepository, IKnowledgeTypeRepository knowledgeTypeRepository, IHotspotTypeRepository hotspotTypeRepository) { _knowledgeRepository = knowledgeRepository; _sessionContext = sessionContext; _knowledgeDomainService = knowledgeDomainService; _mapper = mapper; _knowApplication = knowApplication; _mediator = mediator; _workflowApplication = workflowApplication; _knowledgeWorkFlowRepository = knowledgeWorkFlowRepository; _userRepository = userRepository; _knowledgeTypeRepository = knowledgeTypeRepository; _hotspotTypeRepository = hotspotTypeRepository; } #endregion #region 知识管理 /// /// 知识库-知识修改-查询详情 /// /// /// [HttpGet("updateinfo/{Id}")] public async Task KnowledgeUpdateInfo(string Id) { var know = await _knowledgeRepository.GetAsync(Id, HttpContext.RequestAborted); if (know is null) throw UserFriendlyException.SameMessage("知识查询失败!"); var knowledgeInfoDto = _mapper.Map(know); //分类 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; return knowledgeInfoDto; } /// /// 知识库-查询详情-增加浏览量 /// /// 知识Id /// 默认不增加,false不增加,true增加浏览量 /// [HttpGet("info/{Id}")] public async Task KnowledgeInfo(string Id, bool? IsAddPv) { var knowledge = await _knowledgeDomainService.KnowledgeInfo(Id, HttpContext.RequestAborted); if (knowledge is null) throw UserFriendlyException.SameMessage("知识查询失败!"); //转化 var knowledgeShowInfoDto = _mapper.Map(knowledge); //查询其他 var user = await _userRepository.GetAsync(knowledge.CreatorId, HttpContext.RequestAborted); if (user != null) knowledgeShowInfoDto.CreatorName = user.Name; var type = await _knowledgeTypeRepository.GetAsync(knowledge.KnowledgeTypeId, HttpContext.RequestAborted); if (type != null) knowledgeShowInfoDto.KnowledgeTypeName = type.SpliceName; var hot = await _hotspotTypeRepository.GetAsync(knowledge.HotspotId, HttpContext.RequestAborted); if (hot != null) knowledgeShowInfoDto.HotspotName = hot.HotSpotFullName; if (IsAddPv == true) _mediator.Publish(new GetKnowledgeInfoNotify(knowledge)); return knowledgeShowInfoDto; } /// /// 知识库-新增 /// /// /// [Permission(EPermission.AddKnowledge)] [HttpPost("add")] public async Task AddKnowledge([FromBody] AddKnowledgeDto dto) { var kn = _mapper.Map(dto); //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; return await _knowledgeRepository.AddAsync(kn, HttpContext.RequestAborted); } /// /// 知识库-知识下架 /// /// /// [Permission(EPermission.KnowledgeOffShelf)] [HttpPut("offshelf")] public async Task KnowledgeOffShelf(string Id) { var know = await _knowledgeRepository.GetAsync(Id, HttpContext.RequestAborted); if (know != null && know.Status == EKnowledgeStatus.OnShelf) { know.Status = EKnowledgeStatus.OffShelf; know.OnShelfTime = null; know.OffShelfTime = DateTime.Now; await _knowledgeRepository.UpdateAsync(know, HttpContext.RequestAborted); } else throw UserFriendlyException.SameMessage("知识下架失败"); } /// /// 知识库-知识上架 /// /// /// [Permission(EPermission.KnowledgeOnTheShelf)] [HttpPut("ontheshelf")] public async Task KnowledgeOnTheShelf(string Id) { var know = await _knowledgeRepository.GetAsync(Id, HttpContext.RequestAborted); if (know != null && know.Status == EKnowledgeStatus.OffShelf) { know.Status = EKnowledgeStatus.OnShelf; know.OnShelfTime = DateTime.Now; know.OffShelfTime = null; await _knowledgeRepository.UpdateAsync(know, HttpContext.RequestAborted); } else throw UserFriendlyException.SameMessage("知识上架失败"); } /// /// 知识申请-关联知识-获取知识列表 /// /// [HttpGet("getknowledge")] public async Task> GetKnowledge() { var temp = await _knowledgeRepository .Queryable() .LeftJoin((o, sys) => o.CreatorOrgId == sys.Id) //重新构建数据 .Select((o, sys) => new { index = SqlFunc.RowNumber($"{o.Version} desc ", $"{o.Code}"), DepartmentId = sys.Id, Department = sys.OrgName, o.Id, o.Title, o.Status, o.Code }) //将结果合并成一个表 .MergeTable() //取第一条数据 .Where(d => d.index == 1 && d.Status == EKnowledgeStatus.OnShelf) .ToListAsync(); //返回数据 return _mapper.Map>(temp); } #endregion #region 我的草稿箱 /// /// 我的草稿箱 /// /// /// [Permission(EPermission.KnowledgeMyDraftsList)] [HttpGet("mydraftslist")] public async Task> MyDraftsList([FromQuery] MyDraftsListPagedDto pagedDto) { var (total, items) = await _knowledgeRepository .Queryable() .Includes(it => it.User) .Includes(it => it.KnowledgeType) .Where(p => p.CreatorId == _sessionContext.RequiredUserId && p.Status == EKnowledgeStatus.Drafts) .WhereIF(!string.IsNullOrEmpty(pagedDto.Keyword), d => d.Title.Contains(pagedDto.Keyword!)) .WhereIF(!string.IsNullOrEmpty(pagedDto.KnowledgeTypeId), d => d.KnowledgeTypeId == pagedDto.KnowledgeTypeId) .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(total, _mapper.Map>(items)); } /// /// 知识库-修改知识草稿 /// /// /// [Permission(EPermission.KnowledgeDraftsUpdate)] [HttpPut("update")] public async Task UpdateKnowledge([FromBody] UpdateKnowledgeDto dto) { if (dto.Status != EKnowledgeStatus.Drafts) throw UserFriendlyException.SameMessage("非草稿数据不可修改"); var kn = _mapper.Map(dto); await _knowledgeRepository.UpdateAsync(kn, HttpContext.RequestAborted); } /// /// 删除知识草稿 /// /// /// [Permission(EPermission.KnowledgeDraftsDelete)] [HttpDelete("{id}")] public async Task Remove(string id) { var knowledge = await _knowledgeRepository.GetAsync(id, HttpContext.RequestAborted); if (knowledge == null) return; if (knowledge.Status != EKnowledgeStatus.Drafts) throw UserFriendlyException.SameMessage("非草稿数据不可删除"); await _knowledgeRepository.RemoveAsync(knowledge, false, HttpContext.RequestAborted); } #endregion #region 知识列表 /// /// 知识库列表页面枚举值 /// /// [HttpGet("knowledge-status-data")] public async Task KnowledgeStatus() { return new List> { new KeyValuePair(1, "审核中"), new KeyValuePair(3, "已上架"), new KeyValuePair(4, "已下架") }; } /// /// 知识查询 /// /// /// [Permission(EPermission.KnowledgeAllList)] [HttpGet()] public async Task> GetKnowList([FromQuery] KnowPagedListDto pagedDto) { return await _knowApplication.GetKnowList(pagedDto); } #endregion #region 知识检索 /// /// 知识检索 /// /// /// [Permission(EPermission.KnowledgeRetrieval)] [HttpGet("knowretrieval")] public async Task> KnowRetrieval([FromQuery] KnowledgeRetrievalPagedListDto pagedDto) { //if (string.IsNullOrEmpty(pagedDto.Keyword)) // throw UserFriendlyException.SameMessage("请输入关键字"); RefAsync total = 0; var Keyword = pagedDto.Keyword?.Trim(); var temp = await _knowledgeRepository .Queryable() .Select(o => new { index = SqlFunc.RowNumber($"{o.Version} desc ", $"{o.Code}"), o.Id, o.Code, o.Title, o.Summary, o.Content, o.PageView, o.Additions, o.Status }) //将结果合并成一个表 .MergeTable() //取第一条数据 .Where(d => d.index == 1 && d.Status == EKnowledgeStatus.OnShelf) .WhereIF((pagedDto.RetrievalType == null || pagedDto.RetrievalType == EKnowledgeRetrievalType.All) && !string.IsNullOrEmpty(Keyword), d => d.Title.Contains(Keyword) || d.Content.Contains(Keyword))// || d.Additions.Contains(pagedDto.Keyword) .WhereIF(pagedDto.RetrievalType == EKnowledgeRetrievalType.Title && !string.IsNullOrEmpty(Keyword), d => d.Title.Contains(Keyword)) .WhereIF(pagedDto.RetrievalType == EKnowledgeRetrievalType.Content && !string.IsNullOrEmpty(Keyword), d => d.Content.Contains(Keyword)) // .WhereIF(pagedDto.RetrievalType == EKnowledgeRetrievalType.Enclosure, d => d.Additions.Contains(pagedDto.Keyword)) .OrderByDescending(p => p.PageView) .ToPageListAsync(pagedDto.PageIndex, pagedDto.PageSize, total); return new PagedDto(total, _mapper.Map>(temp)); } #endregion #region 我的知识删除列表 /// /// 我的知识删除列表页面枚举值 /// /// [HttpGet("delete-status-data")] public async Task DeleteApplyStatus() { return EnumExts.GetDescriptions(); } /// /// 我的知识删除列表 /// /// /// [HttpGet("deletelist")] [Permission(EPermission.KnowledgeDeleteApply)] public async Task> 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.OrgName.Contains(pagedDto.Keyword!) || d.Knowledge.Title.Contains(pagedDto.Keyword!)) .OrderByDescending(p => p.CreationTime) .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } #endregion #region 审核管理 /// /// 审核管理页面枚举值 /// /// [HttpGet("approval-base-data")] public async Task ApprovalBaseData() { return new { EKnowledgeWorkFlowStatus = EnumExts.GetDescriptions(), EKnowledgeApplyType = EnumExts.GetDescriptions() }; } /// /// 审核管理 /// /// /// [Permission(EPermission.KnowledgeApprovedAllList)] [HttpGet("approvedlist")] public async Task> 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.Knowledge, it => it.KnowledgeType) .Includes(it => it.Workflow) .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.OrgName.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.Workflow.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgCode); } //处理是否可以办理 //items.ForEach(d => d.CanHandle = d.Workflow.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgCode)); return new PagedDto(total, _mapper.Map>(items)); } #endregion #region 工单受理,知识库检索 /// /// 获取知识热点词 /// /// [HttpGet("getkeyword")] public async Task> GetKeyWord() { return await _knowledgeDomainService.GetKeyWord(); } /// /// 工单受理知识检索 /// /// /// [HttpGet("knowpopscreen")] public async Task> KnowPopScreen([FromQuery] KnowledgePopScreenPagedListDto pagedDto) { RefAsync total = 0; var temp = await _knowledgeRepository .Queryable() .Select(o => new { index = SqlFunc.RowNumber($"{o.Version} desc ", $"{o.Code}"), o.Id, o.Code, o.Title, o.Summary, o.Content, o.PageView, o.Keywords, o.HotspotId, o.Status }) //将结果合并成一个表 .MergeTable() //取第一条数据 .Where(d => d.index == 1 && d.Status == EKnowledgeStatus.OnShelf) .WhereIF(!string.IsNullOrEmpty(pagedDto.Keyword), p => p.Title.Contains(pagedDto.Keyword) || p.Keywords.Contains(pagedDto.Keyword)) .WhereIF(!string.IsNullOrEmpty(pagedDto.HotspotId), p => p.HotspotId == pagedDto.HotspotId) .OrderByDescending(p => p.PageView) .ToPageListAsync(pagedDto.PageIndex, pagedDto.PageSize, total); return new PagedDto(total, _mapper.Map>(temp)); } #endregion #region 流程相关 /// /// 新增-开始流程 /// /// 知识id /// 流程开启参数 /// [Permission(EPermission.AddKnowledge)] [HttpPost("{id}/add-startflow")] public async Task AddStartFlow(string id, [FromBody] StartWorkflowDto dto) { await StartFlow(id, WorkflowModuleConsts.KnowledgeAdd, EKnowledgeApplyType.Add, dto); } /// /// 删除-开始流程 /// /// 知识id /// 流程开启参数 /// [Permission(EPermission.KnowledgeDelete)] [HttpPost("{id}/remove-startflow")] public async Task RemoveStartFlow(string id, [FromBody] StartWorkflowDto dto) { await StartFlow(id, WorkflowModuleConsts.KnowledgeDelete, EKnowledgeApplyType.Delete, dto); } /// /// 查询知识库办理流程开启参数-新增 /// /// [Permission(EPermission.AddKnowledge)] [HttpGet("add-flow-start")] public async Task GetAddFlowStartOptionsAsync() { return await _workflowApplication.GetStartOptionsAsync(WorkflowModuleConsts.KnowledgeAdd, HttpContext.RequestAborted); } /// /// 查询知识库办理流程开启参数-删除 /// /// [Permission(EPermission.KnowledgeDelete)] [HttpGet("remove-flow-start")] public async Task GetRemoveFlowStartOptionsAsync() { return await _workflowApplication.GetStartOptionsAsync(WorkflowModuleConsts.KnowledgeDelete, HttpContext.RequestAborted); } #endregion #region 私有方法-开始流程 /// /// 开始流程 /// /// 知识ID /// 知识模板编号 /// 申请类型 /// 流程开启参数 /// private async Task 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("知识删除失败"); //验证是否已经发起过知识删除流程 var exists = await _knowledgeWorkFlowRepository.GetAsync(p => p.KnowledgeId == knowledge.Id && p.WorkflowModuleStatus == EKnowledgeApplyType.Delete && (p.WorkFlowApplyStatus == EKnowledgeWorkFlowStatus.Success || p.WorkFlowApplyStatus == EKnowledgeWorkFlowStatus.Auditing) && p.WorkflowId != null); if (exists != null) throw UserFriendlyException.SameMessage($"该知识已发起过{WorkflowModule.Modules[WorkflowModuleConsts.KnowledgeDelete]}流程"); } if (!string.IsNullOrEmpty(knowledge.WorkflowId) && eKnowledgeApplyType != EKnowledgeApplyType.Delete) throw UserFriendlyException.SameMessage("知识已发起流程"); //知识审批主表 var flowId = await _knowledgeDomainService.AddWorkFlowAsync(id, eKnowledgeApplyType, HttpContext.RequestAborted); dto.DefinitionModuleCode = moduleCode; dto.Title = knowledge.Title; await _workflowApplication.StartWorkflowAsync(dto, flowId, HttpContext.RequestAborted); } #endregion } }