Browse Source

优化广告选择性能
优化搜索性能
优化拼音搜索
优化其他性能

懒得勤快 2 years ago
parent
commit
e0cbff54d7
24 changed files with 190 additions and 98 deletions
  1. 1 2
      src/Masuit.MyBlogs.Core/Common/CommonHelper.cs
  2. 1 1
      src/Masuit.MyBlogs.Core/Common/HttpContextExtension.cs
  3. 3 1
      src/Masuit.MyBlogs.Core/Common/PerfCounter.cs
  4. 4 4
      src/Masuit.MyBlogs.Core/Controllers/AdvertisementController.cs
  5. 18 12
      src/Masuit.MyBlogs.Core/Controllers/BaseController.cs
  6. 11 10
      src/Masuit.MyBlogs.Core/Controllers/CommentController.cs
  7. 11 10
      src/Masuit.MyBlogs.Core/Controllers/MsgController.cs
  8. 16 14
      src/Masuit.MyBlogs.Core/Controllers/PostController.cs
  9. 1 1
      src/Masuit.MyBlogs.Core/Controllers/SearchController.cs
  10. 11 12
      src/Masuit.MyBlogs.Core/Controllers/ToolsController.cs
  11. 2 2
      src/Masuit.MyBlogs.Core/Controllers/ValidateController.cs
  12. 11 11
      src/Masuit.MyBlogs.Core/Extensions/Firewall/FirewallAttribute.cs
  13. 5 3
      src/Masuit.MyBlogs.Core/Extensions/Firewall/IRequestLogger.cs
  14. 5 0
      src/Masuit.MyBlogs.Core/Infrastructure/Repository/BaseRepository.cs
  15. 1 0
      src/Masuit.MyBlogs.Core/Infrastructure/Repository/Interface/IBaseRepository.cs
  16. 69 5
      src/Masuit.MyBlogs.Core/Infrastructure/Services/AdvertisementService.cs
  17. 5 0
      src/Masuit.MyBlogs.Core/Infrastructure/Services/BaseService.cs
  18. 1 0
      src/Masuit.MyBlogs.Core/Infrastructure/Services/Interface/IBaseService.cs
  19. 2 2
      src/Masuit.MyBlogs.Core/Masuit.MyBlogs.Core.csproj
  20. 5 1
      src/Masuit.MyBlogs.Core/Properties/PublishProfiles/FolderProfile.pubxml
  21. 1 0
      src/Masuit.MyBlogs.Core/Startup.cs
  22. 2 3
      src/Masuit.MyBlogs.Core/Views/Links/Index.cshtml
  23. 2 2
      src/Masuit.MyBlogs.Core/Views/Links/Index_Admin.cshtml
  24. 2 2
      src/Masuit.MyBlogs.Core/wwwroot/ng-views/views/post/postlist.html

+ 1 - 2
src/Masuit.MyBlogs.Core/Common/CommonHelper.cs

@@ -2,12 +2,12 @@
 using AngleSharp.Css.Dom;
 using AngleSharp.Css.Dom;
 using AngleSharp.Dom;
 using AngleSharp.Dom;
 using AutoMapper;
 using AutoMapper;
+using Dispose.Scope;
 using FreeRedis;
 using FreeRedis;
 using Hangfire;
 using Hangfire;
 using Masuit.MyBlogs.Core.Common.Mails;
 using Masuit.MyBlogs.Core.Common.Mails;
 using Masuit.Tools.Media;
 using Masuit.Tools.Media;
 using Masuit.Tools.Models;
 using Masuit.Tools.Models;
-using Masuit.Tools.Systems;
 using MaxMind.GeoIP2;
 using MaxMind.GeoIP2;
 using MaxMind.GeoIP2.Responses;
 using MaxMind.GeoIP2.Responses;
 using Polly;
 using Polly;
@@ -15,7 +15,6 @@ using SixLabors.ImageSharp;
 using System.Net;
 using System.Net;
 using System.Net.Sockets;
 using System.Net.Sockets;
 using System.Text;
 using System.Text;
-using Dispose.Scope;
 using TimeZoneConverter;
 using TimeZoneConverter;
 using ArgumentException = System.ArgumentException;
 using ArgumentException = System.ArgumentException;
 using Configuration = AngleSharp.Configuration;
 using Configuration = AngleSharp.Configuration;

+ 1 - 1
src/Masuit.MyBlogs.Core/Common/HttpContextExtension.cs

@@ -13,7 +13,7 @@ public static class HttpContextExtension
 	/// <returns></returns>
 	/// <returns></returns>
 	public static IPLocation Location(this HttpRequest request)
 	public static IPLocation Location(this HttpRequest request)
 	{
 	{
-		return (IPLocation)request.HttpContext.Items.GetOrAdd("ip.location", () => request.HttpContext.Connection.RemoteIpAddress.GetIPLocation());
+		return (IPLocation)request.HttpContext.Items.GetOrAdd("ip.location", request.HttpContext.Connection.RemoteIpAddress.GetIPLocation);
 	}
 	}
 
 
 	public static int[] GetHideCategories(this HttpRequest request)
 	public static int[] GetHideCategories(this HttpRequest request)

+ 3 - 1
src/Masuit.MyBlogs.Core/Common/PerfCounter.cs

@@ -136,9 +136,11 @@ public sealed class PerfCounterBackService : ScheduledService
 
 
 	protected override Task ExecuteAsync()
 	protected override Task ExecuteAsync()
 	{
 	{
+#if RELEASE
 		using var scope = _serviceScopeFactory.CreateAsyncScope();
 		using var scope = _serviceScopeFactory.CreateAsyncScope();
 		var counter = scope.ServiceProvider.GetRequiredService<IPerfCounter>();
 		var counter = scope.ServiceProvider.GetRequiredService<IPerfCounter>();
-		counter.Process();
+		counter.Process(); 
+#endif
 		return Task.CompletedTask;
 		return Task.CompletedTask;
 	}
 	}
 }
 }

+ 4 - 4
src/Masuit.MyBlogs.Core/Controllers/AdvertisementController.cs

