CaseApplication.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. using Hotline.Settings.Hotspots;
  2. using Hotline.Share.Dtos.Knowledge;
  3. using Hotline.Share.Dtos.Caselibrary;
  4. using Hotline.Share.Enums.Caselibrary;
  5. using MapsterMapper;
  6. using XF.Domain.Authentications;
  7. using XF.Domain.Dependency;
  8. using XF.Domain.Exceptions;
  9. using XF.Domain.Repository;
  10. using Hotline.Repository.SqlSugar.Extensions;
  11. using Hotline.SeedData;
  12. using Hotline.File;
  13. using Hotline.Application.Bulletin;
  14. using Hotline.Share.Tools;
  15. using Hotline.Application.Tools;
  16. using SqlSugar;
  17. using Hotline.CaseLibrary;
  18. using Hotline.Orders;
  19. using Hotline.KnowledgeBase;
  20. using Hotline.Share.Enums.Planlibrary;
  21. using System.Numerics;
  22. namespace Hotline.Application.Caselibrary
  23. {
  24. /// <summary>
  25. /// 案例库处理
  26. /// </summary>
  27. public class CaseApplication : ICaseApplication, IScopeDependency
  28. {
  29. #region 注册
  30. private readonly IRepository<CaseList> _caseListRepository; //案例库列表
  31. private readonly IRepository<CaseRelationType> _caseRelationTypeRepository; //案例库关联类型
  32. private readonly IRepository<CaseType> _caseTypeRepository; //案例库分类管理
  33. private readonly IRepository<CaseTypeOrg> _caseTypeOrgRepository; //案例库分类关联机构
  34. private readonly IRepository<CaseCollect> _caseCollectRepository; //案例库收藏评分
  35. private readonly IRepository<Order> _orderRepository; //工单
  36. private readonly IRepository<Hotline.KnowledgeBase.Knowledge> _knowledgeRepository; //知识库
  37. private readonly ISessionContext _sessionContext;
  38. private readonly IMapper _mapper;
  39. private readonly IRepository<Hotspot> _hotspotTypeRepository;
  40. private readonly IFileRepository _fileRepository;
  41. private readonly IBulletinApplication _bulletinApplication;
  42. public CaseApplication(
  43. IRepository<CaseList> caseListRepository,
  44. IRepository<CaseRelationType> caseRelationTypeRepository,
  45. IRepository<CaseType> caseTypeRepository,
  46. IRepository<CaseTypeOrg> caseTypeOrgRepository,
  47. IRepository<CaseCollect> caseCollectRepository,
  48. IRepository<Order> orderRepository,
  49. IRepository<Hotline.KnowledgeBase.Knowledge> knowledgeRepository,
  50. ISessionContext sessionContext,
  51. IMapper mapper,
  52. IRepository<Hotspot> hotspotTypeRepository,
  53. IFileRepository fileRepository,
  54. IBulletinApplication bulletinApplication)
  55. {
  56. _caseListRepository = caseListRepository;
  57. _caseRelationTypeRepository = caseRelationTypeRepository;
  58. _caseTypeRepository = caseTypeRepository;
  59. _caseTypeOrgRepository = caseTypeOrgRepository;
  60. _caseCollectRepository = caseCollectRepository;
  61. _orderRepository = orderRepository;
  62. _knowledgeRepository = knowledgeRepository;
  63. _sessionContext = sessionContext;
  64. _mapper = mapper;
  65. _hotspotTypeRepository = hotspotTypeRepository;
  66. _fileRepository = fileRepository;
  67. _bulletinApplication = bulletinApplication;
  68. }
  69. #endregion
  70. #region 案例库类型管理
  71. #region 案例库类型 - 新增
  72. /// <summary>
  73. /// 案例库类型 - 新增
  74. /// </summary>
  75. /// <param name="dto"></param>
  76. /// <param name="cancellationToken"></param>
  77. /// <returns></returns>
  78. public async Task<string> AddTypeAsync(AddCaseTypeDto dto, CancellationToken cancellationToken)
  79. {
  80. var sandard = await _caseTypeRepository.GetAsync(p => p.ParentId == dto.ParentId && p.Name == dto.Name && p.IsDeleted == false, cancellationToken);
  81. if (sandard is not null)
  82. throw UserFriendlyException.SameMessage("当前层级已存在相同名称的分类!");
  83. var type = _mapper.Map<CaseType>(dto);
  84. type.InitId();
  85. type.IsEnable = true;
  86. //获取分类名称全称
  87. string FullName = await GetFullName(type.ParentId);
  88. //处理全称,如果为第一级直接用全称,否则获取全称后拼接名称
  89. type.SpliceName = string.IsNullOrEmpty(FullName) ? dto.Name : FullName + "-" + dto.Name;
  90. var id = await _caseTypeRepository.AddAsync(type, cancellationToken);
  91. if (dto.TypeOrgDtos != null && dto.TypeOrgDtos.Any())
  92. {
  93. List<CaseTypeOrg> orgs = _mapper.Map<List<CaseTypeOrg>>(dto.TypeOrgDtos);
  94. orgs.ForEach(x => x.TypeId = type.Id);
  95. await _caseTypeOrgRepository.AddRangeAsync(orgs, cancellationToken);
  96. }
  97. return id;
  98. }
  99. #endregion
  100. #region 案例库类型 - 编辑
  101. /// <summary>
  102. /// 案例库类型 - 编辑
  103. /// </summary>
  104. /// <param name="dto"></param>
  105. /// <param name="cancellationToken"></param>
  106. /// <returns></returns>
  107. public async Task UpdateTypeAsync(UpdateCaseTypeDto dto, CancellationToken cancellationToken)
  108. {
  109. //查询原有数据
  110. var type = await _caseTypeRepository.GetAsync(dto.Id, cancellationToken);
  111. if (type is null)
  112. throw UserFriendlyException.SameMessage("编辑失败!");
  113. bool result = type.Name != dto.Name || type.ParentId != dto.ParentId;
  114. //是否更改分类名称或者层级
  115. //转换
  116. _mapper.Map(dto, type);
  117. //如果更改了名称或者修改了层级,则修改全称,未更改不修改
  118. if (result)
  119. {
  120. string FullName = await GetFullName(type.ParentId);//获取分类名称全称
  121. type.SpliceName = string.IsNullOrEmpty(FullName) ? dto.Name : FullName + "-" + dto.Name;//处理全称,如果为第一级直接用全称,否则获取全称后拼接名称
  122. }
  123. //修改数据
  124. await _caseTypeRepository.UpdateAsync(type, cancellationToken);
  125. //如果修改了名称,对应修改子分类全称
  126. if (result)
  127. await UpdateChildNode(type.Id);
  128. // 修改关联机构
  129. await _caseTypeOrgRepository.RemoveAsync(x => x.TypeId == type.Id, false, cancellationToken);
  130. if (dto.TypeOrgDtos != null && dto.TypeOrgDtos.Any())
  131. {
  132. List<CaseTypeOrg> orgs = _mapper.Map<List<CaseTypeOrg>>(dto.TypeOrgDtos);
  133. orgs.ForEach(x => x.TypeId = type.Id);
  134. await _caseTypeOrgRepository.AddRangeAsync(orgs, cancellationToken);
  135. }
  136. }
  137. #endregion
  138. #region 案例库类型 - 删除
  139. /// <summary>
  140. /// 案例库类型 - 删除
  141. /// </summary>
  142. /// <param name="Id"></param>
  143. /// <param name="cancellationToken"></param>
  144. /// <returns></returns>
  145. public async Task RemoveTypeAsync(string Id, CancellationToken cancellationToken)
  146. {
  147. //查询数据是否存在
  148. var sandard = await _caseTypeRepository.GetAsync(p => p.Id == Id && p.IsDeleted == false, cancellationToken);
  149. if (sandard is null)
  150. throw UserFriendlyException.SameMessage("分类不存在!");
  151. //查询是否有子级分类
  152. var checkChild = await _caseTypeRepository.CountAsync(p => p.ParentId == Id && p.IsDeleted == false, cancellationToken);
  153. if (checkChild > 0)
  154. throw UserFriendlyException.SameMessage("存在子级分类!");
  155. //查询是否有案例分类
  156. var checkKnowledge = await _caseListRepository.CountAsync(p => p.CaseTypes.Any(t => t.CaseId == Id), cancellationToken);
  157. if (checkKnowledge > 0)
  158. throw UserFriendlyException.SameMessage("分类存在案例!");
  159. //删除操作
  160. await _caseTypeRepository.RemoveAsync(sandard, true, cancellationToken);
  161. }
  162. #endregion
  163. #endregion
  164. #region 案例库管理
  165. #region 案例库 - 列表
  166. /// <summary>
  167. /// 案例库 - 列表
  168. /// </summary>
  169. /// <param name="pagedDto"></param>
  170. /// <returns></returns>
  171. public async Task<(int, IList<CaseDataDto>)> QueryAllCaseListAsync(CaseListDto pagedDto, CancellationToken cancellationToken)
  172. {
  173. var typeSpliceName = string.Empty;
  174. if (!string.IsNullOrEmpty(pagedDto.CaseTypeID))
  175. {
  176. var type = await _caseTypeRepository.GetAsync(x => x.Id == pagedDto.CaseTypeID);
  177. typeSpliceName = type?.SpliceName;
  178. }
  179. //单表分页
  180. var (total, temp) = await _caseListRepository.Queryable()
  181. .Includes(x => x.CaseTypes)
  182. .Includes(x => x.ExaminMan)
  183. .Where(x => x.IsDeleted == false)
  184. .Where(x => (x.Status == ECaseStatus.Drafts && x.CreatorId == _sessionContext.UserId) || (x.Status != ECaseStatus.Drafts))
  185. .WhereIF(OrgSeedData.CenterId != pagedDto.CreateOrgId && !string.IsNullOrEmpty(pagedDto.CreateOrgId), x => x.CreatorOrgId != null && x.CreatorOrgId.StartsWith(pagedDto.CreateOrgId!))
  186. .WhereIF(!string.IsNullOrEmpty(pagedDto.Title), x => x.Title.Contains(pagedDto.Title))
  187. .WhereIF(!string.IsNullOrEmpty(pagedDto.Abstract), x => x.Abstract.Contains(pagedDto.Abstract))
  188. .WhereIF(!string.IsNullOrEmpty(pagedDto.Describe), x => x.Describe.Contains(pagedDto.Describe))
  189. .WhereIF(!string.IsNullOrEmpty(pagedDto.Result), x => x.Result.Contains(pagedDto.Result))
  190. .WhereIF(!string.IsNullOrEmpty(pagedDto.Reason), x => x.Reason.Contains(pagedDto.Reason))
  191. .WhereIF(!string.IsNullOrEmpty(pagedDto.Keyword), x => x.Title.Contains(pagedDto.Keyword!) ||
  192. x.CreatorName!.Contains(pagedDto.Keyword!) ||
  193. x.CreatorOrgName!.Contains(pagedDto.Keyword!))
  194. .WhereIF(pagedDto.Status.HasValue && pagedDto.Status != ECaseStatus.OffShelf &&
  195. pagedDto.Status != ECaseStatus.NewDrafts &&
  196. pagedDto.Status != ECaseStatus.All,
  197. x => x.Status == pagedDto.Status && ((x.ExpiredTime != null && x.ExpiredTime > DateTime.Now) || x.ExpiredTime == null))
  198. .WhereIF(pagedDto.Status.HasValue && pagedDto.Status == ECaseStatus.OffShelf, x => x.Status == pagedDto.Status || (x.ExpiredTime != null && x.ExpiredTime < DateTime.Now && x.Status != ECaseStatus.Drafts))
  199. .WhereIF(pagedDto.Status.HasValue && pagedDto.Status == ECaseStatus.NewDrafts, x => x.Status == ECaseStatus.Drafts || x.Status == ECaseStatus.Revert || x.Status == ECaseStatus.NewDrafts)
  200. .WhereIF(!string.IsNullOrEmpty(typeSpliceName), x => x.CaseTypes.Any(t => t.CaseTypeSpliceName.StartsWith(typeSpliceName)))
  201. .WhereIF(pagedDto.CreationTimeStart.HasValue, x => x.CreationTime >= pagedDto.CreationTimeStart)
  202. .WhereIF(pagedDto.CreationTimeEnd.HasValue, x => x.CreationTime <= pagedDto.CreationTimeEnd)
  203. .WhereIF(pagedDto.OnShelfTimeStart.HasValue, x => x.OnShelfTime >= pagedDto.OnShelfTimeStart)
  204. .WhereIF(pagedDto.OnShelfTimeEnd.HasValue, x => x.OnShelfTime <= pagedDto.OnShelfTimeEnd)
  205. .WhereIF(pagedDto.OffShelfTimeStart.HasValue, x => x.OffShelfTime >= pagedDto.OffShelfTimeStart)
  206. .WhereIF(pagedDto.OffShelfTimeEnd.HasValue, x => x.OffShelfTime <= pagedDto.OffShelfTimeEnd)
  207. .WhereIF(pagedDto.UpdateTimeStart.HasValue, x => x.UpdateTime >= pagedDto.UpdateTimeStart)
  208. .WhereIF(pagedDto.UpdateTimeEnd.HasValue, x => x.UpdateTime <= pagedDto.UpdateTimeEnd)
  209. .WhereIF(pagedDto.ExaminTimeStart.HasValue, x => x.ExaminTime >= pagedDto.ExaminTimeStart)
  210. .WhereIF(pagedDto.ExaminTimeEnd.HasValue, x => x.ExaminTime <= pagedDto.ExaminTimeEnd)
  211. .OrderByIF(string.IsNullOrEmpty(pagedDto.SortField), x => x.CreationTime, OrderByType.Desc)
  212. .OrderByIF(pagedDto is { SortField: "pageView" }, x => x.PageView, OrderByType.Desc) //阅读量
  213. .OrderByIF(pagedDto is { SortField: "score" }, x => x.Score, OrderByType.Desc) //评分
  214. .OrderByIF(pagedDto is { SortField: "creationTime" }, x => x.CreationTime, OrderByType.Desc) //创建时间
  215. .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize, cancellationToken);
  216. return (total, _mapper.Map<IList<CaseDataDto>>(temp));
  217. }
  218. #endregion
  219. #region 案例库 - 新增
  220. /// <summary>
  221. /// 新增
  222. /// </summary>
  223. /// <param name="dto"></param>
  224. /// <param name="cancellationToken"></param>
  225. /// <returns></returns>
  226. public async Task<string> AddCaseAsync(AddCaseListDto dto, CancellationToken cancellationToken)
  227. {
  228. var pList = _mapper.Map<CaseList>(dto);
  229. var any = await _caseListRepository.Queryable().Where(x => x.Status == ECaseStatus.OnShelf && x.Title == dto.Title).AnyAsync();
  230. if (any)
  231. throw UserFriendlyException.SameMessage("当前案例标题存在重复标题!");
  232. if (dto.Files != null && dto.Files.Count > 0)
  233. pList.FileJson = await _fileRepository.AddFileAsync(dto.Files, pList.Id, "", cancellationToken);
  234. await _caseListRepository.AddAsync(pList, cancellationToken);
  235. if (dto.CaseTypes.Any())
  236. {
  237. List<CaseRelationType> types = _mapper.Map<List<CaseRelationType>>(dto.CaseTypes);
  238. types.ForEach(x => x.CaseId = pList.Id);
  239. await _caseRelationTypeRepository.AddRangeAsync(types, cancellationToken);
  240. }
  241. return pList.Id;
  242. }
  243. #endregion
  244. #region 案例库 - 修改
  245. /// <summary>
  246. /// 修改
  247. /// </summary>
  248. /// <param name="dto"></param>
  249. /// <param name="cancellationToken"></param>
  250. /// <returns></returns>
  251. public async Task UpdateCaseAsync(UpdateCaseListDto dto, CancellationToken cancellationToken)
  252. {
  253. var Case = await _caseListRepository.GetAsync(dto.Id);
  254. if (Case == null)
  255. throw UserFriendlyException.SameMessage("案例库查询失败");
  256. if ((Case.Status == ECaseStatus.OnShelf || Case.Status == ECaseStatus.Auditing) && (Case.ExpiredTime.HasValue && Case.ExpiredTime.Value > DateTime.Now))
  257. throw UserFriendlyException.SameMessage("案例库数据不可修改");
  258. var any = await _caseListRepository.Queryable().Where(x => x.Status == ECaseStatus.OnShelf && x.Title == dto.Title && x.Id != dto.Id).AnyAsync();
  259. if (any)
  260. throw UserFriendlyException.SameMessage("当前案例标题存在重复标题!");
  261. if (dto.ApplyStatus == ECaseApplyStatus.Delete)
  262. {
  263. Case.Status = (ECaseStatus)dto.Status;
  264. Case.ApplyStatus = (ECaseApplyStatus)dto.ApplyStatus;
  265. Case.Id = dto.Id;
  266. Case.ApplyReason = dto.ApplyReason;
  267. }
  268. else
  269. {
  270. _mapper.Map(dto, Case);
  271. if (dto.Files != null && dto.Files.Count > 0)
  272. Case.FileJson = await _fileRepository.AddFileAsync(dto.Files, Case.Id, "", cancellationToken);
  273. else
  274. Case.FileJson = new List<Share.Dtos.File.FileJson>();
  275. }
  276. await _caseListRepository.UpdateNullAsync(Case, cancellationToken);
  277. if (dto.ApplyStatus != ECaseApplyStatus.Delete)
  278. {
  279. if (dto.CaseTypes.Any())
  280. {
  281. var anyRelationTypes = await _caseRelationTypeRepository.Queryable().Where(x => x.CaseId == Case.Id).ToListAsync();
  282. if (anyRelationTypes.Any())
  283. await _caseRelationTypeRepository.RemoveRangeAsync(anyRelationTypes);
  284. List<CaseRelationType> types = _mapper.Map<List<CaseRelationType>>(dto.CaseTypes);
  285. types.ForEach(x => x.CaseId = dto.Id);
  286. await _caseRelationTypeRepository.AddRangeAsync(types, cancellationToken);
  287. }
  288. }
  289. }
  290. #endregion
  291. #region 案例库 - 删除
  292. /// <summary>
  293. /// 删除
  294. /// </summary>
  295. /// <param name="dto"></param>
  296. /// <param name="cancellationToken"></param>
  297. /// <returns></returns>
  298. public async Task RemoveCaseAsync(UpdateCaseListDto dto, CancellationToken cancellationToken)
  299. {
  300. var Case = await _caseListRepository.GetAsync(dto.Id);
  301. if (Case == null)
  302. throw UserFriendlyException.SameMessage("案例库查询失败");
  303. _mapper.Map(dto, Case);
  304. Case.IsDeleted = true;
  305. await _caseListRepository.UpdateNullAsync(Case, cancellationToken);
  306. }
  307. #endregion
  308. #region 案例库 - 审核
  309. /// <summary>
  310. /// 审核
  311. /// </summary>
  312. /// <param name="dto"></param>
  313. /// <param name="cancellationToken"></param>
  314. /// <returns></returns>
  315. public async Task AuditCaseAsync(UpdateCaseListDto dto, CancellationToken cancellationToken)
  316. {
  317. var Case = await _caseListRepository.GetAsync(dto.Id);
  318. if (Case == null)
  319. throw UserFriendlyException.SameMessage("案例库查询失败");
  320. Case.Status = (ECaseStatus)dto.Status!;
  321. Case.ApplyStatus = (ECaseApplyStatus)dto.ApplyStatus!;
  322. Case.ExaminTime = dto.ExaminTime;
  323. Case.ExaminManId = dto.ExaminManId;
  324. Case.ExaminOrganizeId = dto.ExaminOrganizeId;
  325. Case.ExaminOpinion = dto.ExaminOpinion;
  326. Case.UpdateTime = dto.UpdateTime;
  327. Case.OnShelfTime = dto.OnShelfTime;
  328. Case.OffShelfTime = dto.OffShelfTime;
  329. if (Case.ApplyStatus == ECaseApplyStatus.Delete)
  330. {
  331. Case.IsDeleted = true;
  332. }
  333. await _caseListRepository.UpdateNullAsync(Case, cancellationToken);
  334. }
  335. #endregion
  336. #region 案例库 - 详情
  337. /// <summary>
  338. /// 详情
  339. /// </summary>
  340. /// <param name="Id"></param>
  341. /// <param name="IsAddPv">默认不增加,false不增加,true增加浏览量</param>
  342. /// <returns></returns>
  343. public async Task<CaseInfoDto> GetCaseAsync(string Id, bool? IsAddPv, CancellationToken cancellationToken)
  344. {
  345. var Case = await _caseListRepository.GetAsync(Id);
  346. if (Case == null)
  347. throw UserFriendlyException.SameMessage("案例库查询失败");
  348. ;
  349. //转化
  350. var CaseInfoDto = _mapper.Map<CaseInfoDto>(Case);
  351. if (Case != null)
  352. {
  353. if (!string.IsNullOrEmpty(Case.Describe))
  354. CaseInfoDto.Abstract = _bulletinApplication.GetSiteUrls(Case.Abstract);
  355. if (!string.IsNullOrEmpty(Case.Describe))
  356. CaseInfoDto.Describe = _bulletinApplication.GetSiteUrls(Case.Describe);
  357. if (!string.IsNullOrEmpty(Case.Result))
  358. CaseInfoDto.Result = _bulletinApplication.GetSiteUrls(Case.Result);
  359. if (!string.IsNullOrEmpty(Case.Reason))
  360. CaseInfoDto.Reason = _bulletinApplication.GetSiteUrls(Case.Reason);
  361. }
  362. // 分类
  363. var relationType = await _caseRelationTypeRepository.QueryAsync(x => x.CaseId == Id && x.CreatorId == _sessionContext.UserId);
  364. if (relationType != null)
  365. {
  366. CaseInfoDto.CaseTypes = _mapper.Map<List<CaseRelationTypeDto>>(relationType);
  367. }
  368. // 收藏
  369. var collect = await _caseCollectRepository.GetAsync(x => x.CaseId == Id && x.CreatorId == _sessionContext.UserId);
  370. if (collect != null)
  371. CaseInfoDto.Collect = _mapper.Map<CaseCollectDto>(collect);
  372. // 工单
  373. var order = await _orderRepository.GetAsync(x => x.Id == CaseInfoDto.OrderId, cancellationToken);
  374. if (order != null)
  375. CaseInfoDto.OrderTitle = order.Title;
  376. // 知识库
  377. var knowledge = await _knowledgeRepository.GetAsync(x => x.Id == CaseInfoDto.KnowledgeId, cancellationToken);
  378. if (knowledge != null)
  379. CaseInfoDto.KnowledgeTitle = knowledge.Title;
  380. // 附件
  381. if (CaseInfoDto.FileJson != null && CaseInfoDto.FileJson.Any())
  382. {
  383. var ids = CaseInfoDto.FileJson.Select(x => x.Id).ToList();
  384. CaseInfoDto.Files = await _fileRepository.GetFilesAsync(ids, cancellationToken);
  385. }
  386. // 更新浏览量
  387. if (IsAddPv == true)
  388. {
  389. //修改浏览量
  390. Case.PageView++;
  391. //修改点击量
  392. await _caseListRepository.UpdateAsync(Case, cancellationToken);
  393. }
  394. return CaseInfoDto;
  395. }
  396. #endregion
  397. #region 案例库 - 批量导出
  398. /// <summary>
  399. /// 案例库 - 批量导出
  400. /// </summary>
  401. /// <param name="dto"></param>
  402. /// <param name="cancellationToken"></param>
  403. /// <returns></returns>
  404. public async Task<Dictionary<string, Stream>> CaseInfoListExportAsync(CaseInfoExportDto dto, CancellationToken cancellationToken)
  405. {
  406. var streamList = new Dictionary<string, Stream>();
  407. var knowList = await _caseListRepository.Queryable()
  408. .Where(m => dto.Ids.Contains(m.Id))
  409. .Select(m => new { m.Title, m.Result })
  410. .ToListAsync(cancellationToken);
  411. var tasks = knowList.Select(async item =>
  412. {
  413. var stream = await Task.Run(() => item.Result.HtmlToStream(dto.FileType), cancellationToken);
  414. return new KeyValuePair<string, Stream>(
  415. item.Title + dto.FileType.GetFileExtension(),
  416. stream
  417. );
  418. });
  419. var results = await Task.WhenAll(tasks);
  420. foreach (var kvp in results)
  421. {
  422. if (!streamList.ContainsKey(kvp.Key))
  423. {
  424. streamList.Add(kvp.Key, kvp.Value);
  425. }
  426. }
  427. return streamList;
  428. }
  429. #endregion
  430. #endregion
  431. #region 私有方法
  432. #region 查询所有子级
  433. /// <summary>
  434. /// 查询所有子级
  435. /// </summary>
  436. /// <param name="treeDatas">分类数据</param>
  437. /// <param name="ID">需要查询哪级下面的分类</param>
  438. /// <param name="checkId">选中的数据ID</param>
  439. /// <returns></returns>
  440. private List<TreeListDto> GetChildren(List<CaseType> treeDatas, string ID, string? checkId)
  441. {
  442. List<TreeListDto> nodeList = new();
  443. //根据ID查询子级
  444. var children = treeDatas.Where(q => q.ParentId == ID);
  445. foreach (var dr in children)
  446. {
  447. //组装数据
  448. TreeListDto node = new()
  449. {
  450. name = dr.Name,
  451. ParentID = dr.ParentId,
  452. value = dr.Id,
  453. IsEnable = dr.IsEnable
  454. };
  455. //是否选中
  456. if (!string.IsNullOrEmpty(checkId) && checkId != Guid.Empty.ToString() && checkId == dr.Id)
  457. node.selected = true;
  458. //子级数据赋值
  459. node.children = GetChildren(treeDatas, node.value, checkId);
  460. //添加数据
  461. nodeList.Add(node);
  462. }
  463. return nodeList;
  464. }
  465. #endregion
  466. #region 获取全称
  467. /// <summary>
  468. /// 获取全称
  469. /// </summary>
  470. /// <param name="Id"></param>
  471. /// <returns></returns>
  472. private async Task<string> GetFullName(string? Id)
  473. {
  474. //获取全部父级名称
  475. var list = await GetParentNode(Id);
  476. //倒叙
  477. list.Reverse();
  478. //拆分
  479. return string.Join("-", list.ToArray());
  480. }
  481. /// <summary>
  482. /// 查询父级名称
  483. /// </summary>
  484. /// <param name="Id"></param>
  485. /// <returns></returns>
  486. private async Task<List<string>> GetParentNode(string? Id)
  487. {
  488. List<string> list = new();
  489. //查询父级数据
  490. var type = await _caseTypeRepository.GetAsync(p => p.Id == Id);
  491. if (type != null)
  492. {
  493. //添加名称
  494. list.Add(type.Name);
  495. list.AddRange(await GetParentNode(type.ParentId));
  496. }
  497. return list;
  498. }
  499. #endregion
  500. #region 修改子级分类全称
  501. /// <summary>
  502. /// 修改子级分类全称
  503. /// </summary>
  504. /// <param name="Id"></param>
  505. /// <returns></returns>
  506. private async Task UpdateChildNode(string Id)
  507. {
  508. //查询子分类
  509. var list = await GetChildNode(Id);
  510. if (list is not null && list.Count > 0)
  511. {
  512. foreach (var item in list)
  513. {
  514. //获取全称
  515. string FullName = await GetFullName(item.ParentId);
  516. item.SpliceName = string.IsNullOrEmpty(FullName) ? item.Name : FullName + "-" + item.Name;
  517. //修改全称
  518. await _caseTypeRepository.UpdateAsync(item);
  519. }
  520. }
  521. }
  522. /// <summary>
  523. /// 查询子级节点数据
  524. /// </summary>
  525. /// <param name="Id"></param>
  526. /// <returns></returns>
  527. private async Task<List<CaseType>> GetChildNode(string Id)
  528. {
  529. List<CaseType> list = new();
  530. //查询数据
  531. var typelist = await _caseTypeRepository.QueryAsync(p => p.ParentId == Id);
  532. if (typelist != null)
  533. {
  534. //处理数据
  535. foreach (var item in typelist)
  536. {
  537. list.Add(item);
  538. list.AddRange(await GetChildNode(item.Id));
  539. }
  540. }
  541. return list;
  542. }
  543. #endregion
  544. #endregion
  545. }
  546. }