TracksAdminController.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. using System.Text.Json;
  2. using System.Threading.Tasks;
  3. using CSRedis;
  4. using Dapper;
  5. using dodohold.core;
  6. using Microsoft.AspNetCore.Http;
  7. using Microsoft.AspNetCore.Mvc;
  8. using molilian.core;
  9. namespace molilian.api.Controllers
  10. {
  11. [ApiController]
  12. [MyAuthorize("admin")]
  13. [Route("api/[controller]/[action]")]
  14. public class TracksAdminController : ControllerBase
  15. {
  16. private const string PddTrackWhere = "(LOWER(r.platform)='pdd' OR r.platform='拼多多' OR r.track_link_id IN (21,22) OR r.unique_id LIKE '9|%')";
  17. private const string VisiblePddAccountWhere = "NOT EXISTS (SELECT 1 FROM pdd_pool hp WHERE hp.id=r.account_id AND hp.is_hide=1)";
  18. readonly IAuthorizationProvider provider = new AdminProvider();
  19. protected IHttpContextAccessor _accessor;
  20. public TracksAdminController(IHttpContextAccessor accessor)
  21. {
  22. _accessor = accessor;
  23. }
  24. [HttpPost]
  25. public ActionResult list([FromBody] JsonElement form)
  26. {
  27. var token = provider.Get(_accessor.HttpContext);
  28. int page = form.Read("current", 1);
  29. int size = form.Read("pageSize", 10);
  30. bool getTotal = form.Read("getTotal", true);
  31. string sort = form.Read("sort", "id");
  32. string order = form.Read("order", "DESC");
  33. string keyword = form.Read("keyword", string.Empty);
  34. string filter = string.Empty;
  35. if (!string.IsNullOrEmpty(keyword))
  36. {
  37. filter += " AND (event_type LIKE @keyword OR platform LIKE @keyword OR typename LIKE @keyword OR scene LIKE @keyword OR unique_id LIKE @keyword)";
  38. keyword = $"%{keyword}%";
  39. }
  40. filter = filter.StringTrimStart(" AND ");
  41. order = "descending".Equals(order, System.StringComparison.OrdinalIgnoreCase) ? "DESC" :
  42. "ascending".Equals(order, System.StringComparison.OrdinalIgnoreCase) ? "ASC" : order;
  43. string orderBy = string.IsNullOrEmpty(sort) ? "id DESC" : $"{sort} {order}";
  44. var result = new DBContext.Table("track_links")
  45. .Where(filter, new { keyword })
  46. .Page(size, page)
  47. .Order(orderBy)
  48. .PageList<dynamic>(getTotal);
  49. return new APIResult(new { data = result });
  50. }
  51. [HttpGet]
  52. public ActionResult info([FromQuery] int id)
  53. {
  54. var token = provider.Get(_accessor.HttpContext);
  55. var item = new DBContext.Table("track_links").Get<TrackLinkDTO>("id=@id", new { id });
  56. return new APIResult(new { data = item });
  57. }
  58. [HttpPost]
  59. public ActionResult report([FromBody] JsonElement form)
  60. {
  61. var token = provider.Get(_accessor.HttpContext);
  62. int page = form.Read("current", 1);
  63. int size = form.Read("pageSize", 10);
  64. bool getTotal = form.Read("getTotal", true);
  65. int linkId = form.Read("track_link_id", 0);
  66. int accountId = form.Read("account_id", -1);
  67. bool includeAccountBreakdown = form.Read("include_account_breakdown", false);
  68. bool accountBreakdownOnly = form.Read("account_breakdown_only", false);
  69. string eventType = form.Read("event_type", string.Empty);
  70. string platform = form.Read("platform", string.Empty);
  71. string typename = form.Read("typename", string.Empty);
  72. string scene = form.Read("scene", string.Empty);
  73. string uniqueId = form.Read("unique_id", string.Empty);
  74. DateTime? start = form.Read<DateTime?>("start", null);
  75. DateTime? end = form.Read<DateTime?>("end", null);
  76. page = Math.Max(page, 1);
  77. size = Math.Max(size, 1);
  78. var parameters = new DynamicParameters(new
  79. {
  80. linkId,
  81. accountId,
  82. eventType,
  83. platform,
  84. typename,
  85. scene,
  86. uniqueId,
  87. start,
  88. end,
  89. offset = (page - 1) * size,
  90. size
  91. });
  92. var baseWhere = new List<string>();
  93. if (linkId > 0) baseWhere.Add("r.track_link_id=@linkId");
  94. if (!string.IsNullOrWhiteSpace(eventType)) baseWhere.Add("r.event_type=@eventType");
  95. if (!string.IsNullOrWhiteSpace(platform)) baseWhere.Add("r.platform=@platform");
  96. if (!string.IsNullOrWhiteSpace(typename)) baseWhere.Add("r.typename=@typename");
  97. if (!string.IsNullOrWhiteSpace(scene)) baseWhere.Add("r.scene=@scene");
  98. if (!string.IsNullOrWhiteSpace(uniqueId)) baseWhere.Add("r.unique_id=@uniqueId");
  99. if (start.HasValue) baseWhere.Add("r.report_date>=@start");
  100. if (end.HasValue) baseWhere.Add("r.report_date<=@end");
  101. string unionSql = BuildTrackReportSql(baseWhere, accountId, includeAccountBreakdown, accountBreakdownOnly);
  102. string dataSql = $@"
  103. SELECT *
  104. FROM ({unionSql}) t
  105. ORDER BY t.report_date DESC, t.id DESC
  106. LIMIT @offset,@size";
  107. using var conn = DBContext.GetOpenConnection();
  108. var list = SqlMapper.Query<TrackDailyReportDTO>(conn, dataSql, parameters).ToList();
  109. int count = list.Count;
  110. if (getTotal)
  111. {
  112. count = conn.ExecuteScalar<int>($"SELECT COUNT(1) FROM ({unionSql}) t", parameters);
  113. }
  114. return new APIResult(new { data = new { list, count } });
  115. }
  116. private static string BuildTrackReportSql(List<string> baseWhere, int accountId, bool includeAccountBreakdown, bool accountBreakdownOnly)
  117. {
  118. var selects = new List<string>();
  119. if (accountBreakdownOnly)
  120. {
  121. selects.Add(BuildStoredReportSelect([.. baseWhere, "r.account_id>0", $"(NOT {PddTrackWhere} OR {VisiblePddAccountWhere})"]));
  122. }
  123. else if (accountId > 0)
  124. {
  125. selects.Add(BuildStoredReportSelect([.. baseWhere, "r.account_id=@accountId", $"(NOT {PddTrackWhere} OR {VisiblePddAccountWhere})"]));
  126. }
  127. else if (accountId == 0 || !includeAccountBreakdown)
  128. {
  129. selects.Add(BuildStoredReportSelect([.. baseWhere, "r.account_id=0", $"NOT {PddTrackWhere}"]));
  130. selects.Add(BuildPddTotalReportSelect([.. baseWhere, "r.account_id>0", PddTrackWhere, VisiblePddAccountWhere]));
  131. }
  132. else
  133. {
  134. selects.Add(BuildStoredReportSelect([.. baseWhere, $"NOT {PddTrackWhere}"]));
  135. selects.Add(BuildStoredReportSelect([.. baseWhere, "r.account_id>0", PddTrackWhere, VisiblePddAccountWhere]));
  136. selects.Add(BuildPddTotalReportSelect([.. baseWhere, "r.account_id>0", PddTrackWhere, VisiblePddAccountWhere]));
  137. }
  138. return string.Join("\nUNION ALL\n", selects);
  139. }
  140. private static string BuildStoredReportSelect(List<string> where)
  141. {
  142. return $@"
  143. SELECT
  144. r.id,
  145. r.report_date,
  146. r.event_type,
  147. r.platform,
  148. r.typename,
  149. r.scene,
  150. r.unique_id,
  151. r.track_link_id,
  152. r.account_id,
  153. r.event_count,
  154. r.create_time,
  155. r.update_time
  156. FROM track_daily_report r
  157. {BuildWhere(where)}";
  158. }
  159. private static string BuildPddTotalReportSelect(List<string> where)
  160. {
  161. return $@"
  162. SELECT
  163. MIN(r.id) AS id,
  164. r.report_date,
  165. r.event_type,
  166. r.platform,
  167. r.typename,
  168. r.scene,
  169. r.unique_id,
  170. r.track_link_id,
  171. 0 AS account_id,
  172. CAST(SUM(r.event_count) AS SIGNED) AS event_count,
  173. MIN(r.create_time) AS create_time,
  174. MAX(r.update_time) AS update_time
  175. FROM track_daily_report r
  176. {BuildWhere(where)}
  177. GROUP BY
  178. r.report_date,
  179. r.event_type,
  180. r.platform,
  181. r.typename,
  182. r.scene,
  183. r.unique_id,
  184. r.track_link_id
  185. HAVING SUM(r.event_count)>0";
  186. }
  187. private static string BuildWhere(List<string> where)
  188. {
  189. return where.Count == 0 ? string.Empty : $"WHERE {string.Join(" AND ", where)}";
  190. }
  191. [HttpPost]
  192. public async Task<ActionResult> hourly([FromBody] JsonElement form)
  193. {
  194. var token = provider.Get(_accessor.HttpContext);
  195. int linkId = form.Read("track_link_id", 0);
  196. int accountId = form.Read("account_id", 0);
  197. string dateText = form.Read("date", string.Empty);
  198. string scene = form.Read("scene", string.Empty);
  199. DateTime date = DateTime.TryParse(dateText, out var parsed) ? parsed.Date : DateTime.Now.Date;
  200. var list = await TracksCore.GetHourlyReportAsync(linkId, date, scene, accountId);
  201. return new APIResult(new
  202. {
  203. data = new
  204. {
  205. list,
  206. count = list.Count
  207. }
  208. });
  209. }
  210. [HttpPost]
  211. public async Task<ActionResult> parse_metrics([FromBody] JsonElement form)
  212. {
  213. var token = provider.Get(_accessor.HttpContext);
  214. int page = form.Read("current", 1);
  215. int size = form.Read("pageSize", 10);
  216. bool getTotal = form.Read("getTotal", true);
  217. int accountId = form.Read("account_id", -1);
  218. bool accountBreakdownOnly = form.Read("account_breakdown_only", false);
  219. string platform = form.Read("platform", string.Empty);
  220. string riskStrategy = form.Read("risk_strategy", string.Empty);
  221. int launchSceneValue = form.Read("launch_scene", int.MinValue);
  222. int? launchScene = launchSceneValue == int.MinValue ? null : launchSceneValue;
  223. DateTime? start = form.Read<DateTime?>("start", null);
  224. DateTime? end = form.Read<DateTime?>("end", null);
  225. DateTime startDate = start?.Date ?? DateTime.Now.Date;
  226. DateTime endDate = end?.Date ?? startDate;
  227. var result = await TracksCore.GetParseMetricReportAsync(
  228. startDate,
  229. endDate,
  230. page,
  231. size,
  232. getTotal,
  233. accountId,
  234. accountBreakdownOnly,
  235. platform,
  236. riskStrategy,
  237. launchScene);
  238. return new APIResult(new { data = result });
  239. }
  240. [HttpPost]
  241. public async Task<ActionResult> parse_metric_hourly([FromBody] JsonElement form)
  242. {
  243. var token = provider.Get(_accessor.HttpContext);
  244. string dateText = form.Read("date", string.Empty);
  245. string platform = form.Read("platform", string.Empty);
  246. string riskStrategy = form.Read("risk_strategy", string.Empty);
  247. int launchSceneValue = form.Read("launch_scene", int.MinValue);
  248. int? launchScene = launchSceneValue == int.MinValue ? null : launchSceneValue;
  249. int accountId = form.Read("account_id", 0);
  250. DateTime date = DateTime.TryParse(dateText, out var parsed)
  251. ? parsed.Date
  252. : DateTime.Now.Date;
  253. var list = await TracksCore.GetParseMetricHourlyReportAsync(
  254. date,
  255. platform,
  256. riskStrategy,
  257. launchScene,
  258. accountId);
  259. return new APIResult(new
  260. {
  261. data = new
  262. {
  263. list,
  264. count = list.Count
  265. }
  266. });
  267. }
  268. [HttpPost]
  269. public async Task<ActionResult> backfill_parse_metrics([FromBody] JsonElement form)
  270. {
  271. var token = provider.Get(_accessor.HttpContext);
  272. string reportDateText = form.Read("reportDate", string.Empty);
  273. string platform = form.Read("platform", string.Empty);
  274. string riskStrategy = form.Read("risk_strategy", string.Empty);
  275. int launchSceneValue = form.Read("launch_scene", int.MinValue);
  276. int? launchScene = launchSceneValue == int.MinValue ? null : launchSceneValue;
  277. DateTime targetDate = DateTime.TryParse(reportDateText, out var parsed)
  278. ? parsed.Date
  279. : DateTime.Now.Date;
  280. var result = await TracksCore.BackfillParseMetricCountersAsync(targetDate, platform, riskStrategy, launchScene);
  281. return new APIResult(new
  282. {
  283. data = new
  284. {
  285. success = true,
  286. msg = "重新计算完成",
  287. result
  288. }
  289. });
  290. }
  291. [HttpPost]
  292. public async Task<ActionResult> create([FromBody] TrackLinkDTO data)
  293. {
  294. var token = provider.Get(_accessor.HttpContext);
  295. if (string.IsNullOrWhiteSpace(data.typename)) data.typename = data.platform;
  296. if (string.IsNullOrWhiteSpace(data.platform)) data.platform = data.typename;
  297. var link = await TracksCore.CreateLinkAsync(data.event_type, data.platform, data.typename, data.scene, data.unique_id, data.description, true);
  298. bool success = link != null && link.id > 0;
  299. return new APIResult(new
  300. {
  301. data = link,
  302. success,
  303. msg = success ? "创建成功" : "创建失败"
  304. });
  305. }
  306. [HttpPost]
  307. public ActionResult delete([FromBody] JsonElement form)
  308. {
  309. var token = provider.Get(_accessor.HttpContext);
  310. int id = form.Read<int>("id");
  311. using var conn = DBContext.GetOpenConnection();
  312. var item = new DBContext.Table(conn, "track_links").Get<TrackLinkDTO>("id=@id", new { id });
  313. if (item == null) return new APIResult(new { data = new { success = false, msg = "记录不存在" } });
  314. var result = new DBContext.Table("track_links").Delete("id=@id", new { id });
  315. bool success = result > 0;
  316. if (success)
  317. {
  318. string eventType = (item.event_type ?? string.Empty).Trim().ToLowerInvariant();
  319. string platform = (item.platform ?? string.Empty).Trim();
  320. string typename = (item.typename ?? string.Empty).Trim();
  321. string scene = string.IsNullOrWhiteSpace(item.scene) ? string.Empty : item.scene.Trim();
  322. string uniqueId = string.IsNullOrWhiteSpace(item.unique_id) ? string.Empty : item.unique_id.Trim();
  323. string cacheKey = TracksCore.GetLinkCacheKey(eventType, platform, typename, scene, uniqueId);
  324. RedisHelper.Del(cacheKey);
  325. RedisHelper.Del(TracksCore.GetLinkIdCacheKey(item.id));
  326. }
  327. return new APIResult(new
  328. {
  329. data = new { success, msg = success ? "删除成功" : "删除失败" },
  330. });
  331. }
  332. }
  333. }