@@ -35,8 +35,8 @@ public sealed class AdvertisementController : BaseController
 			HttpContext.Session.Set("ads" + id, id.ToString());
 			HttpContext.Session.Set("ads" + id, id.ToString());
 			ClickRecordService.AddEntity(new AdvertisementClickRecord()
 			ClickRecordService.AddEntity(new AdvertisementClickRecord()
 			{
 			{
-				IP = ClientIP,
-				Location = ClientIP.GetIPLocation(),
+				IP = ClientIP.ToString(),
+				Location = Request.Location(),
 				Referer = Request.Headers[HeaderNames.Referer].ToString(),
 				Referer = Request.Headers[HeaderNames.Referer].ToString(),
 				Time = DateTime.Now,
 				Time = DateTime.Now,
 				AdvertisementId = id
 				AdvertisementId = id
@@ -136,8 +136,8 @@ public sealed class AdvertisementController : BaseController
 			HttpContext.Session.Set("ads" + ad.Id, ad.Id.ToString());
 			HttpContext.Session.Set("ads" + ad.Id, ad.Id.ToString());
 			ClickRecordService.AddEntity(new AdvertisementClickRecord()
 			ClickRecordService.AddEntity(new AdvertisementClickRecord()
 			{
 			{
-				IP = ClientIP,
-				Location = ClientIP.GetIPLocation(),
+				IP = ClientIP.ToString(),
+				Location = Request.Location(),
 				Referer = Request.Headers[HeaderNames.Referer].ToString(),
 				Referer = Request.Headers[HeaderNames.Referer].ToString(),
 				Time = DateTime.Now
 				Time = DateTime.Now
 			});
 			});

+ 18 - 12
src/Masuit.MyBlogs.Core/Controllers/BaseController.cs

@@ -37,7 +37,7 @@ public class BaseController : Controller
 	/// <summary>
 	/// <summary>
 	/// 客户端的真实IP
 	/// 客户端的真实IP
 	/// </summary>
 	/// </summary>
-	public string ClientIP => HttpContext.Connection.RemoteIpAddress.ToString();
+	public IPAddress ClientIP => HttpContext.Connection.RemoteIpAddress;
 
 
 	/// <summary>
 	/// <summary>
 	/// 普通访客是否token合法
 	/// 普通访客是否token合法
@@ -78,7 +78,7 @@ public class BaseController : Controller
 
 
 		var location = Request.Location();
 		var location = Request.Location();
 		var template = Template.Create(text)
 		var template = Template.Create(text)
-			.Set("clientip", ClientIP)
+			.Set("clientip", ClientIP.ToString())
 			.Set("location", location.Address)
 			.Set("location", location.Address)
 			.Set("network", location.Network)
 			.Set("network", location.Network)
 			.Set("domain", Request.Host.Host)
 			.Set("domain", Request.Host.Host)
@@ -114,8 +114,11 @@ public class BaseController : Controller
 		ViewBag.Desc = CommonHelper.SystemSettings["Description"];
 		ViewBag.Desc = CommonHelper.SystemSettings["Description"];
 		var user = filterContext.HttpContext.Session.Get<UserInfoDto>(SessionKey.UserInfo);
 		var user = filterContext.HttpContext.Session.Get<UserInfoDto>(SessionKey.UserInfo);
 #if DEBUG
 #if DEBUG
-		user = Mapper.Map<UserInfoDto>(UserInfoService.GetByUsername("masuit"));
-		filterContext.HttpContext.Session.Set(SessionKey.UserInfo, user);
+		if (HttpContext.Connection.RemoteIpAddress.IsPrivateIP())
+		{
+			user = Mapper.Map<UserInfoDto>(UserInfoService.GetByUsername("masuit"));
+			filterContext.HttpContext.Session.Set(SessionKey.UserInfo, user);
+		}
 #endif
 #endif
 		if (CommonHelper.SystemSettings.GetOrAdd("CloseSite", "false") == "true" && user?.IsAdmin != true)
 		if (CommonHelper.SystemSettings.GetOrAdd("CloseSite", "false") == "true" && user?.IsAdmin != true)
 		{
 		{
@@ -225,19 +228,20 @@ public class BaseController : Controller
 			return _ => true;
 			return _ => true;
 		}
 		}
 
 
+		var ip = ClientIP.ToString();
 		Expression<Func<Post, bool>> where = p => p.Status == Status.Published && p.LimitMode != RegionLimitMode.OnlyForSearchEngine;
 		Expression<Func<Post, bool>> where = p => p.Status == Status.Published && p.LimitMode != RegionLimitMode.OnlyForSearchEngine;
 		where = where.AndIf(HideCategories.Length > 0, p => !HideCategories.Contains(p.CategoryId)).AndIf(SafeMode, p => !p.IsNsfw);
 		where = where.AndIf(HideCategories.Length > 0, p => !HideCategories.Contains(p.CategoryId)).AndIf(SafeMode, p => !p.IsNsfw);
-		if (VisitorTokenValid || CommonHelper.IPWhiteList.Contains(ClientIP))
+		if (VisitorTokenValid || CommonHelper.IPWhiteList.Contains(ip))
 		{
 		{
 			return where;
 			return where;
 		}
 		}
 
 
 		var ipLocation = Request.Location();
 		var ipLocation = Request.Location();
 		var location = ipLocation + ipLocation.Coodinate + "|" + Request.Headers[HeaderNames.Referer] + "|" + Request.Headers[HeaderNames.UserAgent];
 		var location = ipLocation + ipLocation.Coodinate + "|" + Request.Headers[HeaderNames.Referer] + "|" + Request.Headers[HeaderNames.UserAgent];
-		if (Request.Cookies.TryGetValue(SessionKey.RawIP, out var rawip) && ClientIP != rawip)
+		if (Request.Cookies.TryGetValue(SessionKey.RawIP, out var rawip) && ip != rawip)
 		{
 		{
 			var s = rawip.Base64Decrypt();
 			var s = rawip.Base64Decrypt();
-			if (ClientIP != s)
+			if (ip != s)
 			{
 			{
 				location += "|" + s.GetIPLocation();
 				location += "|" + s.GetIPLocation();
 			}
 			}
@@ -251,17 +255,18 @@ public class BaseController : Controller
 
 
 	protected void CheckPermission(Post post)
 	protected void CheckPermission(Post post)
 	{
 	{
-		if (CurrentUser.IsAdmin || VisitorTokenValid || Request.IsRobot() || CommonHelper.IPWhiteList.Contains(ClientIP))
+		var ip = ClientIP.ToString();
+		if (CurrentUser.IsAdmin || VisitorTokenValid || Request.IsRobot() || CommonHelper.IPWhiteList.Contains(ip))
 		{
 		{
 			return;
 			return;
 		}
 		}
 
 
 		var ipLocation = Request.Location();
 		var ipLocation = Request.Location();
 		var location = ipLocation + ipLocation.Coodinate + "|" + Request.Headers[HeaderNames.Referer] + "|" + Request.Headers[HeaderNames.UserAgent];
 		var location = ipLocation + ipLocation.Coodinate + "|" + Request.Headers[HeaderNames.Referer] + "|" + Request.Headers[HeaderNames.UserAgent];
-		if (Request.Cookies.TryGetValue(SessionKey.RawIP, out var rawip) && ClientIP != rawip)
+		if (Request.Cookies.TryGetValue(SessionKey.RawIP, out var rawip) && ip != rawip)
 		{
 		{
 			var s = rawip.Base64Decrypt();
 			var s = rawip.Base64Decrypt();
-			if (ClientIP != s)
+			if (ip != s)
 			{
 			{
 				location += "|" + s.GetIPLocation();
 				location += "|" + s.GetIPLocation();
 			}
 			}
@@ -314,7 +319,8 @@ public class BaseController : Controller
 	private void Disallow(Post post)
 	private void Disallow(Post post)
 	{
 	{
 		var remark = "无权限查看该文章";
 		var remark = "无权限查看该文章";
-		if (Request.Cookies.TryGetValue(SessionKey.RawIP, out var rawip) && ClientIP != rawip.Base64Decrypt())
+		var ip = ClientIP.ToString();
+		if (Request.Cookies.TryGetValue(SessionKey.RawIP, out var rawip) && ip != rawip.Base64Decrypt())
 		{
 		{
 			remark += ",发生了IP切换,原始IP:" + rawip.Base64Decrypt();
 			remark += ",发生了IP切换,原始IP:" + rawip.Base64Decrypt();
 		}
 		}
@@ -322,7 +328,7 @@ public class BaseController : Controller
 		RedisHelper.IncrBy("interceptCount", 1);
 		RedisHelper.IncrBy("interceptCount", 1);
 		RedisHelper.LPush("intercept", new IpIntercepter()
 		RedisHelper.LPush("intercept", new IpIntercepter()
 		{
 		{
-			IP = ClientIP,
+			IP = ip,
 			RequestUrl = $"//{Request.Host}/{post.Id}",
 			RequestUrl = $"//{Request.Host}/{post.Id}",
 			Referer = Request.Headers[HeaderNames.Referer],
 			Referer = Request.Headers[HeaderNames.Referer],
 			Time = DateTime.Now,
 			Time = DateTime.Now,

+ 11 - 10
src/Masuit.MyBlogs.Core/Controllers/CommentController.cs

@@ -1,4 +1,5 @@
 using CacheManager.Core;
 using CacheManager.Core;
+using Dispose.Scope;
 using Hangfire;
 using Hangfire;
 using Masuit.MyBlogs.Core.Common;
 using Masuit.MyBlogs.Core.Common;
 using Masuit.MyBlogs.Core.Common.Mails;
 using Masuit.MyBlogs.Core.Common.Mails;
@@ -12,7 +13,6 @@ using Microsoft.Net.Http.Headers;
 using System.ComponentModel.DataAnnotations;
 using System.ComponentModel.DataAnnotations;
 using System.Text;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
-using Dispose.Scope;
 using SameSiteMode = Microsoft.AspNetCore.Http.SameSiteMode;
 using SameSiteMode = Microsoft.AspNetCore.Http.SameSiteMode;
 
 
 namespace Masuit.MyBlogs.Core.Controllers;
 namespace Masuit.MyBlogs.Core.Controllers;
@@ -64,9 +64,10 @@ public sealed class CommentController : BaseController
 		}
 		}
 
 
 		cmd.Content = cmd.Content.Trim().Replace("<p><br></p>", string.Empty);
 		cmd.Content = cmd.Content.Trim().Replace("<p><br></p>", string.Empty);
-		if (CommentFeq.GetOrAdd("Comments:" + ClientIP, 1) > 2)
+		var ip = ClientIP.ToString();
+		if (CommentFeq.GetOrAdd("Comments:" + ip, 1) > 2)
 		{
 		{
-			CommentFeq.Expire("Comments:" + ClientIP, TimeSpan.FromMinutes(1));
+			CommentFeq.Expire("Comments:" + ip, TimeSpan.FromMinutes(1));
 			return ResultData(null, false, "您的发言频率过快,请稍后再发表吧!");
 			return ResultData(null, false, "您的发言频率过快,请稍后再发表吧!");
 		}
 		}
 
 
@@ -101,7 +102,7 @@ public sealed class CommentController : BaseController
 		}
 		}
 		comment.Content = await cmd.Content.HtmlSantinizerStandard().ClearImgAttributes();
 		comment.Content = await cmd.Content.HtmlSantinizerStandard().ClearImgAttributes();
 		comment.Browser = cmd.Browser ?? Request.Headers[HeaderNames.UserAgent];
 		comment.Browser = cmd.Browser ?? Request.Headers[HeaderNames.UserAgent];
-		comment.IP = ClientIP;
+		comment.IP = ip;
 		comment.Location = Request.Location();
 		comment.Location = Request.Location();
 		comment = CommentService.AddEntitySaved(comment);
 		comment = CommentService.AddEntitySaved(comment);
 		if (comment == null)
 		if (comment == null)
@@ -115,8 +116,8 @@ public sealed class CommentController : BaseController
 			SameSite = SameSiteMode.Lax
 			SameSite = SameSiteMode.Lax
 		});
 		});
 		WriteEmailKeyCookie(cmd.Email);
 		WriteEmailKeyCookie(cmd.Email);
-		CommentFeq.AddOrUpdate("Comments:" + ClientIP, 1, i => i + 1, 5);
-		CommentFeq.Expire("Comments:" + ClientIP, TimeSpan.FromMinutes(1));
+		CommentFeq.AddOrUpdate("Comments:" + comment.IP, 1, i => i + 1, 5);
+		CommentFeq.Expire("Comments:" + comment.IP, TimeSpan.FromMinutes(1));
 		var emails = new HashSet<string>();
 		var emails = new HashSet<string>();
 		var email = CommonHelper.SystemSettings["ReceiveEmail"]; //站长邮箱
 		var email = CommonHelper.SystemSettings["ReceiveEmail"]; //站长邮箱
 		emails.Add(email);
 		emails.Add(email);
@@ -151,7 +152,7 @@ public sealed class CommentController : BaseController
 				//新评论,只通知博主和楼主
 				//新评论,只通知博主和楼主
 				foreach (var s in emails)
 				foreach (var s in emails)
 				{
 				{
-					BackgroundJob.Enqueue(() => CommonHelper.SendMail(Request.Host + "|博客文章新评论:", content.Set("link", Url.Action("Details", "Post", new { id = comment.PostId, cid = comment.Id }, Request.Scheme) + "#comment").Render(false), s, ClientIP));
+					BackgroundJob.Enqueue(() => CommonHelper.SendMail(Request.Host + "|博客文章新评论:", content.Set("link", Url.Action("Details", "Post", new { id = comment.PostId, cid = comment.Id }, Request.Scheme) + "#comment").Render(false), s, comment.IP));
 				}
 				}
 			}
 			}
 			else
 			else
@@ -163,7 +164,7 @@ public sealed class CommentController : BaseController
 				string link = Url.Action("Details", "Post", new { id = comment.PostId, cid = comment.Id }, Request.Scheme) + "#comment";
 				string link = Url.Action("Details", "Post", new { id = comment.PostId, cid = comment.Id }, Request.Scheme) + "#comment";
 				foreach (var s in emails)
 				foreach (var s in emails)
 				{
 				{
-					BackgroundJob.Enqueue(() => CommonHelper.SendMail($"{Request.Host}{CommonHelper.SystemSettings["Title"]}文章评论回复:", content.Set("link", link).Render(false), s, ClientIP));
+					BackgroundJob.Enqueue(() => CommonHelper.SendMail($"{Request.Host}{CommonHelper.SystemSettings["Title"]}文章评论回复:", content.Set("link", link).Render(false), s, comment.IP));
 				}
 				}
 			}
 			}
 			return ResultData(null, true, "评论发表成功,服务器正在后台处理中,这会有一定的延迟,稍后将显示到评论列表中");
 			return ResultData(null, true, "评论发表成功,服务器正在后台处理中,这会有一定的延迟,稍后将显示到评论列表中");
@@ -171,7 +172,7 @@ public sealed class CommentController : BaseController
 
 
 		foreach (var s in emails)
 		foreach (var s in emails)
 		{
 		{
-			BackgroundJob.Enqueue(() => CommonHelper.SendMail(Request.Host + "|博客文章新评论(待审核):", content.Set("link", Url.Action("Details", "Post", new { id = comment.PostId, cid = comment.Id }, Request.Scheme) + "#comment").Render(false) + "<p style='color:red;'>(待审核)</p>", s, ClientIP));
+			BackgroundJob.Enqueue(() => CommonHelper.SendMail(Request.Host + "|博客文章新评论(待审核):", content.Set("link", Url.Action("Details", "Post", new { id = comment.PostId, cid = comment.Id }, Request.Scheme) + "#comment").Render(false) + "<p style='color:red;'>(待审核)</p>", s, comment.IP));
 		}
 		}
 
 
 		return ResultData(null, true, "评论成功,待站长审核通过以后将显示");
 		return ResultData(null, true, "评论成功,待站长审核通过以后将显示");
@@ -298,7 +299,7 @@ public sealed class CommentController : BaseController
 			}, Request.Scheme) + "#comment";
 			}, Request.Scheme) + "#comment";
 			foreach (var email in emails)
 			foreach (var email in emails)
 			{
 			{
-				BackgroundJob.Enqueue(() => CommonHelper.SendMail($"{Request.Host}{CommonHelper.SystemSettings["Title"]}文章评论回复:", content.Set("link", link).Render(false), email, ClientIP));
+				BackgroundJob.Enqueue(() => CommonHelper.SendMail($"{Request.Host}{CommonHelper.SystemSettings["Title"]}文章评论回复:", content.Set("link", link).Render(false), email, ClientIP.ToString()));
 			}
 			}
 
 
 			return ResultData(null, true, "审核通过!");
 			return ResultData(null, true, "审核通过!");

