using Hotline.Settings.Hotspots; using Hotline.Share.Dtos.Knowledge; using Hotline.Share.Dtos.Caselibrary; using Hotline.Share.Enums.Caselibrary; using MapsterMapper; using XF.Domain.Authentications; using XF.Domain.Dependency; using XF.Domain.Exceptions; using XF.Domain.Repository; using Hotline.Repository.SqlSugar.Extensions; using Hotline.SeedData; using Hotline.File; using Hotline.Application.Bulletin; using Hotline.Share.Tools; using Hotline.Application.Tools; using SqlSugar; using Hotline.CaseLibrary; using Hotline.Orders; using Hotline.KnowledgeBase; using Hotline.Share.Enums.Planlibrary; using System.Numerics; namespace Hotline.Application.Caselibrary { /// /// 案例库处理 /// public class CaseApplication : ICaseApplication, IScopeDependency { #region 注册 private readonly IRepository _caseListRepository; //案例库列表 private readonly IRepository _caseRelationTypeRepository; //案例库关联类型 private readonly IRepository _caseTypeRepository; //案例库分类管理 private readonly IRepository _caseTypeOrgRepository; //案例库分类关联机构 private readonly IRepository _caseCollectRepository; //案例库收藏评分 private readonly IRepository _orderRepository; //工单 private readonly IRepository _knowledgeRepository; //知识库 private readonly ISessionContext _sessionContext; private readonly IMapper _mapper; private readonly IRepository _hotspotTypeRepository; private readonly IFileRepository _fileRepository; private readonly IBulletinApplication _bulletinApplication; public CaseApplication( IRepository caseListRepository, IRepository caseRelationTypeRepository, IRepository caseTypeRepository, IRepository caseTypeOrgRepository, IRepository caseCollectRepository, IRepository orderRepository, IRepository knowledgeRepository, ISessionContext sessionContext, IMapper mapper, IRepository hotspotTypeRepository, IFileRepository fileRepository, IBulletinApplication bulletinApplication) { _caseListRepository = caseListRepository; _caseRelationTypeRepository = caseRelationTypeRepository; _caseTypeRepository = caseTypeRepository; _caseTypeOrgRepository = caseTypeOrgRepository; _caseCollectRepository = caseCollectRepository; _orderRepository = orderRepository; _knowledgeRepository = knowledgeRepository; _sessionContext = sessionContext; _mapper = mapper; _hotspotTypeRepository = hotspotTypeRepository; _fileRepository = fileRepository; _bulletinApplication = bulletinApplication; } #endregion #region 案例库类型管理 #region 案例库类型 - 新增 /// /// 案例库类型 - 新增 /// /// /// /// public async Task AddTypeAsync(AddCaseTypeDto dto, CancellationToken cancellationToken) { var sandard = await _caseTypeRepository.GetAsync(p => p.ParentId == dto.ParentId && p.Name == dto.Name && p.IsDeleted == false, cancellationToken); if (sandard is not null) throw UserFriendlyException.SameMessage("当前层级已存在相同名称的分类!"); var type = _mapper.Map(dto); type.InitId(); type.IsEnable = true; //获取分类名称全称 string FullName = await GetFullName(type.ParentId); //处理全称,如果为第一级直接用全称,否则获取全称后拼接名称 type.SpliceName = string.IsNullOrEmpty(FullName) ? dto.Name : FullName + "-" + dto.Name; var id = await _caseTypeRepository.AddAsync(type, cancellationToken); if (dto.TypeOrgDtos != null && dto.TypeOrgDtos.Any()) { List orgs = _mapper.Map>(dto.TypeOrgDtos); orgs.ForEach(x => x.TypeId = type.Id); await _caseTypeOrgRepository.AddRangeAsync(orgs, cancellationToken); } return id; } #endregion #region 案例库类型 - 编辑 /// /// 案例库类型 - 编辑 /// /// /// /// public async Task UpdateTypeAsync(UpdateCaseTypeDto dto, CancellationToken cancellationToken) { //查询原有数据 var type = await _caseTypeRepository.GetAsync(dto.Id, cancellationToken); if (type is null) throw UserFriendlyException.SameMessage("编辑失败!"); bool result = type.Name != dto.Name || type.ParentId != dto.ParentId; //是否更改分类名称或者层级 //转换 _mapper.Map(dto, type); //如果更改了名称或者修改了层级,则修改全称,未更改不修改 if (result) { string FullName = await GetFullName(type.ParentId);//获取分类名称全称 type.SpliceName = string.IsNullOrEmpty(FullName) ? dto.Name : FullName + "-" + dto.Name;//处理全称,如果为第一级直接用全称,否则获取全称后拼接名称 } //修改数据 await _caseTypeRepository.UpdateAsync(type, cancellationToken); //如果修改了名称,对应修改子分类全称 if (result) await UpdateChildNode(type.Id); // 修改关联机构 await _caseTypeOrgRepository.RemoveAsync(x => x.TypeId == type.Id, false, cancellationToken); if (dto.TypeOrgDtos != null && dto.TypeOrgDtos.Any()) { List orgs = _mapper.Map>(dto.TypeOrgDtos); orgs.ForEach(x => x.TypeId = type.Id); await _caseTypeOrgRepository.AddRangeAsync(orgs, cancellationToken); } } #endregion #region 案例库类型 - 删除 /// /// 案例库类型 - 删除 /// /// /// /// public async Task RemoveTypeAsync(string Id, CancellationToken cancellationToken) { //查询数据是否存在 var sandard = await _caseTypeRepository.GetAsync(p => p.Id == Id && p.IsDeleted == false, cancellationToken); if (sandard is null) throw UserFriendlyException.SameMessage("分类不存在!"); //查询是否有子级分类 var checkChild = await _caseTypeRepository.CountAsync(p => p.ParentId == Id && p.IsDeleted == false, cancellationToken); if (checkChild > 0) throw UserFriendlyException.SameMessage("存在子级分类!"); //查询是否有案例分类 var checkKnowledge = await _caseListRepository.CountAsync(p => p.CaseTypes.Any(t => t.CaseId == Id), cancellationToken); if (checkKnowledge > 0) throw UserFriendlyException.SameMessage("分类存在案例!"); //删除操作 await _caseTypeRepository.RemoveAsync(sandard, true, cancellationToken); } #endregion #endregion #region 案例库管理 #region 案例库 - 列表 /// /// 案例库 - 列表 /// /// /// public async Task<(int, IList)> QueryAllCaseListAsync(CaseListDto pagedDto, CancellationToken cancellationToken) { var typeSpliceName = string.Empty; if (!string.IsNullOrEmpty(pagedDto.CaseTypeID)) { var type = await _caseTypeRepository.GetAsync(x => x.Id == pagedDto.CaseTypeID); typeSpliceName = type?.SpliceName; } //单表分页 var (total, temp) = await _caseListRepository.Queryable() .Includes(x => x.CaseTypes) .Includes(x => x.ExaminMan) .Where(x => x.IsDeleted == false) .Where(x => (x.Status == ECaseStatus.Drafts && x.CreatorId == _sessionContext.UserId) || (x.Status != ECaseStatus.Drafts)) .WhereIF(OrgSeedData.CenterId != pagedDto.CreateOrgId && !string.IsNullOrEmpty(pagedDto.CreateOrgId), x => x.CreatorOrgId != null && x.CreatorOrgId.StartsWith(pagedDto.CreateOrgId!)) .WhereIF(!string.IsNullOrEmpty(pagedDto.Title), x => x.Title.Contains(pagedDto.Title)) .WhereIF(!string.IsNullOrEmpty(pagedDto.Abstract), x => x.Abstract.Contains(pagedDto.Abstract)) .WhereIF(!string.IsNullOrEmpty(pagedDto.Describe), x => x.Describe.Contains(pagedDto.Describe)) .WhereIF(!string.IsNullOrEmpty(pagedDto.Result), x => x.Result.Contains(pagedDto.Result)) .WhereIF(!string.IsNullOrEmpty(pagedDto.Reason), x => x.Reason.Contains(pagedDto.Reason)) .WhereIF(!string.IsNullOrEmpty(pagedDto.Keyword), x => x.Title.Contains(pagedDto.Keyword!) || x.CreatorName!.Contains(pagedDto.Keyword!) || x.CreatorOrgName!.Contains(pagedDto.Keyword!)) .WhereIF(pagedDto.Status.HasValue && pagedDto.Status != ECaseStatus.OffShelf && pagedDto.Status != ECaseStatus.NewDrafts && pagedDto.Status != ECaseStatus.All, x => x.Status == pagedDto.Status && ((x.ExpiredTime != null && x.ExpiredTime > DateTime.Now) || x.ExpiredTime == null)) .WhereIF(pagedDto.Status.HasValue && pagedDto.Status == ECaseStatus.OffShelf, x => x.Status == pagedDto.Status || (x.ExpiredTime != null && x.ExpiredTime < DateTime.Now && x.Status != ECaseStatus.Drafts)) .WhereIF(pagedDto.Status.HasValue && pagedDto.Status == ECaseStatus.NewDrafts, x => x.Status == ECaseStatus.Drafts || x.Status == ECaseStatus.Revert || x.Status == ECaseStatus.NewDrafts) .WhereIF(!string.IsNullOrEmpty(typeSpliceName), x => x.CaseTypes.Any(t => t.CaseTypeSpliceName.StartsWith(typeSpliceName))) .WhereIF(pagedDto.CreationTimeStart.HasValue, x => x.CreationTime >= pagedDto.CreationTimeStart) .WhereIF(pagedDto.CreationTimeEnd.HasValue, x => x.CreationTime <= pagedDto.CreationTimeEnd) .WhereIF(pagedDto.OnShelfTimeStart.HasValue, x => x.OnShelfTime >= pagedDto.OnShelfTimeStart) .WhereIF(pagedDto.OnShelfTimeEnd.HasValue, x => x.OnShelfTime <= pagedDto.OnShelfTimeEnd) .WhereIF(pagedDto.OffShelfTimeStart.HasValue, x => x.OffShelfTime >= pagedDto.OffShelfTimeStart) .WhereIF(pagedDto.OffShelfTimeEnd.HasValue, x => x.OffShelfTime <= pagedDto.OffShelfTimeEnd) .WhereIF(pagedDto.UpdateTimeStart.HasValue, x => x.UpdateTime >= pagedDto.UpdateTimeStart) .WhereIF(pagedDto.UpdateTimeEnd.HasValue, x => x.UpdateTime <= pagedDto.UpdateTimeEnd) .WhereIF(pagedDto.ExaminTimeStart.HasValue, x => x.ExaminTime >= pagedDto.ExaminTimeStart) .WhereIF(pagedDto.ExaminTimeEnd.HasValue, x => x.ExaminTime <= pagedDto.ExaminTimeEnd) .OrderByIF(string.IsNullOrEmpty(pagedDto.SortField), x => x.CreationTime, OrderByType.Desc) .OrderByIF(pagedDto is { SortField: "pageView" }, x => x.PageView, OrderByType.Desc) //阅读量 .OrderByIF(pagedDto is { SortField: "score" }, x => x.Score, OrderByType.Desc) //评分 .OrderByIF(pagedDto is { SortField: "creationTime" }, x => x.CreationTime, OrderByType.Desc) //创建时间 .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize, cancellationToken); return (total, _mapper.Map>(temp)); } #endregion #region 案例库 - 新增 /// /// 新增 /// /// /// /// public async Task AddCaseAsync(AddCaseListDto dto, CancellationToken cancellationToken) { var pList = _mapper.Map(dto); var any = await _caseListRepository.Queryable().Where(x => x.Status == ECaseStatus.OnShelf && x.Title == dto.Title).AnyAsync(); if (any) throw UserFriendlyException.SameMessage("当前案例标题存在重复标题!"); if (dto.Files != null && dto.Files.Count > 0) pList.FileJson = await _fileRepository.AddFileAsync(dto.Files, pList.Id, "", cancellationToken); await _caseListRepository.AddAsync(pList, cancellationToken); if (dto.CaseTypes.Any()) { List types = _mapper.Map>(dto.CaseTypes); types.ForEach(x => x.CaseId = pList.Id); await _caseRelationTypeRepository.AddRangeAsync(types, cancellationToken); } return pList.Id; } #endregion #region 案例库 - 修改 /// /// 修改 /// /// /// /// public async Task UpdateCaseAsync(UpdateCaseListDto dto, CancellationToken cancellationToken) { var Case = await _caseListRepository.GetAsync(dto.Id); if (Case == null) throw UserFriendlyException.SameMessage("案例库查询失败"); if ((Case.Status == ECaseStatus.OnShelf || Case.Status == ECaseStatus.Auditing) && (Case.ExpiredTime.HasValue && Case.ExpiredTime.Value > DateTime.Now)) throw UserFriendlyException.SameMessage("案例库数据不可修改"); var any = await _caseListRepository.Queryable().Where(x => x.Status == ECaseStatus.OnShelf && x.Title == dto.Title && x.Id != dto.Id).AnyAsync(); if (any) throw UserFriendlyException.SameMessage("当前案例标题存在重复标题!"); if (dto.ApplyStatus == ECaseApplyStatus.Delete) { Case.Status = (ECaseStatus)dto.Status; Case.ApplyStatus = (ECaseApplyStatus)dto.ApplyStatus; Case.Id = dto.Id; Case.ApplyReason = dto.ApplyReason; } else { _mapper.Map(dto, Case); if (dto.Files != null && dto.Files.Count > 0) Case.FileJson = await _fileRepository.AddFileAsync(dto.Files, Case.Id, "", cancellationToken); else Case.FileJson = new List(); } await _caseListRepository.UpdateNullAsync(Case, cancellationToken); if (dto.ApplyStatus != ECaseApplyStatus.Delete) { if (dto.CaseTypes.Any()) { var anyRelationTypes = await _caseRelationTypeRepository.Queryable().Where(x => x.CaseId == Case.Id).ToListAsync(); if (anyRelationTypes.Any()) await _caseRelationTypeRepository.RemoveRangeAsync(anyRelationTypes); List types = _mapper.Map>(dto.CaseTypes); types.ForEach(x => x.CaseId = dto.Id); await _caseRelationTypeRepository.AddRangeAsync(types, cancellationToken); } } } #endregion #region 案例库 - 删除 /// /// 删除 /// /// /// /// public async Task RemoveCaseAsync(UpdateCaseListDto dto, CancellationToken cancellationToken) { var Case = await _caseListRepository.GetAsync(dto.Id); if (Case == null) throw UserFriendlyException.SameMessage("案例库查询失败"); _mapper.Map(dto, Case); Case.IsDeleted = true; await _caseListRepository.UpdateNullAsync(Case, cancellationToken); } #endregion #region 案例库 - 审核 /// /// 审核 /// /// /// /// public async Task AuditCaseAsync(UpdateCaseListDto dto, CancellationToken cancellationToken) { var Case = await _caseListRepository.GetAsync(dto.Id); if (Case == null) throw UserFriendlyException.SameMessage("案例库查询失败"); Case.Status = (ECaseStatus)dto.Status!; Case.ApplyStatus = (ECaseApplyStatus)dto.ApplyStatus!; Case.ExaminTime = dto.ExaminTime; Case.ExaminManId = dto.ExaminManId; Case.ExaminOrganizeId = dto.ExaminOrganizeId; Case.ExaminOpinion = dto.ExaminOpinion; Case.UpdateTime = dto.UpdateTime; Case.OnShelfTime = dto.OnShelfTime; Case.OffShelfTime = dto.OffShelfTime; if (Case.ApplyStatus == ECaseApplyStatus.Delete) { Case.IsDeleted = true; } await _caseListRepository.UpdateNullAsync(Case, cancellationToken); } #endregion #region 案例库 - 详情 /// /// 详情 /// /// /// 默认不增加,false不增加,true增加浏览量 /// public async Task GetCaseAsync(string Id, bool? IsAddPv, CancellationToken cancellationToken) { var Case = await _caseListRepository.GetAsync(Id); if (Case == null) throw UserFriendlyException.SameMessage("案例库查询失败"); ; //转化 var CaseInfoDto = _mapper.Map(Case); if (Case != null) { if (!string.IsNullOrEmpty(Case.Describe)) CaseInfoDto.Abstract = _bulletinApplication.GetSiteUrls(Case.Abstract); if (!string.IsNullOrEmpty(Case.Describe)) CaseInfoDto.Describe = _bulletinApplication.GetSiteUrls(Case.Describe); if (!string.IsNullOrEmpty(Case.Result)) CaseInfoDto.Result = _bulletinApplication.GetSiteUrls(Case.Result); if (!string.IsNullOrEmpty(Case.Reason)) CaseInfoDto.Reason = _bulletinApplication.GetSiteUrls(Case.Reason); } // 分类 var relationType = await _caseRelationTypeRepository.QueryAsync(x => x.CaseId == Id && x.CreatorId == _sessionContext.UserId); if (relationType != null) { CaseInfoDto.CaseTypes = _mapper.Map>(relationType); } // 收藏 var collect = await _caseCollectRepository.GetAsync(x => x.CaseId == Id && x.CreatorId == _sessionContext.UserId); if (collect != null) CaseInfoDto.Collect = _mapper.Map(collect); // 工单 var order = await _orderRepository.GetAsync(x => x.Id == CaseInfoDto.OrderId, cancellationToken); if (order != null) CaseInfoDto.OrderTitle = order.Title; // 知识库 var knowledge = await _knowledgeRepository.GetAsync(x => x.Id == CaseInfoDto.KnowledgeId, cancellationToken); if (knowledge != null) CaseInfoDto.KnowledgeTitle = knowledge.Title; // 附件 if (CaseInfoDto.FileJson != null && CaseInfoDto.FileJson.Any()) { var ids = CaseInfoDto.FileJson.Select(x => x.Id).ToList(); CaseInfoDto.Files = await _fileRepository.GetFilesAsync(ids, cancellationToken); } // 更新浏览量 if (IsAddPv == true) { //修改浏览量 Case.PageView++; //修改点击量 await _caseListRepository.UpdateAsync(Case, cancellationToken); } return CaseInfoDto; } #endregion #region 案例库 - 批量导出 /// /// 案例库 - 批量导出 /// /// /// /// public async Task> CaseInfoListExportAsync(CaseInfoExportDto dto, CancellationToken cancellationToken) { var streamList = new Dictionary(); var knowList = await _caseListRepository.Queryable() .Where(m => dto.Ids.Contains(m.Id)) .Select(m => new { m.Title, m.Result }) .ToListAsync(cancellationToken); var tasks = knowList.Select(async item => { var stream = await Task.Run(() => item.Result.HtmlToStream(dto.FileType), cancellationToken); return new KeyValuePair( item.Title + dto.FileType.GetFileExtension(), stream ); }); var results = await Task.WhenAll(tasks); foreach (var kvp in results) { if (!streamList.ContainsKey(kvp.Key)) { streamList.Add(kvp.Key, kvp.Value); } } return streamList; } #endregion #endregion #region 私有方法 #region 查询所有子级 /// /// 查询所有子级 /// /// 分类数据 /// 需要查询哪级下面的分类 /// 选中的数据ID /// private List GetChildren(List treeDatas, string ID, string? checkId) { List nodeList = new(); //根据ID查询子级 var children = treeDatas.Where(q => q.ParentId == ID); foreach (var dr in children) { //组装数据 TreeListDto node = new() { name = dr.Name, ParentID = dr.ParentId, value = dr.Id, IsEnable = dr.IsEnable }; //是否选中 if (!string.IsNullOrEmpty(checkId) && checkId != Guid.Empty.ToString() && checkId == dr.Id) node.selected = true; //子级数据赋值 node.children = GetChildren(treeDatas, node.value, checkId); //添加数据 nodeList.Add(node); } return nodeList; } #endregion #region 获取全称 /// /// 获取全称 /// /// /// private async Task GetFullName(string? Id) { //获取全部父级名称 var list = await GetParentNode(Id); //倒叙 list.Reverse(); //拆分 return string.Join("-", list.ToArray()); } /// /// 查询父级名称 /// /// /// private async Task> GetParentNode(string? Id) { List list = new(); //查询父级数据 var type = await _caseTypeRepository.GetAsync(p => p.Id == Id); if (type != null) { //添加名称 list.Add(type.Name); list.AddRange(await GetParentNode(type.ParentId)); } return list; } #endregion #region 修改子级分类全称 /// /// 修改子级分类全称 /// /// /// private async Task UpdateChildNode(string Id) { //查询子分类 var list = await GetChildNode(Id); if (list is not null && list.Count > 0) { foreach (var item in list) { //获取全称 string FullName = await GetFullName(item.ParentId); item.SpliceName = string.IsNullOrEmpty(FullName) ? item.Name : FullName + "-" + item.Name; //修改全称 await _caseTypeRepository.UpdateAsync(item); } } } /// /// 查询子级节点数据 /// /// /// private async Task> GetChildNode(string Id) { List list = new(); //查询数据 var typelist = await _caseTypeRepository.QueryAsync(p => p.ParentId == Id); if (typelist != null) { //处理数据 foreach (var item in typelist) { list.Add(item); list.AddRange(await GetChildNode(item.Id)); } } return list; } #endregion #endregion } }