using EFSecondLevelCache.Core; using Masuit.LuceneEFCore.SearchEngine.Linq; using Masuit.MyBlogs.Core.Extensions; using Masuit.MyBlogs.Core.Infrastructure.Repository; using Masuit.MyBlogs.Core.Infrastructure.Services.Interface; using Masuit.MyBlogs.Core.Models; using Masuit.MyBlogs.Core.Models.DTO; using Masuit.MyBlogs.Core.Models.Entity; using Masuit.MyBlogs.Core.Models.Enum; using Masuit.MyBlogs.Core.Models.ViewModel; using Masuit.Tools.Systems; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Linq.Dynamic.Core; using System.Linq.Expressions; using System.Runtime.InteropServices; using System.Threading.Tasks; namespace Masuit.MyBlogs.Core.Controllers { /// /// 首页 /// public class HomeController : BaseController { /// /// 文章 /// public IPostService PostService { get; set; } /// /// 分类 /// public ICategoryService CategoryService { get; set; } /// /// 网站公告 /// public INoticeService NoticeService { get; set; } /// /// 快速分享 /// public IFastShareService FastShareService { get; set; } /// /// 首页 /// /// [HttpGet, ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "orderBy" }, VaryByHeader = "Cookie")] public ActionResult Index() { var banners = AdsService.GetsByWeightedPrice(8, AdvertiseType.Banner).OrderBy(a => Guid.NewGuid()).ToList(); var fastShares = FastShareService.GetAllFromCache(s => s.Sort).ToList(); var postsQuery = PostService.GetQuery(p => (p.Status == Status.Pended || CurrentUser.IsAdmin)); //准备文章的查询 var posts = postsQuery.Where(p => !p.IsFixedTop).OrderBy(OrderBy.ModifyDate.GetDisplay() + " desc").ToCachedPagedList(1, 15); posts.Data.InsertRange(0, postsQuery.Where(p => p.IsFixedTop).OrderByDescending(p => p.ModifyDate).ToList()); var viewModel = GetIndexPageViewModel(); viewModel.Banner = banners; viewModel.Posts = posts; ViewBag.FastShare = fastShares; viewModel.PageParams = new Pagination(1, 15, posts.TotalCount, OrderBy.ModifyDate); return View(viewModel); } /// /// 文章列表页 /// /// /// /// /// [Route("p"), ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "page", "size", "orderBy" }, VaryByHeader = "Cookie")] public ActionResult Post([Optional]OrderBy? orderBy, [Range(1, int.MaxValue, ErrorMessage = "页码必须大于0")]int page = 1, [Range(1, int.MaxValue, ErrorMessage = "页大小必须大于0")]int size = 15) { var viewModel = GetIndexPageViewModel(); var postsQuery = PostService.GetQuery(p => (p.Status == Status.Pended || CurrentUser.IsAdmin)); //准备文章的查询 var posts = postsQuery.Where(p => !p.IsFixedTop).OrderBy((orderBy ?? OrderBy.ModifyDate).GetDisplay() + " desc").ToCachedPagedList(page, size); if (page == 1) { posts.Data.InsertRange(0, postsQuery.Where(p => p.IsFixedTop).OrderByDescending(p => p.ModifyDate).ToList()); } viewModel.Posts = posts; viewModel.PageParams = new Pagination(1, 15, posts.TotalCount, OrderBy.ModifyDate); return View(viewModel); } /// /// 标签文章页 /// /// /// /// /// /// [Route("tag/{id}/{page:int?}/{size:int?}/{orderBy:int?}"), ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "id", "page", "size", "orderBy" }, VaryByHeader = "Cookie")] 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) { var posts = PostService.GetQuery(p => p.Label.Contains(id) && (p.Status == Status.Pended || CurrentUser.IsAdmin)).OrderBy($"{nameof(PostDto.IsFixedTop)} desc,{(orderBy ?? OrderBy.ModifyDate).GetDisplay()} desc").ToCachedPagedList(page, size); var viewModel = GetIndexPageViewModel(); ViewBag.Tag = id; viewModel.Posts = posts; viewModel.PageParams = new Pagination(1, 15, posts.TotalCount, OrderBy.ModifyDate); return View(viewModel); } /// /// 作者文章页 /// /// /// /// /// /// [Route("author/{author}/{page:int?}/{size:int?}/{orderBy:int?}"), ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "author", "page", "size", "orderBy" }, VaryByHeader = "Cookie")] 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) { Expression> 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)); where = where.And(p => p.Status == Status.Pended || CurrentUser.IsAdmin); var posts = PostService.GetQuery(where).OrderBy($"{nameof(PostDto.IsFixedTop)} desc,{(orderBy ?? OrderBy.ModifyDate).GetDisplay()} desc").ToCachedPagedList(page, size); var viewModel = GetIndexPageViewModel(); ViewBag.Author = author; viewModel.Posts = posts; viewModel.PageParams = new Pagination(1, 15, posts.TotalCount, OrderBy.ModifyDate); return View(viewModel); } /// /// 分类文章页 /// /// /// /// /// /// [Route("cat/{id:int}"), ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "id", "page", "size", "orderBy" }, VaryByHeader = "Cookie")] [Route("cat/{id:int}/{page:int?}/{size:int?}/{orderBy:int?}")] public async Task Category(int id, [Optional]OrderBy? orderBy, [Range(1, int.MaxValue, ErrorMessage = "页码必须大于0")]int page = 1, [Range(1, int.MaxValue, ErrorMessage = "页大小必须大于0")]int size = 15) { var cat = await CategoryService.GetByIdAsync(id) ?? throw new NotFoundException("文章分类未找到"); var posts = PostService.GetQuery(p => p.CategoryId == cat.Id && (p.Status == Status.Pended || CurrentUser.IsAdmin)).OrderBy($"{nameof(PostDto.IsFixedTop)} desc,{(orderBy ?? OrderBy.ModifyDate).GetDisplay()} desc").ToCachedPagedList(page, size); var viewModel = GetIndexPageViewModel(); viewModel.Posts = posts; ViewBag.Category = cat; viewModel.PageParams = new Pagination(1, 15, posts.TotalCount, OrderBy.ModifyDate); return View(viewModel); } /// /// 获取页面视图模型 /// /// private HomePageViewModel GetIndexPageViewModel() { var postsQuery = PostService.GetQuery(p => (p.Status == Status.Pended || CurrentUser.IsAdmin)); //准备文章的查询 var notices = NoticeService.GetPagesFromCache(1, 5, n => (n.Status == Status.Display || CurrentUser.IsAdmin), n => n.ModifyDate, false); //加载前5条公告 var cats = CategoryService.GetQueryFromCache(c => c.Status == Status.Available, c => c.Name).ToList(); //加载分类目录 var hotSearches = RedisHelper.Get>("SearchRank:Week").Take(10).ToList(); //热词统计 var hot6Post = postsQuery.OrderBy((new Random().Next() % 3) switch { 1 => nameof(OrderBy.VoteUpCount), 2 => nameof(OrderBy.AverageViewCount), _ => nameof(OrderBy.TotalViewCount) } + " desc").Skip(0).Take(5).Cacheable().ToList(); //热门文章 var newdic = new Dictionary(); //标签云最终结果 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()); //统计标签 if (tagdic.Any()) { var min = tagdic.Values.Min(); foreach (var (key, value) in tagdic) { var fontsize = (int)Math.Floor(value * 1.0 / (min * 1.0) + 12.0); newdic.Add(key, fontsize >= 36 ? 36 : fontsize); } } return new HomePageViewModel() { Categories = cats, HotSearch = hotSearches, Notices = notices.Data, Tags = newdic, Top6Post = hot6Post, PostsQueryable = postsQuery, SidebarAds = AdsService.GetsByWeightedPrice(2, AdvertiseType.SideBar), ListAdvertisement = AdsService.GetByWeightedPrice(AdvertiseType.PostList) }; } } }