+ 11 - 10
src/Masuit.MyBlogs.Core/Controllers/MsgController.cs

@@ -1,4 +1,5 @@
 using CacheManager.Core;
 using CacheManager.Core;
+using Dispose.Scope;
 using Hangfire;
 using Hangfire;
 using Masuit.MyBlogs.Core.Common;
 using Masuit.MyBlogs.Core.Common;
 using Masuit.MyBlogs.Core.Common.Mails;
 using Masuit.MyBlogs.Core.Common.Mails;
@@ -12,7 +13,6 @@ using Microsoft.Net.Http.Headers;
 using System.ComponentModel.DataAnnotations;
 using System.ComponentModel.DataAnnotations;
 using System.Text;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
-using Dispose.Scope;
 using SameSiteMode = Microsoft.AspNetCore.Http.SameSiteMode;
 using SameSiteMode = Microsoft.AspNetCore.Http.SameSiteMode;
 
 
 namespace Masuit.MyBlogs.Core.Controllers;
 namespace Masuit.MyBlogs.Core.Controllers;
@@ -143,9 +143,10 @@ public sealed class MsgController : BaseController
 		}
 		}
 
 
 		cmd.Content = cmd.Content.Trim().Replace("<p><br></p>", string.Empty);
 		cmd.Content = cmd.Content.Trim().Replace("<p><br></p>", string.Empty);
-		if (MsgFeq.GetOrAdd("Comments:" + ClientIP, 1) > 2)
+		var ip = ClientIP.ToString();
+		if (MsgFeq.GetOrAdd("Comments:" + ip, 1) > 2)
 		{
 		{
-			MsgFeq.Expire("Comments:" + ClientIP, TimeSpan.FromMinutes(1));
+			MsgFeq.Expire("Comments:" + ip, TimeSpan.FromMinutes(1));
 			return ResultData(null, false, "您的发言频率过快,请稍后再发表吧!");
 			return ResultData(null, false, "您的发言频率过快,请稍后再发表吧!");
 		}
 		}
 
 
@@ -181,7 +182,7 @@ public sealed class MsgController : BaseController
 
 
 		msg.Content = await cmd.Content.HtmlSantinizerStandard().ClearImgAttributes();
 		msg.Content = await cmd.Content.HtmlSantinizerStandard().ClearImgAttributes();
 		msg.Browser = cmd.Browser ?? Request.Headers[HeaderNames.UserAgent];
 		msg.Browser = cmd.Browser ?? Request.Headers[HeaderNames.UserAgent];
-		msg.IP = ClientIP;
+		msg.IP = ip;
 		msg.Location = Request.Location();
 		msg.Location = Request.Location();
 		msg = LeaveMessageService.AddEntitySaved(msg);
 		msg = LeaveMessageService.AddEntitySaved(msg);
 		if (msg == null)
 		if (msg == null)
@@ -195,8 +196,8 @@ public sealed class MsgController : BaseController
 			SameSite = SameSiteMode.Lax
 			SameSite = SameSiteMode.Lax
 		});
 		});
 		WriteEmailKeyCookie(cmd.Email);
 		WriteEmailKeyCookie(cmd.Email);
-		MsgFeq.AddOrUpdate("Comments:" + ClientIP, 1, i => i + 1, 5);
-		MsgFeq.Expire("Comments:" + ClientIP, TimeSpan.FromMinutes(1));
+		MsgFeq.AddOrUpdate("Comments:" + ip, 1, i => i + 1, 5);
+		MsgFeq.Expire("Comments:" + ip, TimeSpan.FromMinutes(1));
 		var email = CommonHelper.SystemSettings["ReceiveEmail"];
 		var email = CommonHelper.SystemSettings["ReceiveEmail"];
 		var content = new Template(await new FileInfo(HostEnvironment.WebRootPath + "/template/notify.html").ShareReadWrite().ReadAllTextAsync(Encoding.UTF8)).Set("title", "网站留言板").Set("time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")).Set("nickname", msg.NickName).Set("content", msg.Content);
 		var content = new Template(await new FileInfo(HostEnvironment.WebRootPath + "/template/notify.html").ShareReadWrite().ReadAllTextAsync(Encoding.UTF8)).Set("title", "网站留言板").Set("time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")).Set("nickname", msg.NickName).Set("content", msg.Content);
 		if (msg.Status == Status.Published)
 		if (msg.Status == Status.Published)
@@ -213,7 +214,7 @@ public sealed class MsgController : BaseController
 			if (msg.ParentId == null)
 			if (msg.ParentId == null)
 			{
 			{
 				//新评论,只通知博主
 				//新评论,只通知博主
-				BackgroundJob.Enqueue(() => CommonHelper.SendMail(Request.Host + "|博客新留言:", content.Set("link", Url.Action("Index", "Msg", new { cid = msg.Id }, Request.Scheme)).Render(false), email, ClientIP));
+				BackgroundJob.Enqueue(() => CommonHelper.SendMail(Request.Host + "|博客新留言:", content.Set("link", Url.Action("Index", "Msg", new { cid = msg.Id }, Request.Scheme)).Render(false), email, ip));
 			}
 			}
 			else
 			else
 			{
 			{
@@ -222,7 +223,7 @@ public sealed class MsgController : BaseController
 				string link = Url.Action("Index", "Msg", new { cid = msg.Id }, Request.Scheme);
 				string link = Url.Action("Index", "Msg", new { cid = msg.Id }, Request.Scheme);
 				foreach (var s in emails)
 				foreach (var s in emails)
 				{
 				{
-					BackgroundJob.Enqueue(() => CommonHelper.SendMail($"{Request.Host}{CommonHelper.SystemSettings["Title"]} 留言回复:", content.Set("link", link).Render(false), s, ClientIP));
+					BackgroundJob.Enqueue(() => CommonHelper.SendMail($"{Request.Host}{CommonHelper.SystemSettings["Title"]} 留言回复:", content.Set("link", link).Render(false), s, ip));
 				}
 				}
 			}
 			}
 			return ResultData(null, true, "留言发表成功,服务器正在后台处理中,这会有一定的延迟,稍后将会显示到列表中!");
 			return ResultData(null, true, "留言发表成功,服务器正在后台处理中,这会有一定的延迟,稍后将会显示到列表中!");
