HomeController.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. using EFSecondLevelCache.Core;
  2. using Masuit.LuceneEFCore.SearchEngine.Linq;
  3. using Masuit.MyBlogs.Core.Extensions;
  4. using Masuit.MyBlogs.Core.Infrastructure.Repository;
  5. using Masuit.MyBlogs.Core.Infrastructure.Services.Interface;
  6. using Masuit.MyBlogs.Core.Models;
  7. using Masuit.MyBlogs.Core.Models.DTO;
  8. using Masuit.MyBlogs.Core.Models.Entity;
  9. using Masuit.MyBlogs.Core.Models.Enum;
  10. using Masuit.MyBlogs.Core.Models.ViewModel;
  11. using Masuit.Tools.Systems;
  12. using Microsoft.AspNetCore.Mvc;
  13. using System;
  14. using System.Collections.Generic;
  15. using System.ComponentModel.DataAnnotations;
  16. using System.Linq;
  17. using System.Linq.Dynamic.Core;
  18. using System.Linq.Expressions;
  19. using System.Runtime.InteropServices;
  20. using System.Threading.Tasks;
  21. namespace Masuit.MyBlogs.Core.Controllers
  22. {
  23. /// <summary>
  24. /// 首页
  25. /// </summary>
  26. public class HomeController : BaseController
  27. {
  28. /// <summary>
  29. /// 文章
  30. /// </summary>
  31. public IPostService PostService { get; set; }
  32. /// <summary>
  33. /// 分类
  34. /// </summary>
  35. public ICategoryService CategoryService { get; set; }
  36. /// <summary>
  37. /// 网站公告
  38. /// </summary>
  39. public INoticeService NoticeService { get; set; }
  40. /// <summary>
  41. /// 快速分享
  42. /// </summary>
  43. public IFastShareService FastShareService { get; set; }
  44. /// <summary>
  45. /// 首页
  46. /// </summary>
  47. /// <returns></returns>
  48. [HttpGet, ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "orderBy" }, VaryByHeader = "Cookie")]
  49. public ActionResult Index()
  50. {
  51. var banners = AdsService.GetsByWeightedPrice(8, AdvertiseType.Banner).OrderBy(a => Guid.NewGuid()).ToList();
  52. var fastShares = FastShareService.GetAllFromCache(s => s.Sort).ToList();
  53. var postsQuery = PostService.GetQuery<PostDto>(p => (p.Status == Status.Pended || CurrentUser.IsAdmin)); //准备文章的查询
  54. var posts = postsQuery.Where(p => !p.IsFixedTop).OrderBy(OrderBy.ModifyDate.GetDisplay() + " desc").ToCachedPagedList(1, 15);
  55. posts.Data.InsertRange(0, postsQuery.Where(p => p.IsFixedTop).OrderByDescending(p => p.ModifyDate).ToList());
  56. var viewModel = GetIndexPageViewModel();
  57. viewModel.Banner = banners;
  58. viewModel.Posts = posts;
  59. ViewBag.FastShare = fastShares;
  60. viewModel.PageParams = new Pagination(1, 15, posts.TotalCount, OrderBy.ModifyDate);
  61. return View(viewModel);
  62. }
  63. /// <summary>
  64. /// 文章列表页
  65. /// </summary>
  66. /// <param name="page"></param>
  67. /// <param name="size"></param>
  68. /// <param name="orderBy"></param>
  69. /// <returns></returns>
  70. [Route("p"), ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "page", "size", "orderBy" }, VaryByHeader = "Cookie")]
  71. public ActionResult Post([Optional]OrderBy? orderBy, [Range(1, int.MaxValue, ErrorMessage = "页码必须大于0")]int page = 1, [Range(1, int.MaxValue, ErrorMessage = "页大小必须大于0")]int size = 15)
  72. {
  73. var viewModel = GetIndexPageViewModel();
  74. var postsQuery = PostService.GetQuery<PostDto>(p => (p.Status == Status.Pended || CurrentUser.IsAdmin)); //准备文章的查询
  75. var posts = postsQuery.Where(p => !p.IsFixedTop).OrderBy((orderBy ?? OrderBy.ModifyDate).GetDisplay() + " desc").ToCachedPagedList(page, size);
  76. if (page == 1)
  77. {
  78. posts.Data.InsertRange(0, postsQuery.Where(p => p.IsFixedTop).OrderByDescending(p => p.ModifyDate).ToList());
  79. }
  80. viewModel.Posts = posts;
  81. viewModel.PageParams = new Pagination(1, 15, posts.TotalCount, OrderBy.ModifyDate);
  82. return View(viewModel);
  83. }
  84. /// <summary>
  85. /// 标签文章页
  86. /// </summary>
  87. /// <param name="id"></param>
  88. /// <param name="page"></param>
  89. /// <param name="size"></param>
  90. /// <param name="orderBy"></param>
  91. /// <returns></returns>
  92. [Route("tag/{id}/{page:int?}/{size:int?}/{orderBy:int?}"), ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "id", "page", "size", "orderBy" }, VaryByHeader = "Cookie")]
  93. public ActionResult Tag(string id, [Optional]OrderBy? orderBy, [Range(1, int.MaxValue, ErrorMessage = "页码必须大于0")]int page = 1, [Range(1, int.MaxValue, ErrorMessage = "页大小必须大于0")]int size = 15)
  94. {
  95. var posts = PostService.GetQuery<PostDto>(p => p.Label.Contains(id) && (p.Status == Status.Pended || CurrentUser.IsAdmin)).OrderBy($"{nameof(PostDto.IsFixedTop)} desc,{(orderBy ?? OrderBy.ModifyDate).GetDisplay()} desc").ToCachedPagedList(page, size);
  96. var viewModel = GetIndexPageViewModel();
  97. ViewBag.Tag = id;
  98. viewModel.Posts = posts;
  99. viewModel.PageParams = new Pagination(1, 15, posts.TotalCount, OrderBy.ModifyDate);
  100. return View(viewModel);
  101. }
  102. /// <summary>
  103. /// 作者文章页
  104. /// </summary>
  105. /// <param name="author"></param>
  106. /// <param name="page"></param>
  107. /// <param name="size"></param>
  108. /// <param name="orderBy"></param>
  109. /// <returns></returns>
  110. [Route("author/{author}/{page:int?}/{size:int?}/{orderBy:int?}"), ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "author", "page", "size", "orderBy" }, VaryByHeader = "Cookie")]
  111. public ActionResult Author(string author, [Optional]OrderBy? orderBy, [Range(1, int.MaxValue, ErrorMessage = "页码必须大于0")]int page = 1, [Range(1, int.MaxValue, ErrorMessage = "页大小必须大于0")]int size = 15)
  112. {
  113. Expression<Func<Post, bool>> where = p => p.Author.Equals(author) || p.Modifier.Equals(author) || p.Email.Equals(author) || p.PostHistoryVersion.Any(v => v.Modifier.Equals(author) || v.ModifierEmail.Equals(author));
  114. where = where.And(p => p.Status == Status.Pended || CurrentUser.IsAdmin);
  115. var posts = PostService.GetQuery<PostDto>(where).OrderBy($"{nameof(PostDto.IsFixedTop)} desc,{(orderBy ?? OrderBy.ModifyDate).GetDisplay()} desc").ToCachedPagedList(page, size);
  116. var viewModel = GetIndexPageViewModel();
  117. ViewBag.Author = author;
  118. viewModel.Posts = posts;
  119. viewModel.PageParams = new Pagination(1, 15, posts.TotalCount, OrderBy.ModifyDate);
  120. return View(viewModel);
  121. }
  122. /// <summary>
  123. /// 分类文章页
  124. /// </summary>
  125. /// <param name="id"></param>
  126. /// <param name="page"></param>
  127. /// <param name="size"></param>
  128. /// <param name="orderBy"></param>
  129. /// <returns></returns>
  130. [Route("cat/{id:int}"), ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "id", "page", "size", "orderBy" }, VaryByHeader = "Cookie")]
  131. [Route("cat/{id:int}/{page:int?}/{size:int?}/{orderBy:int?}")]
  132. public async Task<ActionResult> Category(int id, [Optional]OrderBy? orderBy, [Range(1, int.MaxValue, ErrorMessage = "页码必须大于0")]int page = 1, [Range(1, int.MaxValue, ErrorMessage = "页大小必须大于0")]int size = 15)
  133. {
  134. var cat = await CategoryService.GetByIdAsync(id) ?? throw new NotFoundException("文章分类未找到");
  135. var posts = PostService.GetQuery<PostDto>(p => p.CategoryId == cat.Id && (p.Status == Status.Pended || CurrentUser.IsAdmin)).OrderBy($"{nameof(PostDto.IsFixedTop)} desc,{(orderBy ?? OrderBy.ModifyDate).GetDisplay()} desc").ToCachedPagedList(page, size);
  136. var viewModel = GetIndexPageViewModel();
  137. viewModel.Posts = posts;
  138. ViewBag.Category = cat;
  139. viewModel.PageParams = new Pagination(1, 15, posts.TotalCount, OrderBy.ModifyDate);
  140. return View(viewModel);
  141. }
  142. /// <summary>
  143. /// 获取页面视图模型
  144. /// </summary>
  145. /// <returns></returns>
  146. private HomePageViewModel GetIndexPageViewModel()
  147. {
  148. var postsQuery = PostService.GetQuery<PostDto>(p => (p.Status == Status.Pended || CurrentUser.IsAdmin)); //准备文章的查询
  149. var notices = NoticeService.GetPagesFromCache<DateTime, NoticeDto>(1, 5, n => (n.Status == Status.Display || CurrentUser.IsAdmin), n => n.ModifyDate, false); //加载前5条公告
  150. var cats = CategoryService.GetQueryFromCache<string, CategoryDto>(c => c.Status == Status.Available, c => c.Name).ToList(); //加载分类目录
  151. var hotSearches = RedisHelper.Get<List<KeywordsRank>>("SearchRank:Week").Take(10).ToList(); //热词统计
  152. var hot6Post = postsQuery.OrderBy((new Random().Next() % 3) switch
  153. {
  154. 1 => nameof(OrderBy.VoteUpCount),
  155. 2 => nameof(OrderBy.AverageViewCount),
  156. _ => nameof(OrderBy.TotalViewCount)
  157. } + " desc").Skip(0).Take(5).Cacheable().ToList(); //热门文章
  158. var newdic = new Dictionary<string, int>(); //标签云最终结果
  159. var tagdic = postsQuery.Where(p => !string.IsNullOrEmpty(p.Label)).Select(p => p.Label).Distinct().Cacheable().AsParallel().SelectMany(s => s.Split(',', ',')).GroupBy(s => s).ToDictionary(g => g.Key, g => g.Count()); //统计标签
  160. if (tagdic.Any())
  161. {
  162. var min = tagdic.Values.Min();
  163. foreach (var (key, value) in tagdic)
  164. {
  165. var fontsize = (int)Math.Floor(value * 1.0 / (min * 1.0) + 12.0);
  166. newdic.Add(key, fontsize >= 36 ? 36 : fontsize);
  167. }
  168. }
  169. return new HomePageViewModel()
  170. {
  171. Categories = cats,
  172. HotSearch = hotSearches,
  173. Notices = notices.Data,
  174. Tags = newdic,
  175. Top6Post = hot6Post,
  176. PostsQueryable = postsQuery,
  177. SidebarAds = AdsService.GetsByWeightedPrice(2, AdvertiseType.SideBar),
  178. ListAdvertisement = AdsService.GetByWeightedPrice(AdvertiseType.PostList)
  179. };
  180. }
  181. }
  182. }