using Hotline.Planlibrary; using Hotline.Settings.Hotspots; using Hotline.Share.Dtos.Knowledge; using Hotline.Share.Dtos.Planlibrary; using Hotline.Share.Enums.Planlibrary; 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.KnowledgeBase; using Hotline.Repository.SqlSugar.Knowledge; using Hotline.Share.Enums.KnowledgeBase; using Microsoft.AspNetCore.Http; namespace Hotline.Application.Planlibrary { /// /// 预案库处理 /// public class PlanApplication : IPlanApplication, IScopeDependency { #region 注册 private readonly IRepository _planListRepository; //预案库列表 private readonly IRepository _planRelationTypeRepository; //预案库关联类型 private readonly IRepository _planTypeRepository; //预案库分类管理 private readonly IRepository _planTypeOrgRepository; //预案库分类关联机构 private readonly IRepository _planCollectRepository; //预案库收藏评分 private readonly ISessionContext _sessionContext; private readonly IMapper _mapper; private readonly IRepository _hotspotTypeRepository; private readonly IFileRepository _fileRepository; private readonly IBulletinApplication _bulletinApplication; public PlanApplication( IRepository planListRepository, IRepository planRelationTypeRepository, IRepository planTypeRepository, IRepository planTypeOrgRepository, ISessionContext sessionContext, IMapper mapper, IRepository hotspotTypeRepository, IFileRepository fileRepository, IBulletinApplication bulletinApplication, IRepository planCollectRepository) { _planListRepository = planListRepository; _planRelationTypeRepository = planRelationTypeRepository; _planTypeRepository = planTypeRepository; _planTypeOrgRepository = planTypeOrgRepository; _sessionContext = sessionContext; _mapper = mapper; _hotspotTypeRepository = hotspotTypeRepository; _fileRepository = fileRepository; _bulletinApplication = bulletinApplication; _planCollectRepository = planCollectRepository; } #endregion #region 预案库类型管理 #region 预案库类型 - 新增 /// /// 预案库类型 - 新增 /// /// /// /// public async Task AddTypeAsync(AddPlanTypeDto dto, CancellationToken cancellationToken) { var sandard = await _planTypeRepository.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 _planTypeRepository.AddAsync(type, cancellationToken); if (dto.TypeOrgDtos != null && dto.TypeOrgDtos.Any()) { List orgs = _mapper.Map>(dto.TypeOrgDtos); orgs.ForEach(x => x.TypeId = type.Id); await _planTypeOrgRepository.AddRangeAsync(orgs, cancellationToken); } return id; } #endregion #region 预案库类型 - 编辑 /// /// 预案库类型 - 编辑 /// /// /// /// public async Task UpdateTypeAsync(UpdatePlanTypeDto dto, CancellationToken cancellationToken) { //查询原有数据 var type = await _planTypeRepository.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 _planTypeRepository.UpdateAsync(type, cancellationToken); //如果修改了名称,对应修改子分类全称 if (result) await UpdateChildNode(type.Id); // 修改关联机构 await _planTypeOrgRepository.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 _planTypeOrgRepository.AddRangeAsync(orgs, cancellationToken); } } #endregion #region 预案库类型 - 删除 /// /// 预案库类型 - 删除 /// /// /// /// public async Task RemoveTypeAsync(string Id, CancellationToken cancellationToken) { //查询数据是否存在 var sandard = await _planTypeRepository.GetAsync(p => p.Id == Id && p.IsDeleted == false, cancellationToken); if (sandard is null) throw UserFriendlyException.SameMessage("分类不存在!"); //查询是否有子级分类 var checkChild = await _planTypeRepository.CountAsync(p => p.ParentId == Id && p.IsDeleted == false, cancellationToken); if (checkChild > 0) throw UserFriendlyException.SameMessage("存在子级分类!"); //查询是否有预案分类 var checkKnowledge = await _planListRepository.CountAsync(p => p.PlanTypes.Any(t => t.PlanId == Id), cancellationToken); if (checkKnowledge > 0) throw UserFriendlyException.SameMessage("分类存在预案!"); //删除操作 await _planTypeRepository.RemoveAsync(sandard, true, cancellationToken); } #endregion #endregion #region 预案库管理 #region 预案库 - 列表 /// /// 预案库 - 列表 /// /// /// public async Task<(int, IList)> QueryAllPlanListAsync(PlanListDto pagedDto, CancellationToken cancellationToken) { //if (!_sessionContext.OrgIsCenter) //{// 部门只能查询【部门预案库】 // pagedDto.Attribution = "部门预案库"; //} var typeSpliceName = string.Empty; var hotspotHotSpotFullName = string.Empty; if (!string.IsNullOrEmpty(pagedDto.PlanTypeID)) { var type = await _planTypeRepository.GetAsync(x => x.Id == pagedDto.PlanTypeID); typeSpliceName = type?.SpliceName; } if (!string.IsNullOrEmpty(pagedDto.HotspotId)) { var hotspot = await _hotspotTypeRepository.GetAsync(x => x.Id == pagedDto.HotspotId); hotspotHotSpotFullName = hotspot?.HotSpotFullName; } //单表分页 var (total, temp) = await _planListRepository.Queryable() .Includes(x => x.PlanTypes) .Includes(x => x.HotspotType) .Includes(x => x.ExaminMan) .Where(x => x.IsDeleted == false) .Where(x => (x.Status == EPlanStatus.Drafts && x.CreatorId == _sessionContext.UserId) || (x.Status != EPlanStatus.Drafts)) .WhereIF(OrgSeedData.CenterId != pagedDto.CreateOrgId && !string.IsNullOrEmpty(pagedDto.CreateOrgId), x => x.CreatorOrgId != null && x.CreatorOrgId.StartsWith(pagedDto.CreateOrgId!)) .WhereIF(!string.IsNullOrEmpty(pagedDto.Attribution), x => x.Attribution == pagedDto.Attribution) .WhereIF(!string.IsNullOrEmpty(pagedDto.Title), x => x.Title.Contains(pagedDto.Title)) .WhereIF(!string.IsNullOrEmpty(pagedDto.Content), x => x.Content.Contains(pagedDto.Content)) .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 != EPlanStatus.OffShelf && pagedDto.Status != EPlanStatus.NewDrafts && pagedDto.Status != EPlanStatus.All, x => x.Status == pagedDto.Status && ((x.ExpiredTime != null && x.ExpiredTime > DateTime.Now) || x.ExpiredTime == null)) .WhereIF(pagedDto.Status.HasValue && pagedDto.Status == EPlanStatus.OffShelf, x => x.Status == pagedDto.Status || (x.ExpiredTime != null && x.ExpiredTime < DateTime.Now && x.Status != EPlanStatus.Drafts)) .WhereIF(pagedDto.Status.HasValue && pagedDto.Status == EPlanStatus.NewDrafts, x => x.Status == EPlanStatus.Drafts || x.Status == EPlanStatus.Revert || x.Status == EPlanStatus.NewDrafts) .WhereIF(pagedDto.IsPublic.HasValue, x => x.IsPublic == pagedDto.IsPublic) .WhereIF(!string.IsNullOrEmpty(typeSpliceName), x => x.PlanTypes.Any(t => t.PlanTypeSpliceName.StartsWith(typeSpliceName))) .WhereIF(!string.IsNullOrEmpty(hotspotHotSpotFullName), x => x.HotspotType.HotSpotFullName.EndsWith(hotspotHotSpotFullName!)) .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 AddPlanAsync(AddPlanListDto dto, CancellationToken cancellationToken) { var pList = _mapper.Map(dto); var any = await _planListRepository.Queryable().Where(x => x.Status == EPlanStatus.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 _planListRepository.AddAsync(pList, cancellationToken); if (dto.PlanTypes.Any()) { List types = _mapper.Map>(dto.PlanTypes); types.ForEach(x => x.PlanId = pList.Id); await _planRelationTypeRepository.AddRangeAsync(types, cancellationToken); } return pList.Id; } #endregion #region 预案库 - 修改 /// /// 修改 /// /// /// /// public async Task UpdatePlanAsync(UpdatePlanListDto dto, CancellationToken cancellationToken) { var plan = await _planListRepository.GetAsync(dto.Id); if (plan == null) throw UserFriendlyException.SameMessage("预案库查询失败"); if ((plan.Status == EPlanStatus.OnShelf || plan.Status == EPlanStatus.Auditing) && (plan.ExpiredTime.HasValue && plan.ExpiredTime.Value > DateTime.Now)) throw UserFriendlyException.SameMessage("预案库数据不可修改"); var any = await _planListRepository.Queryable().Where(x => x.Status == EPlanStatus.OnShelf && x.Title == dto.Title && x.Id != dto.Id).AnyAsync(); if (any) throw UserFriendlyException.SameMessage("当前预案标题存在重复标题!"); if (dto.ApplyStatus == EPlanApplyStatus.Delete) { plan.Status = (EPlanStatus)dto.Status; plan.ApplyStatus = (EPlanApplyStatus)dto.ApplyStatus; plan.Id = dto.Id; plan.ApplyReason = dto.ApplyReason; } else { _mapper.Map(dto, plan); plan.HotspotId = dto.HotspotId; if (dto.Files != null && dto.Files.Count > 0) plan.FileJson = await _fileRepository.AddFileAsync(dto.Files, plan.Id, "", cancellationToken); else plan.FileJson = new List(); } await _planListRepository.UpdateNullAsync(plan, cancellationToken); if (dto.ApplyStatus != EPlanApplyStatus.Delete) { if (dto.PlanTypes.Any()) { var anyRelationTypes = await _planRelationTypeRepository.Queryable().Where(x => x.PlanId == plan.Id).ToListAsync(); if (anyRelationTypes.Any()) await _planRelationTypeRepository.RemoveRangeAsync(anyRelationTypes); List types = _mapper.Map>(dto.PlanTypes); types.ForEach(x => x.PlanId = dto.Id); await _planRelationTypeRepository.AddRangeAsync(types, cancellationToken); } } } #endregion #region 预案库 - 删除 /// /// 删除 /// /// /// /// public async Task RemovePlanAsync(UpdatePlanListDto dto, CancellationToken cancellationToken) { var plan = await _planListRepository.GetAsync(dto.Id); if (plan == null) throw UserFriendlyException.SameMessage("预案库查询失败"); _mapper.Map(dto, plan); plan.IsDeleted = true; await _planListRepository.UpdateNullAsync(plan, cancellationToken); } #endregion #region 预案库 - 审核 /// /// 审核 /// /// /// /// public async Task AuditPlanAsync(UpdatePlanListDto dto, CancellationToken cancellationToken) { var plan = await _planListRepository.GetAsync(dto.Id); if (plan == null) throw UserFriendlyException.SameMessage("预案库查询失败"); plan.Status = (EPlanStatus)dto.Status!; plan.ApplyStatus = (EPlanApplyStatus)dto.ApplyStatus!; plan.ExaminTime = dto.ExaminTime; plan.ExaminManId = dto.ExaminManId; plan.ExaminOrganizeId = dto.ExaminOrganizeId; plan.ExaminOpinion = dto.ExaminOpinion; plan.UpdateTime = dto.UpdateTime; plan.OnShelfTime = dto.OnShelfTime; plan.OffShelfTime = dto.OffShelfTime; if (plan.ApplyStatus == EPlanApplyStatus.Delete) { plan.IsDeleted = true; } await _planListRepository.UpdateNullAsync(plan, cancellationToken); } #endregion #region 预案库 - 详情 /// /// 详情 /// /// /// 默认不增加,false不增加,true增加浏览量 /// public async Task GetPlanAsync(string Id, bool? IsAddPv, CancellationToken cancellationToken) { var plan = await _planListRepository.GetAsync(Id); if (plan == null) throw UserFriendlyException.SameMessage("预案库查询失败"); ; // 转化 var planInfoDto = _mapper.Map(plan); // 内容 if (plan != null && !string.IsNullOrEmpty(plan.Content)) planInfoDto.Content = _bulletinApplication.GetSiteUrls(plan.Content); // 热点 var hot = await _hotspotTypeRepository.GetAsync(plan.HotspotId, cancellationToken); if (hot != null) planInfoDto.HotspotName = hot.HotSpotFullName; // 分类 var relationType = await _planRelationTypeRepository.QueryAsync(x => x.PlanId == Id && x.CreatorId == _sessionContext.UserId); if (relationType != null) { planInfoDto.PlanTypes = _mapper.Map>(relationType); } // 收藏 var collect = await _planCollectRepository.GetAsync(x => x.PlanId == Id && x.CreatorId == _sessionContext.UserId); if (collect != null) planInfoDto.Collect = _mapper.Map(collect); // 附件 if (planInfoDto.FileJson != null && planInfoDto.FileJson.Any()) { var ids = planInfoDto.FileJson.Select(x => x.Id).ToList(); planInfoDto.Files = await _fileRepository.GetFilesAsync(ids, cancellationToken); } // 更新浏览量 if (IsAddPv == true) { //修改浏览量 plan.PageView++; //修改点击量 await _planListRepository.UpdateAsync(plan, cancellationToken); } return planInfoDto; } #endregion #region 预案库 - 批量导出 /// /// 预案库 - 批量导出 /// /// /// /// public async Task> PlanInfoListExportAsync(PlanInfoExportDto dto, CancellationToken cancellationToken) { var streamList = new Dictionary(); var knowList = await _planListRepository.Queryable() .Where(m => dto.Ids.Contains(m.Id)) .Select(m => new { m.Title, m.Content }) .ToListAsync(cancellationToken); var tasks = knowList.Select(async item => { var stream = await Task.Run(() => item.Content.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 _planTypeRepository.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 _planTypeRepository.UpdateAsync(item); } } } /// /// 查询子级节点数据 /// /// /// private async Task> GetChildNode(string Id) { List list = new(); //查询数据 var typelist = await _planTypeRepository.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 } }