@@ -231,7 +232,7 @@ public sealed class MsgController : BaseController
 		BackgroundJob.Enqueue(() => CommonHelper.SendMail(Request.Host + "|博客新留言(待审核):", content.Set("link", Url.Action("Index", "Msg", new
 		BackgroundJob.Enqueue(() => CommonHelper.SendMail(Request.Host + "|博客新留言(待审核):", content.Set("link", Url.Action("Index", "Msg", new
 		{
 		{
 			cid = msg.Id
 			cid = msg.Id
-		}, Request.Scheme)).Render(false) + "<p style='color:red;'>(待审核)</p>", email, ClientIP));
+		}, Request.Scheme)).Render(false) + "<p style='color:red;'>(待审核)</p>", email, ip));
 		return ResultData(null, true, "留言发表成功,待站长审核通过以后将显示到列表中!");
 		return ResultData(null, true, "留言发表成功,待站长审核通过以后将显示到列表中!");
 	}
 	}
 
 
@@ -253,7 +254,7 @@ public sealed class MsgController : BaseController
 			var link = Url.Action("Index", "Msg", new { cid = id }, Request.Scheme);
 			var link = Url.Action("Index", "Msg", new { cid = id }, Request.Scheme);
 			foreach (var s in emails)
 			foreach (var s in emails)
 			{
 			{
-				BackgroundJob.Enqueue(() => CommonHelper.SendMail($"{Request.Host}{CommonHelper.SystemSettings["Title"]} 留言回复:", content.Set("link", link).Render(false), s, ClientIP));
+				BackgroundJob.Enqueue(() => CommonHelper.SendMail($"{Request.Host}{CommonHelper.SystemSettings["Title"]} 留言回复:", content.Set("link", link).Render(false), s, ClientIP.ToString()));
 			}
 			}
 		}
 		}
 
 

+ 16 - 14
src/Masuit.MyBlogs.Core/Controllers/PostController.cs

@@ -60,7 +60,7 @@ public sealed class PostController : BaseController
 	/// </summary>
 	/// </summary>
 	/// <returns></returns>
 	/// <returns></returns>
 	[Route("{id:int}"), Route("{id:int}/comments/{cid:int}"), ResponseCache(Duration = 600, VaryByHeader = "Cookie")]
 	[Route("{id:int}"), Route("{id:int}/comments/{cid:int}"), ResponseCache(Duration = 600, VaryByHeader = "Cookie")]
-	public async Task<ActionResult> Details(int id, string kw, int cid, string t)
+	public async Task<ActionResult> Details([FromServices] ISearchDetailsService searchService, int id, string kw, int cid, string t)
 	{
 	{
 		var notRobot = !Request.IsRobot();
 		var notRobot = !Request.IsRobot();
 		if (string.IsNullOrEmpty(t) && notRobot)
 		if (string.IsNullOrEmpty(t) && notRobot)
@@ -70,11 +70,12 @@ public sealed class PostController : BaseController
 
 
 		var post = await PostService.GetQuery(p => p.Id == id && (p.Status == Status.Published || CurrentUser.IsAdmin)).Include(p => p.Seminar).AsNoTracking().FirstOrDefaultAsync() ?? throw new NotFoundException("文章未找到");
 		var post = await PostService.GetQuery(p => p.Id == id && (p.Status == Status.Published || CurrentUser.IsAdmin)).Include(p => p.Seminar).AsNoTracking().FirstOrDefaultAsync() ?? throw new NotFoundException("文章未找到");
 		CheckPermission(post);
 		CheckPermission(post);
+		var ip = ClientIP.ToString();
 		if (!string.IsNullOrEmpty(post.Redirect))
 		if (!string.IsNullOrEmpty(post.Redirect))
 		{
 		{
 			if (notRobot && string.IsNullOrEmpty(HttpContext.Session.Get<string>("post" + id)))
 			if (notRobot && string.IsNullOrEmpty(HttpContext.Session.Get<string>("post" + id)))
 			{
 			{
-				BackgroundJob.Enqueue<IHangfireBackJob>(job => job.RecordPostVisit(id, ClientIP, Request.Headers[HeaderNames.Referer].ToString(), Request.GetDisplayUrl()));
+				BackgroundJob.Enqueue<IHangfireBackJob>(job => job.RecordPostVisit(id, ip, Request.Headers[HeaderNames.Referer].ToString(), Request.GetDisplayUrl()));
 				HttpContext.Session.Set("post" + id, id.ToString());
 				HttpContext.Session.Set("post" + id, id.ToString());
 			}
 			}
 
 
@@ -106,10 +107,11 @@ public sealed class PostController : BaseController
 			await PostService.Highlight(post, kw);
 			await PostService.Highlight(post, kw);
 		}
 		}
 
 
-		var regex = SearchEngine.LuceneIndexSearcher.CutKeywords(string.IsNullOrWhiteSpace(post.Keyword + post.Label) ? post.Title : post.Keyword + post.Label).Select(Regex.Escape).Join("|");
+		var keys = searchService.GetQuery(e => e.IP == ip).OrderByDescending(e => e.SearchTime).Select(e => e.Keywords).Distinct().Take(5).FromCache();
+		var regex = SearchEngine.LuceneIndexSearcher.CutKeywords(string.IsNullOrWhiteSpace(post.Keyword + post.Label) ? post.Title : post.Keyword + post.Label).Union(keys).Select(Regex.Escape).Join("|");
 		ViewBag.Ads = AdsService.GetByWeightedPrice(AdvertiseType.InPage, Request.Location(), post.CategoryId, regex);
 		ViewBag.Ads = AdsService.GetByWeightedPrice(AdvertiseType.InPage, Request.Location(), post.CategoryId, regex);
-		var related = PostService.GetQuery(PostBaseWhere().And(p => p.Id != id && Regex.IsMatch(p.Title + (p.Keyword ?? "") + (p.Label ?? ""), regex, RegexOptions.IgnoreCase)), p => p.AverageViewCount, false).Take(10).Select(p => new { p.Id, p.Title }).FromCache().ToDictionary(p => p.Id, p => p.Title);
-		ViewBag.Related = related;
+		ViewBag.Related = PostService.GetQuery(PostBaseWhere().And(p => p.Id != post.Id && Regex.IsMatch(p.Title + (p.Keyword ?? "") + (p.Label ?? ""), regex, RegexOptions.IgnoreCase)), p => p.AverageViewCount, false).Take(10).Select(p => new { p.Id, p.Title }).FromCache().ToDictionary(p => p.Id, p => p.Title);
+
 		post.ModifyDate = post.ModifyDate.ToTimeZone(HttpContext.Session.Get<string>(SessionKey.TimeZone));
 		post.ModifyDate = post.ModifyDate.ToTimeZone(HttpContext.Session.Get<string>(SessionKey.TimeZone));
 		post.PostDate = post.PostDate.ToTimeZone(HttpContext.Session.Get<string>(SessionKey.TimeZone));
 		post.PostDate = post.PostDate.ToTimeZone(HttpContext.Session.Get<string>(SessionKey.TimeZone));
 		post.Content = await ReplaceVariables(post.Content).Next(s => notRobot && post.DisableCopy ? s.InjectFingerprint() : Task.FromResult(s));
 		post.Content = await ReplaceVariables(post.Content).Next(s => notRobot && post.DisableCopy ? s.InjectFingerprint() : Task.FromResult(s));
@@ -122,13 +124,13 @@ public sealed class PostController : BaseController
 
 
 		if (notRobot && string.IsNullOrEmpty(HttpContext.Session.Get<string>("post" + id)))
 		if (notRobot && string.IsNullOrEmpty(HttpContext.Session.Get<string>("post" + id)))
 		{
 		{
-			BackgroundJob.Enqueue<IHangfireBackJob>(job => job.RecordPostVisit(id, ClientIP, Request.Headers[HeaderNames.Referer].ToString(), Request.GetDisplayUrl()));
+			BackgroundJob.Enqueue<IHangfireBackJob>(job => job.RecordPostVisit(id, ip, Request.Headers[HeaderNames.Referer].ToString(), Request.GetDisplayUrl()));
 			HttpContext.Session.Set("post" + id, id.ToString());
 			HttpContext.Session.Set("post" + id, id.ToString());
 		}
 		}
 
 
 		if (post.LimitMode == RegionLimitMode.OnlyForSearchEngine)
 		if (post.LimitMode == RegionLimitMode.OnlyForSearchEngine)
 		{
 		{
-			BackgroundJob.Enqueue<IHangfireBackJob>(job => job.RecordPostVisit(id, ClientIP, Request.Headers[HeaderNames.Referer].ToString(), Request.GetDisplayUrl()));
+			BackgroundJob.Enqueue<IHangfireBackJob>(job => job.RecordPostVisit(id, ip, Request.Headers[HeaderNames.Referer].ToString(), Request.GetDisplayUrl()));
 		}
 		}
 
 
 		return View(post);
 		return View(post);
@@ -297,7 +299,7 @@ public sealed class PostController : BaseController
 		post.Status = Status.Pending;
 		post.Status = Status.Pending;
 		post.Content = await ImagebedClient.ReplaceImgSrc(await post.Content.HtmlSantinizerStandard().ClearImgAttributes(), cancellationToken);
 		post.Content = await ImagebedClient.ReplaceImgSrc(await post.Content.HtmlSantinizerStandard().ClearImgAttributes(), cancellationToken);
 		Post p = post.Mapper<Post>();
 		Post p = post.Mapper<Post>();
-		p.IP = ClientIP;
+		p.IP = ClientIP.ToString();
 		p.Modifier = p.Author;
 		p.Modifier = p.Author;
 		p.ModifierEmail = p.Email;
 		p.ModifierEmail = p.Email;
 		p.DisableCopy = true;
 		p.DisableCopy = true;
@@ -318,7 +320,7 @@ public sealed class PostController : BaseController
 			.Set("link", Url.Action("Details", "Post", new { id = p.Id }, Request.Scheme))
 			.Set("link", Url.Action("Details", "Post", new { id = p.Id }, Request.Scheme))
 			.Set("time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
 			.Set("time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
 			.Set("title", p.Title).Render();
 			.Set("title", p.Title).Render();
-		BackgroundJob.Enqueue(() => CommonHelper.SendMail(CommonHelper.SystemSettings["Title"] + "有访客投稿:", content, CommonHelper.SystemSettings["ReceiveEmail"], ClientIP));
+		BackgroundJob.Enqueue(() => CommonHelper.SendMail(CommonHelper.SystemSettings["Title"] + "有访客投稿:", content, CommonHelper.SystemSettings["ReceiveEmail"], p.IP));
 		return ResultData(p.Mapper<PostDto>(), message: "文章发表成功,待站长审核通过以后将显示到列表中!");
 		return ResultData(p.Mapper<PostDto>(), message: "文章发表成功,待站长审核通过以后将显示到列表中!");
 	}
 	}
 
 
@@ -406,7 +408,7 @@ public sealed class PostController : BaseController
 
 
 		var token = SnowFlake.GetInstance().GetUniqueShortId(6);
 		var token = SnowFlake.GetInstance().GetUniqueShortId(6);
 		RedisHelper.Set("token:" + email, token, 86400);
 		RedisHelper.Set("token:" + email, token, 86400);
-		BackgroundJob.Enqueue(() => CommonHelper.SendMail(Request.Host + "博客访问验证码", $"{Request.Host}本次验证码是:<span style='color:red'>{token}</span>,有效期为24h,请按时使用!", email, ClientIP));
+		BackgroundJob.Enqueue(() => CommonHelper.SendMail(Request.Host + "博客访问验证码", $"{Request.Host}本次验证码是:<span style='color:red'>{token}</span>,有效期为24h,请按时使用!", email, ClientIP.ToString()));
 		RedisHelper.Set("get:" + email, token, 120);
 		RedisHelper.Set("get:" + email, token, 120);
 		return ResultData(null);
 		return ResultData(null);
 	}
 	}
