1
0

AdvertisementController.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. using AutoMapper.QueryableExtensions;
  2. using Collections.Pooled;
  3. using Masuit.MyBlogs.Core.Common;
  4. using Masuit.MyBlogs.Core.Extensions;
  5. using Masuit.MyBlogs.Core.Infrastructure.Services.Interface;
  6. using Masuit.MyBlogs.Core.Models.DTO;
  7. using Masuit.MyBlogs.Core.Models.Entity;
  8. using Masuit.MyBlogs.Core.Models.Enum;
  9. using Masuit.MyBlogs.Core.Models.ViewModel;
  10. using Masuit.Tools.AspNetCore.Mime;
  11. using Masuit.Tools.AspNetCore.ModelBinder;
  12. using Masuit.Tools.AspNetCore.ResumeFileResults.Extensions;
  13. using Masuit.Tools.Core.Net;
  14. using Masuit.Tools.Database;
  15. using Masuit.Tools.Excel;
  16. using Masuit.Tools.Linq;
  17. using Masuit.Tools.Models;
  18. using Microsoft.AspNetCore.Mvc;
  19. using Microsoft.EntityFrameworkCore;
  20. using Microsoft.Net.Http.Headers;
  21. using System.ComponentModel.DataAnnotations;
  22. using System.Linq.Expressions;
  23. using System.Net;
  24. using System.Text.RegularExpressions;
  25. namespace Masuit.MyBlogs.Core.Controllers;
  26. [Route("partner/[action]")]
  27. public class AdvertisementController : BaseController
  28. {
  29. public IAdvertisementClickRecordService ClickRecordService { get; set; }
  30. /// <summary>
  31. /// 前往
  32. /// </summary>
  33. /// <param name="id">广告id</param>
  34. /// <returns></returns>
  35. [HttpGet("/p{id:int}"), HttpGet("{id:int}", Order = 1), ResponseCache(Duration = 3600)]
  36. public async Task<IActionResult> Redirect(int id)
  37. {
  38. var ad = await AdsService.GetByIdAsync(id) ?? throw new NotFoundException("推广链接不存在");
  39. if (!Request.IsRobot() && string.IsNullOrEmpty(HttpContext.Session.Get<string>("ads" + id)))
  40. {
  41. HttpContext.Session.Set("ads" + id, id.ToString());
  42. ad.ClickRecords.Add(new AdvertisementClickRecord()
  43. {
  44. IP = ClientIP,
  45. Location = ClientIP.GetIPLocation(),
  46. Referer = Request.Headers[HeaderNames.Referer].ToString(),
  47. Time = DateTime.Now
  48. });
  49. await AdsService.SaveChangesAsync();
  50. var start = DateTime.Today.AddMonths(-6);
  51. await ClickRecordService.GetQuery(a => a.Time < start).DeleteFromQueryAsync();
  52. }
  53. return Redirect(ad.Url);
  54. }
  55. /// <summary>
  56. /// 获取分页
  57. /// </summary>
  58. /// <returns></returns>
  59. [MyAuthorize]
  60. public ActionResult GetPageData(int page = 1, [Range(1, int.MaxValue, ErrorMessage = "页大小必须大于0")] int size = 10, string kw = "")
  61. {
  62. Expression<Func<Advertisement, bool>> where = p => true;
  63. if (!string.IsNullOrEmpty(kw))
  64. {
  65. kw = Regex.Escape(kw);
  66. where = where.And(p => Regex.IsMatch(p.Title + p.Description + p.Url, kw, RegexOptions.IgnoreCase));
  67. }
  68. var list = AdsService.GetQuery(where).OrderByDescending(p => p.Status == Status.Available).ThenByDescending(a => a.Price).ThenByDescending(a => a.Id).ProjectTo<AdvertisementViewModel>(MapperConfig).ToPagedList(page, size);
  69. return Ok(list);
  70. }
  71. /// <summary>
  72. /// 保存广告
  73. /// </summary>
  74. /// <param name="model"></param>
  75. /// <returns></returns>
  76. [HttpPost, MyAuthorize]
  77. public async Task<IActionResult> Save([FromBodyOrDefault] AdvertisementDto model)
  78. {
  79. var entity = AdsService[model.Id] ?? new Advertisement();
  80. model.CategoryIds = model.CategoryIds?.Replace("null", "");
  81. model.Regions = Regex.Replace(model.Regions ?? "", @"(\p{P}|\p{Z}|\p{S})+", "|");
  82. if (model.RegionMode == RegionLimitMode.All)
  83. {
  84. model.Regions = null;
  85. }
  86. if (model.Types.Contains(AdvertiseType.Banner.ToString("D")) && string.IsNullOrEmpty(model.ImageUrl))
  87. {
  88. return ResultData(null, false, "宣传大图不能为空");
  89. }
  90. if (model.Types.Length > 3 && string.IsNullOrEmpty(model.ThumbImgUrl))
  91. {
  92. return ResultData(null, false, "宣传小图不能为空");
  93. }
  94. Mapper.Map(model, entity);
  95. var b = await AdsService.AddOrUpdateSavedAsync(a => a.Id, entity) > 0;
  96. return ResultData(null, b, b ? "保存成功" : "保存失败");
  97. }
  98. /// <summary>
  99. /// 删除广告
  100. /// </summary>
  101. /// <param name="id"></param>
  102. /// <returns></returns>
  103. [HttpPost("{id}"), HttpGet("{id}"), MyAuthorize]
  104. public async Task<IActionResult> Delete(int id)
  105. {
  106. bool b = await AdsService.DeleteByIdAsync(id) > 0;
  107. return ResultData(null, b, b ? "删除成功" : "删除失败");
  108. }
  109. /// <summary>
  110. /// 广告上下架
  111. /// </summary>
  112. /// <param name="id">文章id</param>
  113. /// <returns></returns>
  114. [MyAuthorize, HttpPost("{id}")]
  115. public async Task<ActionResult> ChangeState(int id)
  116. {
  117. var ad = await AdsService.GetByIdAsync(id) ?? throw new NotFoundException("广告不存在!");
  118. ad.Status = ad.Status == Status.Available ? Status.Unavailable : Status.Available;
  119. return ResultData(null, await AdsService.SaveChangesAsync() > 0, ad.Status == Status.Available ? $"【{ad.Title}】已上架!" : $"【{ad.Title}】已下架!");
  120. }
  121. /// <summary>
  122. /// 随机前往一个广告
  123. /// </summary>
  124. /// <returns></returns>
  125. [HttpGet("/partner-random")]
  126. public async Task<ActionResult> RandomGo()
  127. {
  128. var ad = AdsService.GetByWeightedPrice((AdvertiseType)new Random().Next(1, 4), Request.Location());
  129. if (!Request.IsRobot() && string.IsNullOrEmpty(HttpContext.Session.Get<string>("ads" + ad.Id)))
  130. {
  131. HttpContext.Session.Set("ads" + ad.Id, ad.Id.ToString());
  132. ad.ClickRecords.Add(new AdvertisementClickRecord()
  133. {
  134. IP = ClientIP,
  135. Location = ClientIP.GetIPLocation(),
  136. Referer = Request.Headers[HeaderNames.Referer].ToString(),
  137. Time = DateTime.Now
  138. });
  139. await AdsService.SaveChangesAsync();
  140. var start = DateTime.Today.AddMonths(-1);
  141. await ClickRecordService.GetQuery(a => a.Time < start).DeleteFromQueryAsync();
  142. }
  143. return Redirect(ad.Url);
  144. }
  145. /// <summary>
  146. /// 广告访问记录
  147. /// </summary>
  148. /// <param name="id"></param>
  149. /// <param name="page"></param>
  150. /// <param name="size"></param>
  151. /// <returns></returns>
  152. [HttpGet("/partner/{id}/records"), MyAuthorize]
  153. public async Task<IActionResult> ClickRecords(int id, int page = 1, int size = 15, string kw = "")
  154. {
  155. Expression<Func<AdvertisementClickRecord, bool>> where = e => e.AdvertisementId == id;
  156. if (!string.IsNullOrEmpty(kw))
  157. {
  158. kw = Regex.Escape(kw);
  159. where = where.And(e => Regex.IsMatch(e.IP + e.Location + e.Referer, kw));
  160. }
  161. var pages = await ClickRecordService.GetPagesAsync<DateTime, AdvertisementClickRecordViewModel>(page, size, where, e => e.Time, false);
  162. return Ok(pages);
  163. }
  164. /// <summary>
  165. /// 导出广告访问记录
  166. /// </summary>
  167. /// <param name="id"></param>
  168. /// <param name="page"></param>
  169. /// <param name="size"></param>
  170. /// <returns></returns>
  171. [HttpGet("/partner/{id}/records-export"), MyAuthorize]
  172. public IActionResult ExportClickRecords(int id)
  173. {
  174. using var list = ClickRecordService.GetQuery<DateTime, AdvertisementClickRecordViewModel>(e => e.AdvertisementId == id, e => e.Time, false).ToPooledList();
  175. using var ms = list.ToDataTable().ToExcel();
  176. var advertisement = AdsService[id];
  177. return this.ResumeFile(ms.ToArray(), ContentType.Xlsx, advertisement.Title + "访问记录.xlsx");
  178. }
  179. /// <summary>
  180. /// 广告访问记录图表
  181. /// </summary>
  182. /// <param name="id"></param>
  183. /// <param name="cancellationToken"></param>
  184. /// <returns></returns>
  185. [HttpGet("/partner/{id}/records-chart"), MyAuthorize]
  186. [ProducesResponseType((int)HttpStatusCode.OK)]
  187. public async Task<IActionResult> ClickRecordsChart(int id, CancellationToken cancellationToken)
  188. {
  189. var list = await ClickRecordService.GetQuery(e => e.AdvertisementId == id).Select(e => e.Time).GroupBy(t => t.Date).Select(g => new
  190. {
  191. Date = g.Key,
  192. Count = g.Count()
  193. }).OrderBy(a => a.Date).ToListAsync(cancellationToken);
  194. return Ok(list);
  195. }
  196. /// <summary>
  197. /// 广告访问记录图表
  198. /// </summary>
  199. /// <param name="cancellationToken"></param>
  200. /// <returns></returns>
  201. [HttpGet("/partner/records-chart"), MyAuthorize]
  202. [ProducesResponseType((int)HttpStatusCode.OK)]
  203. public async Task<IActionResult> ClickRecordsChart(CancellationToken cancellationToken)
  204. {
  205. var start = DateTime.Now.AddMonths(-1);
  206. var list = await ClickRecordService.GetQuery(e => e.Time >= start).Select(e => e.Time).GroupBy(t => t.Date).Select(g => new
  207. {
  208. Date = g.Key,
  209. Count = g.Count()
  210. }).OrderBy(a => a.Date).ToListAsync(cancellationToken);
  211. return Ok(list);
  212. }
  213. /// <summary>
  214. /// 广告访问记录分析
  215. /// </summary>
  216. /// <param name="id"></param>
  217. /// <returns></returns>
  218. [HttpGet("/partner/{id}/insight"), MyAuthorize]
  219. public IActionResult ClickRecordsInsight(int id)
  220. {
  221. return View(AdsService[id]);
  222. }
  223. /// <summary>
  224. /// 设置分类
  225. /// </summary>
  226. /// <param name="id"></param>
  227. /// <param name="cids"></param>
  228. /// <returns></returns>
  229. /// <exception cref="NotFoundException"></exception>
  230. [HttpPost("/partner/{id}/categories")]
  231. public async Task<ActionResult> SetCategories(int id, [FromBodyOrDefault] string cids)
  232. {
  233. var entity = await AdsService.GetByIdAsync(id) ?? throw new NotFoundException("广告未找到");
  234. entity.CategoryIds = cids;
  235. await AdsService.SaveChangesAsync();
  236. return Ok();
  237. }
  238. }