@@ -500,7 +502,7 @@ public sealed class PostController : BaseController
 			merge.SubmitTime = DateTime.Now;
 			merge.SubmitTime = DateTime.Now;
 			post.PostMergeRequests.Add(merge);
 			post.PostMergeRequests.Add(merge);
 		}
 		}
-		merge.IP = ClientIP;
+		merge.IP = ClientIP.ToString();
 		var b = await PostService.SaveChangesAsync() > 0;
 		var b = await PostService.SaveChangesAsync() > 0;
 		if (!b)
 		if (!b)
 		{
 		{
@@ -524,7 +526,7 @@ public sealed class PostController : BaseController
 			.Set("host", "//" + Request.Host)
 			.Set("host", "//" + Request.Host)
 			.Set("id", merge.Id.ToString())
 			.Set("id", merge.Id.ToString())
 			.Render();
 			.Render();
-		BackgroundJob.Enqueue(() => CommonHelper.SendMail("博客文章修改请求:", content, CommonHelper.SystemSettings["ReceiveEmail"], ClientIP));
+		BackgroundJob.Enqueue(() => CommonHelper.SendMail("博客文章修改请求:", content, CommonHelper.SystemSettings["ReceiveEmail"], merge.IP));
 		return ResultData(null, true, "您的修改请求已提交,已进入审核状态,感谢您的参与!");
 		return ResultData(null, true, "您的修改请求已提交,已进入审核状态,感谢您的参与!");
 	}
 	}
 
 
@@ -734,7 +736,7 @@ public sealed class PostController : BaseController
 		}
 		}
 
 
 		Mapper.Map(post, p);
 		Mapper.Map(post, p);
-		p.IP = ClientIP;
+		p.IP = ClientIP.ToString();
 		p.Seminar.Clear();
 		p.Seminar.Clear();
 		if (!string.IsNullOrEmpty(post.Seminars))
 		if (!string.IsNullOrEmpty(post.Seminars))
 		{
 		{
@@ -783,7 +785,7 @@ public sealed class PostController : BaseController
 		Post p = post.Mapper<Post>();
 		Post p = post.Mapper<Post>();
 		p.Modifier = p.Author;
 		p.Modifier = p.Author;
 		p.ModifierEmail = p.Email;
 		p.ModifierEmail = p.Email;
-		p.IP = ClientIP;
+		p.IP = ClientIP.ToString();
 		p.Rss = p.LimitMode is null or RegionLimitMode.All;
 		p.Rss = p.LimitMode is null or RegionLimitMode.All;
 		if (!string.IsNullOrEmpty(post.Seminars))
 		if (!string.IsNullOrEmpty(post.Seminars))
 		{
 		{

+ 1 - 1
src/Masuit.MyBlogs.Core/Controllers/SearchController.cs

@@ -58,7 +58,7 @@ public sealed class SearchController : BaseController
 				{
 				{
 					Keywords = wd,
 					Keywords = wd,
 					SearchTime = DateTime.Now,
 					SearchTime = DateTime.Now,
-					IP = ClientIP,
+					IP = ClientIP.ToString(),
 					Elapsed = posts.Elapsed,
 					Elapsed = posts.Elapsed,
 					ResultCount = posts.Total
 					ResultCount = posts.Total
 				});
 				});

+ 11 - 12
src/Masuit.MyBlogs.Core/Controllers/ToolsController.cs

@@ -36,17 +36,16 @@ public sealed class ToolsController : BaseController
 	[Route("ip"), Route("ip/{ip?}", Order = 1), ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "ip" })]
 	[Route("ip"), Route("ip/{ip?}", Order = 1), ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "ip" })]
 	public async Task<ActionResult> GetIpInfo([IsIPAddress] string ip)
 	public async Task<ActionResult> GetIpInfo([IsIPAddress] string ip)
 	{
 	{
-		if (string.IsNullOrEmpty(ip))
+		if (!IPAddress.TryParse(ip, out var ipAddress))
 		{
 		{
-			ip = ClientIP;
+			ipAddress = ClientIP;
 		}
 		}
 
 
-		if (ip.IsPrivateIP())
+		if (ipAddress.IsPrivateIP())
 		{
 		{
 			return Ok("内网IP");
 			return Ok("内网IP");
 		}
 		}
 
 
-		var ipAddress = IPAddress.Parse(ip);
 		ViewBag.IP = ip;
 		ViewBag.IP = ip;
 		var loc = ipAddress.GetIPLocation();
 		var loc = ipAddress.GetIPLocation();
 		var asn = ipAddress.GetIPAsn();
 		var asn = ipAddress.GetIPAsn();
@@ -89,8 +88,8 @@ public sealed class ToolsController : BaseController
 		{
 		{
 			var ip = ClientIP;
 			var ip = ClientIP;
 #if DEBUG
 #if DEBUG
-                var r = new Random();
-                ip = $"{r.Next(210)}.{r.Next(255)}.{r.Next(255)}.{r.Next(255)}";
+			var r = new Random();
+			ip = IPAddress.Parse($"{r.Next(210)}.{r.Next(255)}.{r.Next(255)}.{r.Next(255)}");
 #endif
 #endif
 			var location = Policy<CityResponse>.Handle<AddressNotFoundException>().Fallback(() => new CityResponse()).Execute(() => CommonHelper.MaxmindReader.City(ip));
 			var location = Policy<CityResponse>.Handle<AddressNotFoundException>().Fallback(() => new CityResponse()).Execute(() => CommonHelper.MaxmindReader.City(ip));
 			var address = new PhysicsAddress()
 			var address = new PhysicsAddress()
@@ -98,7 +97,7 @@ public sealed class ToolsController : BaseController
 				Status = 0,
 				Status = 0,
 				AddressResult = new AddressResult()
 				AddressResult = new AddressResult()
 				{
 				{
-					FormattedAddress = IPAddress.Parse(ip).GetIPLocation().Address,
+					FormattedAddress = ip.GetIPLocation().Address,
 					Location = new Location()
 					Location = new Location()
 					{
 					{
 						Lng = (decimal)location.Location.Longitude.GetValueOrDefault(),
 						Lng = (decimal)location.Location.Longitude.GetValueOrDefault(),
@@ -135,17 +134,17 @@ public sealed class ToolsController : BaseController
 		{
 		{
 			var ip = ClientIP;
 			var ip = ClientIP;
 #if DEBUG
 #if DEBUG
-                Random r = new Random();
-                ip = $"{r.Next(210)}.{r.Next(255)}.{r.Next(255)}.{r.Next(255)}";
+			Random r = new Random();
+			ip = IPAddress.Parse($"{r.Next(210)}.{r.Next(255)}.{r.Next(255)}.{r.Next(255)}");
 #endif
 #endif
 			var location = Policy<CityResponse>.Handle<AddressNotFoundException>().Fallback(() => new CityResponse()).Execute(() => CommonHelper.MaxmindReader.City(ip));
 			var location = Policy<CityResponse>.Handle<AddressNotFoundException>().Fallback(() => new CityResponse()).Execute(() => CommonHelper.MaxmindReader.City(ip));
 			var address = new PhysicsAddress()
 			var address = new PhysicsAddress()
 			{
 			{
 				Status = 0,
 				Status = 0,
-				AddressResult = new AddressResult()
+				AddressResult = new AddressResult
 				{
 				{
-					FormattedAddress = IPAddress.Parse(ip).GetIPLocation().Address,
-					Location = new Location()
+					FormattedAddress = ip.GetIPLocation().Address,
+					Location = new Location
 					{
 					{
 						Lng = (decimal)location.Location.Longitude.GetValueOrDefault(),
 						Lng = (decimal)location.Location.Longitude.GetValueOrDefault(),
 						Lat = (decimal)location.Location.Latitude.GetValueOrDefault()
 						Lat = (decimal)location.Location.Latitude.GetValueOrDefault()

+ 2 - 2
src/Masuit.MyBlogs.Core/Controllers/ValidateController.cs

@@ -29,12 +29,12 @@ public sealed class ValidateController : BaseController
 
 
 		string code = SnowFlake.GetInstance().GetUniqueShortId(6);
 		string code = SnowFlake.GetInstance().GetUniqueShortId(6);
 		RedisHelper.Set("code:" + email, code, 86400);
 		RedisHelper.Set("code:" + email, code, 86400);
-		BackgroundJob.Enqueue(() => CommonHelper.SendMail(Request.Host + "博客验证码", $"{Request.Host}本次验证码是:<span style='color:red'>{code}</span>,有效期为24h,请按时使用!", email, ClientIP));
+		BackgroundJob.Enqueue(() => CommonHelper.SendMail(Request.Host + "博客验证码", $"{Request.Host}本次验证码是:<span style='color:red'>{code}</span>,有效期为24h,请按时使用!", email, ClientIP.ToString()));
 		RedisHelper.Set("get:" + email, code, 120);
 		RedisHelper.Set("get:" + email, code, 120);
 #if !DEBUG
 #if !DEBUG
 		return ResultData(null, true, "验证码发送成功!");
 		return ResultData(null, true, "验证码发送成功!");
 #else
 #else
-            return ResultData(null, true, "验证码:" + code);
+		return ResultData(null, true, "验证码:" + code);
 #endif
 #endif
 	}
 	}
 }
 }

+ 11 - 11
src/Masuit.MyBlogs.Core/Extensions/Firewall/FirewallAttribute.cs

@@ -1,8 +1,4 @@
-using System.Net;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Web;
-using CacheManager.Core;
+using CacheManager.Core;
 using FreeRedis;
 using FreeRedis;
 using Markdig;
 using Markdig;
 using Masuit.MyBlogs.Core.Common;
 using Masuit.MyBlogs.Core.Common;
@@ -14,6 +10,10 @@ using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc.Filters;
 using Microsoft.AspNetCore.Mvc.Filters;
 using Microsoft.Extensions.Caching.Memory;
 using Microsoft.Extensions.Caching.Memory;
 using Microsoft.Net.Http.Headers;
 using Microsoft.Net.Http.Headers;
+using System.Net;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Web;
 using SameSiteMode = Microsoft.AspNetCore.Http.SameSiteMode;
 using SameSiteMode = Microsoft.AspNetCore.Http.SameSiteMode;
 
 
 namespace Masuit.MyBlogs.Core.Extensions.Firewall;
 namespace Masuit.MyBlogs.Core.Extensions.Firewall;
@@ -109,7 +109,7 @@ public sealed class FirewallAttribute : IAsyncActionFilter
 		}
 		}
 
 
 		//白名单地区
 		//白名单地区
-		var ipLocation = ip.GetIPLocation();
+		var ipLocation = context.HttpContext.Connection.RemoteIpAddress.GetIPLocation();
 		var (location, network, pos) = ipLocation;
 		var (location, network, pos) = ipLocation;
 		pos += ipLocation.Coodinate;
 		pos += ipLocation.Coodinate;
 		var allowedAreas = CommonHelper.SystemSettings.GetOrAdd("AllowedArea", "").Split(new[]
 		var allowedAreas = CommonHelper.SystemSettings.GetOrAdd("AllowedArea", "").Split(new[]
@@ -123,11 +123,7 @@ public sealed class FirewallAttribute : IAsyncActionFilter
 		}
 		}
 
 
 		//黑名单地区
 		//黑名单地区
-		var denyAreas = CommonHelper.SystemSettings.GetOrAdd("DenyArea", "").Split(new[]
-		{
-			',',
-			','
-		}, StringSplitOptions.RemoveEmptyEntries);
+		var denyAreas = CommonHelper.SystemSettings.GetOrAdd("DenyArea", "").Split(new[] { ',', ',' }, StringSplitOptions.RemoveEmptyEntries);
 		if (denyAreas.Any())
 		if (denyAreas.Any())
 		{
 		{
 			if (string.IsNullOrWhiteSpace(location) || string.IsNullOrWhiteSpace(network) || pos.Contains(denyAreas) || denyAreas.Intersect(pos.Split("|")).Any()) // 未知地区的,未知网络的,禁区的
 			if (string.IsNullOrWhiteSpace(location) || string.IsNullOrWhiteSpace(network) || pos.Contains(denyAreas) || denyAreas.Intersect(pos.Split("|")).Any()) // 未知地区的,未知网络的,禁区的
@@ -167,6 +163,10 @@ public sealed class FirewallAttribute : IAsyncActionFilter
 
 
 	private static bool Challenge(ActionExecutingContext context, out Task completedTask)
 	private static bool Challenge(ActionExecutingContext context, out Task completedTask)
 	{
 	{
+#if DEBUG
+		completedTask = Task.CompletedTask;
+		return false;
+#endif
 		var mode = CommonHelper.SystemSettings.GetOrAdd(SessionKey.ChallengeMode, "");
 		var mode = CommonHelper.SystemSettings.GetOrAdd(SessionKey.ChallengeMode, "");
 		if (mode == SessionKey.JSChallenge)
 		if (mode == SessionKey.JSChallenge)
 		{
 		{

+ 5 - 3
src/Masuit.MyBlogs.Core/Extensions/Firewall/IRequestLogger.cs

@@ -1,7 +1,7 @@
-using System.Collections.Concurrent;
-using System.Diagnostics;
-using Masuit.MyBlogs.Core.Common;
+using Masuit.MyBlogs.Core.Common;
 using Microsoft.Extensions.DependencyInjection.Extensions;
 using Microsoft.Extensions.DependencyInjection.Extensions;
+using System.Collections.Concurrent;
+using System.Diagnostics;
 
 
 namespace Masuit.MyBlogs.Core.Extensions.Firewall;
 namespace Masuit.MyBlogs.Core.Extensions.Firewall;
 
 
@@ -118,9 +118,11 @@ public class RequestLoggerBackService : ScheduledService
 
 
 	protected override Task ExecuteAsync()
 	protected override Task ExecuteAsync()
 	{
 	{
+#if RELEASE
 		using var scope = _scopeFactory.CreateAsyncScope();
 		using var scope = _scopeFactory.CreateAsyncScope();
 		var logger = scope.ServiceProvider.GetRequiredService<IRequestLogger>();
 		var logger = scope.ServiceProvider.GetRequiredService<IRequestLogger>();
 		logger.Process();
 		logger.Process();
+#endif
 		return Task.CompletedTask;
 		return Task.CompletedTask;
 	}
 	}
 }
 }

+ 5 - 0
src/Masuit.MyBlogs.Core/Infrastructure/Repository/BaseRepository.cs

@@ -144,6 +144,11 @@ public abstract class BaseRepository<T> : Disposable, IBaseRepository<T> where T
 		return GetQueryNoTracking(where, orderby, isAsc).FromCache().ToPooledListScope();
 		return GetQueryNoTracking(where, orderby, isAsc).FromCache().ToPooledListScope();
 	}
 	}
 
 
+	public PooledList<TDto> GetQueryFromCache<TDto>(Expression<Func<T, bool>> where) where TDto : class
+	{
+		return GetQuery<TDto>(where).FromCache().ToPooledListScope();
+	}
+
 	/// <summary>
 	/// <summary>
 	/// 基本查询方法,获取一个集合(不跟踪实体)
 	/// 基本查询方法,获取一个集合(不跟踪实体)
 	/// </summary>
 	/// </summary>

+ 1 - 0
src/Masuit.MyBlogs.Core/Infrastructure/Repository/Interface/IBaseRepository.cs

@@ -115,6 +115,7 @@ public interface IBaseRepository<T> : IDisposable where T : LuceneIndexableBaseE
 	/// <param name="isAsc">是否升序</param>
 	/// <param name="isAsc">是否升序</param>
 	/// <returns></returns>
 	/// <returns></returns>
 	PooledList<T> GetQueryFromCache<TS>(Expression<Func<T, bool>> where, Expression<Func<T, TS>> orderby, bool isAsc = true);
 	PooledList<T> GetQueryFromCache<TS>(Expression<Func<T, bool>> where, Expression<Func<T, TS>> orderby, bool isAsc = true);
+	PooledList<TDto> GetQueryFromCache<TDto>(Expression<Func<T, bool>> where) where TDto : class;
 
 
 	/// <summary>
 	/// <summary>
 	/// 基本查询方法,获取一个被AutoMapper映射后的集合,优先从二级缓存读取
 	/// 基本查询方法,获取一个被AutoMapper映射后的集合,优先从二级缓存读取

+ 69 - 5
src/Masuit.MyBlogs.Core/Infrastructure/Services/AdvertisementService.cs

@@ -45,6 +45,24 @@ public sealed partial class AdvertisementService : BaseService<Advertisement>, I
 	/// <param name="keywords"></param>
 	/// <param name="keywords"></param>
 	/// <returns></returns>
 	/// <returns></returns>
 	public List<AdvertisementDto> GetsByWeightedPrice(int count, AdvertiseType type, IPLocation ipinfo, int? cid = null, string keywords = "")
 	public List<AdvertisementDto> GetsByWeightedPrice(int count, AdvertiseType type, IPLocation ipinfo, int? cid = null, string keywords = "")
+	{
+		if (Count(a => a.Status == Status.Available) >= 200)
+		{
+			return GetsByWeightedPriceExternal(count, type, ipinfo, cid, keywords);
+		}
+		return GetsByWeightedPriceMemory(count, type, ipinfo, cid, keywords);
+	}
+
+	/// <summary>
+	/// 按价格随机筛选一个元素
+	/// </summary>
+	/// <param name="count">数量</param>
+	/// <param name="type">广告类型</param>
+	/// <param name="ipinfo"></param>
+	/// <param name="cid">分类id</param>
+	/// <param name="keywords"></param>
+	/// <returns></returns>
+	public List<AdvertisementDto> GetsByWeightedPriceExternal(int count, AdvertiseType type, IPLocation ipinfo, int? cid = null, string keywords = "")
 	{
 	{
 		var (location, _, _) = ipinfo;
 		var (location, _, _) = ipinfo;
 		return CacheManager.GetOrAdd($"Advertisement:{location.Crc32()}:{type}:{count}-{cid}-{keywords}", _ =>
 		return CacheManager.GetOrAdd($"Advertisement:{location.Crc32()}:{type}:{count}-{cid}-{keywords}", _ =>
@@ -55,11 +73,11 @@ public sealed partial class AdvertisementService : BaseService<Advertisement>, I
 			where = where.And(a => a.RegionMode == RegionLimitMode.All || (a.RegionMode == RegionLimitMode.AllowRegion ? Regex.IsMatch(location, a.Regions, RegexOptions.IgnoreCase) : !Regex.IsMatch(location, a.Regions, RegexOptions.IgnoreCase)));
 			where = where.And(a => a.RegionMode == RegionLimitMode.All || (a.RegionMode == RegionLimitMode.AllowRegion ? Regex.IsMatch(location, a.Regions, RegexOptions.IgnoreCase) : !Regex.IsMatch(location, a.Regions, RegexOptions.IgnoreCase)));
 			if (cid.HasValue)
 			if (cid.HasValue)
 			{
 			{
-				var pids = CategoryRepository.GetQuery(c => c.Id == cid).Select(c => c.ParentId + "|" + c.Parent.ParentId).FromCache(new MemoryCacheEntryOptions()
+				var pids = CategoryRepository.GetQuery(c => c.Id == cid).Select(c => string.Concat(c.ParentId, "|", c.Parent.ParentId).Trim('|')).Distinct().FromCache(new MemoryCacheEntryOptions()
 				{
 				{
 					AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(5)
 					AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(5)
-				}).ToArray();
-				var scid = pids.Select(s => s.Trim('|')).Where(s => !string.IsNullOrEmpty(s)).Append(cid + "").Join("|");
+				});
+				var scid = pids.Append(cid + "").Join("|");
 				if (Any(a => Regex.IsMatch(a.CategoryIds, scid)))
 				if (Any(a => Regex.IsMatch(a.CategoryIds, scid)))
 				{
 				{
 					where = where.And(a => Regex.IsMatch(a.CategoryIds, scid) || string.IsNullOrEmpty(a.CategoryIds));
 					where = where.And(a => Regex.IsMatch(a.CategoryIds, scid) || string.IsNullOrEmpty(a.CategoryIds));
@@ -76,11 +94,57 @@ public sealed partial class AdvertisementService : BaseService<Advertisement>, I
 			var list = GetQuery<AdvertisementDto>(where).Where(a => array.Contains(a.Id)).OrderBy(a => -Math.Log(EF.Functions.Random()) / ((double)a.Price / a.Types.Length * catCount / (string.IsNullOrEmpty(a.CategoryIds) ? catCount : (a.CategoryIds.Length + 1)))).Take(count).ToList();
 			var list = GetQuery<AdvertisementDto>(where).Where(a => array.Contains(a.Id)).OrderBy(a => -Math.Log(EF.Functions.Random()) / ((double)a.Price / a.Types.Length * catCount / (string.IsNullOrEmpty(a.CategoryIds) ? catCount : (a.CategoryIds.Length + 1)))).Take(count).ToList();
 			if (list.Count == 0 && keywords is { Length: > 0 })
 			if (list.Count == 0 && keywords is { Length: > 0 })
 			{
 			{
-				return GetsByWeightedPrice(count, type, ipinfo, cid);
+				return GetsByWeightedPriceExternal(count, type, ipinfo, cid);
+			}
+
+			var ids = list.Select(a => a.Id).ToArray();
+			GetQuery(a => ids.Contains(a.Id)).ExecuteUpdate(p => p.SetProperty(a => a.DisplayCount, a => a.DisplayCount + 1));
+			return list;
+		});
+	}
+
+	/// <summary>
+	/// 按价格随机筛选一个元素
+	/// </summary>
+	/// <param name="count">数量</param>
+	/// <param name="type">广告类型</param>
+	/// <param name="ipinfo"></param>
+	/// <param name="cid">分类id</param>
+	/// <param name="keywords"></param>
+	/// <returns></returns>
+	public List<AdvertisementDto> GetsByWeightedPriceMemory(int count, AdvertiseType type, IPLocation ipinfo, int? cid = null, string keywords = "")
+	{
+		var (location, _, _) = ipinfo;
+		var all = CacheManager.GetOrAdd("Advertisement:all", _ => GetQueryFromCache<AdvertisementDto>(a => a.Status == Status.Available).ToList());
+		return CacheManager.GetOrAdd($"Advertisement:{location.Crc32()}:{type}:{count}-{cid}-{keywords}", _ =>
+		{
+			var atype = type.ToString("D");
+			var catCount = CategoryRepository.Count(_ => true);
+			string scid = "";
+			if (cid.HasValue)
+			{
+				scid = CategoryRepository.GetQuery(c => c.Id == cid).Select(c => string.Concat(c.ParentId, "|", c.Parent.ParentId).Trim('|')).Distinct().FromCache(new MemoryCacheEntryOptions()
+				{
+					AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(5)
+				}).Append(cid + "").Join("|");
+			}
+
+			var array = all.GroupBy(a => a.Merchant).Select(g => g.OrderByRandom().FirstOrDefault().Id).Take(50).ToArray();
+			var list = all.Where(a => a.Types.Contains(atype))
+				.Where(a => a.RegionMode == RegionLimitMode.All || (a.RegionMode == RegionLimitMode.AllowRegion ? Regex.IsMatch(location, a.Regions, RegexOptions.IgnoreCase) : !Regex.IsMatch(location, a.Regions, RegexOptions.IgnoreCase)))
+				.WhereIf(cid.HasValue, a => Regex.IsMatch(a.CategoryIds + "", scid) || string.IsNullOrEmpty(a.CategoryIds))
+				.WhereIf(!keywords.IsNullOrEmpty(), a => (a.Title + a.Description).Contains(_luceneIndexSearcher.CutKeywords(keywords)))
+				.Where(a => array.Contains(a.Id)).OrderBy(a => -Math.Log(Random.Shared.NextDouble()) / ((double)a.Price / a.Types.Length * catCount / (string.IsNullOrEmpty(a.CategoryIds) ? catCount : (a.CategoryIds.Length + 1)))).Take(count).ToList();
+			if (list.Count == 0 && keywords is { Length: > 0 })
+			{
+				list.AddRange(all.Where(a => a.Types.Contains(atype))
+				.Where(a => a.RegionMode == RegionLimitMode.All || (a.RegionMode == RegionLimitMode.AllowRegion ? Regex.IsMatch(location, a.Regions, RegexOptions.IgnoreCase) : !Regex.IsMatch(location, a.Regions, RegexOptions.IgnoreCase)))
+				.WhereIf(cid.HasValue, a => Regex.IsMatch(a.CategoryIds + "", scid) || string.IsNullOrEmpty(a.CategoryIds))
+				.Where(a => array.Contains(a.Id)).OrderBy(a => -Math.Log(Random.Shared.NextDouble()) / ((double)a.Price / a.Types.Length * catCount / (string.IsNullOrEmpty(a.CategoryIds) ? catCount : (a.CategoryIds.Length + 1)))).Take(count));
 			}
 			}
 
 
 			var ids = list.Select(a => a.Id).ToArray();
 			var ids = list.Select(a => a.Id).ToArray();
-			GetQuery(a => ids.Contains(a.Id)).ExecuteUpdate(a => a.SetProperty(a => a.DisplayCount, a => a.DisplayCount + 1));
+			GetQuery(a => ids.Contains(a.Id)).ExecuteUpdate(p => p.SetProperty(a => a.DisplayCount, a => a.DisplayCount + 1));
 			return list;
 			return list;
 		});
 		});
 	}
 	}

+ 5 - 0
src/Masuit.MyBlogs.Core/Infrastructure/Services/BaseService.cs

@@ -158,6 +158,11 @@ public class BaseService<T> : IBaseService<T> where T : LuceneIndexableBaseEntit
 		return BaseDal.GetQueryFromCache(where);
 		return BaseDal.GetQueryFromCache(where);
 	}
 	}
 
 
+	public IEnumerable<TDto> GetQueryFromCache<TDto>(Expression<Func<T, bool>> where) where TDto : class
+	{
+		return BaseDal.GetQueryFromCache<TDto>(where);
+	}
+
 	/// <summary>
 	/// <summary>
 	/// 基本查询方法,获取一个集合,优先从二级缓存读取
 	/// 基本查询方法,获取一个集合,优先从二级缓存读取
 	/// </summary>
 	/// </summary>

+ 1 - 0
src/Masuit.MyBlogs.Core/Infrastructure/Services/Interface/IBaseService.cs

@@ -105,6 +105,7 @@ public interface IBaseService<T> where T : LuceneIndexableBaseEntity
 	/// <param name="where">查询条件</param>
 	/// <param name="where">查询条件</param>
 	/// <returns></returns>
 	/// <returns></returns>
 	IEnumerable<T> GetQueryFromCache(Expression<Func<T, bool>> @where);
 	IEnumerable<T> GetQueryFromCache(Expression<Func<T, bool>> @where);
+	IEnumerable<TDto> GetQueryFromCache<TDto>(Expression<Func<T, bool>> @where) where TDto : class;
 
 
 	/// <summary>
 	/// <summary>
 	/// 基本查询方法,获取一个集合,优先从二级缓存读取
 	/// 基本查询方法,获取一个集合,优先从二级缓存读取

+ 2 - 2
src/Masuit.MyBlogs.Core/Masuit.MyBlogs.Core.csproj

@@ -10,8 +10,8 @@
         <Copyright>懒得勤快</Copyright>
         <Copyright>懒得勤快</Copyright>
         <NeutralLanguage>zh-CN</NeutralLanguage>
         <NeutralLanguage>zh-CN</NeutralLanguage>
         <ImplicitUsings>enable</ImplicitUsings>
         <ImplicitUsings>enable</ImplicitUsings>
-        <SignAssembly>False</SignAssembly>
         <PackageReadmeFile>README.md</PackageReadmeFile>
         <PackageReadmeFile>README.md</PackageReadmeFile>
+        <TieredPGO>true</TieredPGO>
     </PropertyGroup>
     </PropertyGroup>
 
 
     <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
     <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
@@ -69,7 +69,7 @@
         <PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.23" />
         <PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.23" />
         <PackageReference Include="TimeZoneConverter" Version="6.0.1" />
         <PackageReference Include="TimeZoneConverter" Version="6.0.1" />
         <PackageReference Include="WilderMinds.RssSyndication" Version="1.7.0" />
         <PackageReference Include="WilderMinds.RssSyndication" Version="1.7.0" />
-        <PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="7.17.1" />
+        <PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="7.18.0" />
     </ItemGroup>
     </ItemGroup>
     <ItemGroup>
     <ItemGroup>
         <Content Update="appsettings.json">
         <Content Update="appsettings.json">

+ 5 - 1
src/Masuit.MyBlogs.Core/Properties/PublishProfiles/FolderProfile.pubxml

@@ -14,8 +14,12 @@
     <ExcludeApp_Data>false</ExcludeApp_Data>
     <ExcludeApp_Data>false</ExcludeApp_Data>
     <TargetFramework>net7.0</TargetFramework>
     <TargetFramework>net7.0</TargetFramework>
     <ProjectGuid>2f8270e4-5e57-4ce4-ab5f-8008f9fc8c7c</ProjectGuid>
     <ProjectGuid>2f8270e4-5e57-4ce4-ab5f-8008f9fc8c7c</ProjectGuid>
-    <SelfContained>false</SelfContained>
+    <SelfContained>true</SelfContained>
     <publishUrl>bin\Release\publish\</publishUrl>
     <publishUrl>bin\Release\publish\</publishUrl>
     <DeleteExistingFiles>true</DeleteExistingFiles>
     <DeleteExistingFiles>true</DeleteExistingFiles>
+    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
+    <PublishSingleFile>true</PublishSingleFile>
+    <PublishReadyToRun>true</PublishReadyToRun>
+    <PublishTrimmed>true</PublishTrimmed>
   </PropertyGroup>
   </PropertyGroup>
 </Project>
 </Project>

+ 1 - 0
src/Masuit.MyBlogs.Core/Startup.cs

@@ -17,6 +17,7 @@ using Masuit.Tools.AspNetCore.Mime;
 using Masuit.Tools.Config;
 using Masuit.Tools.Config;
 using Masuit.Tools.Core.AspNetCore;
 using Masuit.Tools.Core.AspNetCore;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Caching.Memory;
 using Microsoft.Extensions.Primitives;
 using Microsoft.Extensions.Primitives;
 using Newtonsoft.Json;
 using Newtonsoft.Json;
 using SixLabors.ImageSharp.Web.DependencyInjection;
 using SixLabors.ImageSharp.Web.DependencyInjection;

+ 2 - 3
src/Masuit.MyBlogs.Core/Views/Links/Index.cshtml

@@ -1,6 +1,5 @@
 @using Masuit.MyBlogs.Core.Models.DTO
 @using Masuit.MyBlogs.Core.Models.DTO
-@using Masuit.MyBlogs.Core.Models.Entity
-@model List<Masuit.MyBlogs.Core.Models.DTO.LinksDto>
+@model IEnumerable<Masuit.MyBlogs.Core.Models.DTO.LinksDto>
 
 
 @{
 @{
     ViewBag.Title = "友情链接大全";
     ViewBag.Title = "友情链接大全";
@@ -20,7 +19,7 @@
     </article>
     </article>
     <section>
     <section>
         <div class="button-effect">
         <div class="button-effect">
-            @foreach (LinksDto link in Model)
+            @foreach (var link in Model)
             {
             {
                 <a class="effect effect-5" href="@link.Url" title="@link.Name" target="_blank" referrerpolicy="unsafe-url">@link.Name</a>
                 <a class="effect effect-5" href="@link.Url" title="@link.Name" target="_blank" referrerpolicy="unsafe-url">@link.Name</a>
             }
             }

+ 2 - 2
src/Masuit.MyBlogs.Core/Views/Links/Index_Admin.cshtml

@@ -1,5 +1,5 @@
 @using Masuit.MyBlogs.Core.Models.DTO
 @using Masuit.MyBlogs.Core.Models.DTO
-@model List<Masuit.MyBlogs.Core.Models.DTO.LinksDto>
+@model IEnumerable<Masuit.MyBlogs.Core.Models.DTO.LinksDto>
 
 
 @{
 @{
     ViewBag.Title = "友情链接大全";
     ViewBag.Title = "友情链接大全";
@@ -19,7 +19,7 @@
     </article>
     </article>
     <section>
     <section>
         <div class="button-effect">
         <div class="button-effect">
-            @foreach (LinksDto link in Model)
+            @foreach (var link in Model)
             {
             {
                 <a class="effect effect-5" href="@link.Url" title="@link.Name" target="_blank" referrerpolicy="unsafe-url">@link.Name</a>
                 <a class="effect effect-5" href="@link.Url" title="@link.Name" target="_blank" referrerpolicy="unsafe-url">@link.Name</a>
             }
             }

+ 2 - 2
src/Masuit.MyBlogs.Core/wwwroot/ng-views/views/post/postlist.html

@@ -35,7 +35,7 @@
         </div>
         </div>
     <table ng-table="list.tableParams" class="table table-striped table-vmiddle table-bordered table-hover table-condensed">
     <table ng-table="list.tableParams" class="table table-striped table-vmiddle table-bordered table-hover table-condensed">
         <tr ng-repeat="row in $data" ng-class="{'warning':(diffDateFromNow(row.ModifyDate)>365)}">
         <tr ng-repeat="row in $data" ng-class="{'warning':(diffDateFromNow(row.ModifyDate)>365)}">
-            <td data-title="'标题'" ng-class="{'danger':(row.AverageViewCount<1)}">
+            <td data-title="'标题'" ng-class="{'danger':(row.AverageViewCount<1 && row.IsNsfw==false && row.LimitDesc=='无限制')}">
                 <a ng-href="/{{row.Id}}" target="_blank">{{row.Title}}</a>
                 <a ng-href="/{{row.Id}}" target="_blank">{{row.Title}}</a>
             </td>
             </td>
             <td data-title="'作者'">
             <td data-title="'作者'">
@@ -107,7 +107,7 @@
                     <span class="el-switch-style" ng-click="nsfwSwitch(row.Id)"></span>
                     <span class="el-switch-style" ng-click="nsfwSwitch(row.Id)"></span>
                 </label>
                 </label>
             </td>
             </td>
-            <td data-title="'操作'" style="width: 195px;" ng-class="{'danger':(row.AverageViewCount<1)}">
+            <td data-title="'操作'" style="width: 195px;" ng-class="{'danger':(row.AverageViewCount<1 && row.IsNsfw==false && row.LimitDesc=='无限制')}">
                 <div class="btn-group">
                 <div class="btn-group">
                     <button class="btn btn-default btn-sm waves-effect" ng-click="list.pass(row)" ng-if="row.Status=='审核中'">
                     <button class="btn btn-default btn-sm waves-effect" ng-click="list.pass(row)" ng-if="row.Status=='审核中'">
                         <i class="icon-checkmark"></i>
                         <i class="icon-checkmark"></i>