TaobaoController.cs 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059
  1. using molilian.core;
  2. using dodohold.core;
  3. using Microsoft.AspNetCore.Mvc;
  4. using System.Text.Json;
  5. using System.Net;
  6. using static QRCoder.PayloadGenerator;
  7. using MySqlX.XDevAPI;
  8. using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
  9. using StackExchange.Redis;
  10. namespace molilian.api.Controllers
  11. {
  12. [ApiController]
  13. [MyAuthorize("admin")]
  14. [Route("api/[controller]/[action]")]
  15. [Route("coupon_api/[controller]/[action]")]
  16. public class TaobaoController : ControllerBase
  17. {
  18. readonly IAuthorizationProvider provider = new AdminProvider();
  19. protected IHttpContextAccessor _accessor;
  20. public TaobaoController(IHttpContextAccessor accessor)
  21. {
  22. _accessor = accessor;
  23. }
  24. [HttpPost]
  25. public async Task<ActionResult> updateCookies([FromBody] JsonElement form)
  26. {
  27. var clientIp = _accessor.HttpContext.GetUserIp();
  28. var token = provider.Get(_accessor.HttpContext);
  29. string user_agent = _accessor.HttpContext.Request.UserAgent();
  30. string cookie = form.Read<string>("cookie", string.Empty);
  31. var accountId = await TkPoolCore.UpdateCookies(cookie, user_agent);
  32. bool success = accountId > 0;
  33. if (success)
  34. {
  35. //string desc = ObjectComparer.PrintCompareToString(old, form).Trim();
  36. OperationLogCore.LogOperation(token.AccessKey, clientIp, $"tk_pool:{accountId}:cookie", string.Empty, cookie);
  37. }
  38. return new APIResult(new
  39. {
  40. data = new { success, msg = success ? "更新成功" : "更新失败,请检查输入的cookie" },
  41. });
  42. }
  43. [HttpPost]
  44. public async Task<ActionResult> update([FromBody] JsonElement form)
  45. {
  46. var clientIp = _accessor.HttpContext.GetUserIp();
  47. var token = provider.Get(_accessor.HttpContext);
  48. int id = form.Read<int>("id", 0);
  49. string name = form.Read<string>("name", string.Empty);
  50. string val = form.Read<string>("val", string.Empty);
  51. if (id == 0)
  52. {
  53. return new APIResult(new { data = new { success = false, msg = "更新失败,请检查输入的cookie" } });
  54. }
  55. int result;
  56. switch (name)
  57. {
  58. case "enable_fake_click":
  59. case "enable_order_summary_cache":
  60. case "enable_parse":
  61. case "enable_coupon":
  62. case "enable_sync_order":
  63. case "enable_promotionQuery":
  64. case "enable_deep_url":
  65. case "enable_general_link_parse_pool":
  66. case "use_general_link_parse_pool":
  67. case "status":
  68. bool bVal = val.Equals("True");
  69. result = new DBContext.Table("tk_pool")
  70. .Add(name, bVal)
  71. .Add("last_time", DateTime.Now)
  72. .Where("id=@id", new { id })
  73. .Update();
  74. break;
  75. case "check_status":
  76. //检查状态
  77. var arr = EndPointCore.NotifyCheckDeepUrl(id);
  78. string suspended_endpoint = string.Empty;
  79. var log = new LoggerLibrary("check_suspended_endpoint");
  80. foreach ((string node, string message) in arr)
  81. {
  82. log.Info(node, message);
  83. if (message.Contains("霸下验证码"))
  84. {
  85. suspended_endpoint += $"{node},";
  86. }
  87. }
  88. result = new DBContext.Table("tk_pool")
  89. .Add("suspended_endpoint", suspended_endpoint)
  90. .Add("last_time", DateTime.Now)
  91. .Where("id=@id", new { id })
  92. .Update();
  93. log.SaveAsync();
  94. break;
  95. case "time_range":
  96. case "qps_limit":
  97. case "cis_limit":
  98. int.TryParse(val, out int iVal);
  99. if (("qps_limit".Equals(name) || "cis_limit".Equals(name)) && iVal < 0) iVal = 0;
  100. result = new DBContext.Table("tk_pool")
  101. .Add(name, iVal)
  102. .Add("last_time", DateTime.Now)
  103. .Where("id=@id", new { id })
  104. .Update();
  105. break;
  106. default:
  107. return new APIResult(new { data = new { success = false, msg = "更新失败,未授权操作" } });
  108. }
  109. bool success = result > 0;
  110. if (success)
  111. {
  112. //string desc = ObjectComparer.PrintCompareToString(old, form).Trim();
  113. OperationLogCore.LogOperation(token.AccessKey, clientIp, $"tk_pool:{id}:{name}", string.Empty, val);
  114. await EndPointCore.NotifyReload(true);
  115. }
  116. return new APIResult(new
  117. {
  118. data = new { success, msg = success ? "更新成功" : "更新失败,请检查输入信息" },
  119. });
  120. }
  121. /// <summary>
  122. /// 账号列表
  123. /// </summary>
  124. /// <param name="form"></param>
  125. /// <returns></returns>
  126. [HttpPost]
  127. public async Task<ActionResult> list([FromBody] JsonElement form)
  128. {
  129. var token = provider.Get(_accessor.HttpContext);
  130. int page = form.Read("current", 1);
  131. int size = form.Read("pageSize", 10);
  132. string keyword = form.Read("name", string.Empty);
  133. bool getTotal = form.Read("getTotal", true);
  134. string _status = form.Read("status", string.Empty);
  135. int status = _status switch
  136. {
  137. "online" => 1,
  138. "offline" => 0,
  139. _ => -1,
  140. };
  141. var lastTime = form.PathReadArray<string>("lastTime[]");
  142. string sort = form.Read<string>("sort");
  143. string order = form.Read<string>("order");
  144. bool show_hide = form.Read("show_hide", false);
  145. string filter = string.Empty;
  146. if (!show_hide) filter = "is_hide=0";
  147. if (!string.IsNullOrEmpty(keyword))
  148. {
  149. filter += $" AND (`name` LIKE @keyword OR `description` LIKE @keyword)";
  150. keyword = $"%{keyword}%";
  151. }
  152. DateTime stime = DateTime.MinValue, etime = DateTime.MinValue;
  153. if (lastTime.Count == 2)
  154. {
  155. if (DateTime.TryParse(lastTime[0], out stime) && DateTime.TryParse(lastTime[1], out etime))
  156. {
  157. etime = etime.AddDays(1).AddSeconds(-1);
  158. filter += $" AND last_time BETWEEN @stime AND @etime";
  159. }
  160. }
  161. if (status != -1)
  162. {
  163. filter += $" AND status=@status";
  164. }
  165. filter = filter.StringTrimStart(" AND ");
  166. //排序
  167. string orderBy = "id DESC";
  168. if (!string.IsNullOrEmpty(order))
  169. {
  170. order = "descending".Equals(order) ? "DESC" : "ASC";
  171. orderBy = sort switch
  172. {
  173. //"num" => $"num {order}",
  174. _ => $"{sort} {order},ID DESC",
  175. };
  176. }
  177. using var conn = DBContext.GetOpenConnection();
  178. var result = new DBContext.Table(conn, "tk_pool")
  179. .Where(filter, new { keyword, status, stime, etime })
  180. .Page(size, page)
  181. .Order(orderBy)
  182. .PageList<TkPoolDTO>(getTotal);
  183. var proxyNodes = (ProxyNodesCore.AllList() ?? Array.Empty<ProxyNodesDTO>())
  184. .ToList();
  185. var aiOpenAccounts = result.List
  186. .Where(AiOpenRiskControlCore.IsApplicableAccount)
  187. .ToList();
  188. var aiOpenRiskEvents = await AiOpenRiskControlCore.GetTodayEventsAsync(
  189. aiOpenAccounts.Select(account => account.id));
  190. foreach (var item in result.List)
  191. {
  192. item.current_amt = Math.Round(RiskControlCore.GetIncomeAmt(TkChannelEnum.tb, $"{item.id}"), 2);
  193. item.cookies = string.Empty;
  194. //await RiskControlCore.SetRiskCookie($"tb:{item.id}", "TEST");
  195. item.riskCookie = RiskControlCore.GetRiskCookie($"tb:{item.id}");
  196. item.proxyStatus = proxyNodes
  197. .FirstOrDefault(proxyNode =>
  198. ProxyNodesCore.IsMatchNode(proxyNode, item.nodeName))
  199. ?.status;
  200. if (AiOpenRiskControlCore.IsApplicableAccount(item))
  201. {
  202. item.aiopen_risk = new AiOpenRiskStatusDTO
  203. {
  204. applicable = true
  205. };
  206. if (aiOpenRiskEvents.TryGetValue(item.id, out var riskEvent))
  207. {
  208. item.aiopen_risk.triggered = true;
  209. item.aiopen_risk.reason_code = riskEvent.reason_code;
  210. item.aiopen_risk.reason = riskEvent.reason;
  211. item.aiopen_risk.first_trigger_time = riskEvent.first_trigger_time;
  212. item.aiopen_risk.request_count_at_trigger = riskEvent.request_count_at_trigger;
  213. item.aiopen_risk.success_count_at_trigger = riskEvent.success_count_at_trigger;
  214. item.aiopen_risk.release_time = riskEvent.release_time;
  215. }
  216. }
  217. }
  218. return new APIResult(new { data = result });
  219. }
  220. [HttpPost]
  221. public async Task<ActionResult> report_dailys([FromBody] JsonElement form)
  222. {
  223. int page = form.Read("current", 1);
  224. int size = form.Read("pageSize", 10);
  225. bool getTotal = form.Read("getTotal", true);
  226. string sort = form.Read<string>("sort");
  227. string order = form.Read<string>("order");
  228. var report_date = form.PathReadArray<string>("query_date[]");
  229. string dailys_accountName = "all";
  230. int dailys_accountId = 0;
  231. string filter = string.Empty;
  232. DateTime stime = DateTime.MinValue, etime = DateTime.MinValue;
  233. if (report_date.Count == 2)
  234. {
  235. if (DateTime.TryParse(report_date[0], out stime) && DateTime.TryParse(report_date[1], out etime))
  236. {
  237. etime = etime.AddDays(1).AddSeconds(-1);
  238. filter += $" AND A.report_date BETWEEN @stime AND @etime";
  239. }
  240. }
  241. filter = filter.StringTrimStart(" AND ");
  242. //排序
  243. string orderBy = "A.report_date DESC";
  244. if (!string.IsNullOrEmpty(order))
  245. {
  246. order = "descending".Equals(order) ? "DESC" : "ASC";
  247. orderBy = sort switch
  248. {
  249. _ => $"A.{sort} {order}",
  250. };
  251. }
  252. var result = new DBContext.Table("v_tk_report_dailys")
  253. .LeftJoin("daily_logs",
  254. "B.log_date = A.report_date AND B.channel=0 AND B.accountId=@dailys_accountId",
  255. "total_count, B.abandon_count, B.success_count, B.abandon_percentage, B.success_percentage," +
  256. "B.parse_total_count, B.parse_abandon_count, B.parse_success_count, B.parse_abandon_percentage, B.parse_success_percentage," +
  257. "B.coupon_total_count, B.coupon_abandon_count, B.coupon_success_count, B.coupon_abandon_percentage, B.coupon_success_percentage," +
  258. "B.tool_total_count, B.tool_abandon_count, B.tool_success_count, B.tool_abandon_percentage, B.tool_success_percentage")
  259. .Where(filter, new { dailys_accountId, dailys_accountName, stime, etime })
  260. .Page(size, page)
  261. .Order(orderBy)
  262. .PageList<TkReportDTO>(getTotal);
  263. foreach (var item in result.List)
  264. {
  265. if (item.report_date.Date < DateTime.Now.Date) continue;
  266. if (item.total_count == 0)
  267. {
  268. item.total_count = await TkLogCore.GetTotalAsync($":total:tb:{item.report_date:yyyyMMdd}");
  269. if (item.total_count > 0)
  270. {
  271. item.success_count = await TkLogCore.GetTotalAsync($":total:tb:success:{item.report_date:yyyyMMdd}");
  272. item.abandon_count = await TkLogCore.GetTotalAsync($":total:tb:放弃转链:{item.report_date:yyyyMMdd}");
  273. if (item.total_count > 0)
  274. {
  275. item.success_percentage = $"{item.success_count / (double)item.total_count * 100:f2}%";
  276. item.abandon_percentage = $"{item.abandon_count / (double)item.total_count * 100:f2}%";
  277. }
  278. }
  279. }
  280. if (item.parse_total_count == 0)
  281. {
  282. item.parse_total_count = await TkLogCore.GetTotalAsync($":parse_total:tb:{item.report_date:yyyyMMdd}");
  283. if (item.parse_total_count > 0)
  284. {
  285. item.parse_success_count = await TkLogCore.GetTotalAsync($":parse_total:tb:success:{item.report_date:yyyyMMdd}");
  286. item.parse_abandon_count = await TkLogCore.GetTotalAsync($":parse_total:tb:放弃转链:{item.report_date:yyyyMMdd}");
  287. if (item.parse_total_count > 0)
  288. {
  289. item.parse_success_percentage = $"{item.parse_success_count / (double)item.parse_total_count * 100:f2}%";
  290. item.parse_abandon_percentage = $"{item.parse_abandon_count / (double)item.parse_total_count * 100:f2}%";
  291. }
  292. }
  293. }
  294. if (item.coupon_total_count == 0)
  295. {
  296. item.coupon_total_count = await TkLogCore.GetTotalAsync($":coupon_total:tb:{item.report_date:yyyyMMdd}", false);
  297. if (item.coupon_total_count > 0)
  298. {
  299. item.coupon_success_count = await TkLogCore.GetTotalAsync($":coupon_total:tb:success:{item.report_date:yyyyMMdd}", false);
  300. item.coupon_abandon_count = await TkLogCore.GetTotalAsync($":coupon_total:tb:放弃转链:{item.report_date:yyyyMMdd}", false);
  301. if (item.coupon_total_count > 0)
  302. {
  303. item.coupon_success_percentage = $"{item.coupon_success_count / (double)item.coupon_total_count * 100:f2}%";
  304. item.coupon_abandon_percentage = $"{item.coupon_abandon_count / (double)item.coupon_total_count * 100:f2}%";
  305. }
  306. }
  307. }
  308. if (item.tool_total_count == 0)
  309. {
  310. item.tool_total_count = await TkLogCore.GetTotalAsync($":parse_total:tool:{item.report_date:yyyyMMdd}");
  311. if (item.tool_total_count > 0)
  312. {
  313. item.tool_success_count = await TkLogCore.GetTotalAsync($":parse_total:tool:success:{item.report_date:yyyyMMdd}");
  314. item.tool_abandon_count = await TkLogCore.GetTotalAsync($":parse_total:tool:放弃转链:{item.report_date:yyyyMMdd}");
  315. if (item.tool_total_count > 0)
  316. {
  317. item.tool_success_percentage = $"{item.tool_success_count / (double)item.tool_total_count * 100:f2}%";
  318. item.tool_abandon_percentage = $"{item.tool_abandon_count / (double)item.tool_total_count * 100:f2}%";
  319. }
  320. }
  321. }
  322. }
  323. return new APIResult(new
  324. {
  325. data = result
  326. });
  327. }
  328. [HttpPost]
  329. public async Task<ActionResult> report_hourlys([FromBody] JsonElement form)
  330. {
  331. int page = form.Read("current", 1);
  332. int size = form.Read("pageSize", 10);
  333. bool getTotal = form.Read("getTotal", true);
  334. string sort = form.Read<string>("sort");
  335. string order = form.Read<string>("order");
  336. var report_date = form.PathReadArray<string>("query_date[]");
  337. var filterHours = form.Read<int?>("filterHours", null);
  338. string dailys_accountName = "all";
  339. int dailys_accountId = 0;
  340. string filter = string.Empty;
  341. DateTime stime = DateTime.MinValue, etime = DateTime.MinValue;
  342. if (report_date.Count == 2)
  343. {
  344. if (DateTime.TryParse(report_date[0], out stime) && DateTime.TryParse(report_date[1], out etime))
  345. {
  346. etime = etime.AddDays(1).AddSeconds(-1);
  347. filter += $" AND A.report_date BETWEEN @stime AND @etime";
  348. }
  349. }
  350. if (filterHours != null)
  351. {
  352. filterHours--;
  353. filter += $" AND HOUR(report_date) = @filterHours";
  354. }
  355. filter = filter.StringTrimStart(" AND ");
  356. //排序
  357. string orderBy = "A.report_date DESC";
  358. if (!string.IsNullOrEmpty(order))
  359. {
  360. order = "descending".Equals(order) ? "DESC" : "ASC";
  361. orderBy = sort switch
  362. {
  363. _ => $"A.{sort} {order}",
  364. };
  365. }
  366. var result = new DBContext.Table("v_tk_report_hourlys")
  367. .LeftJoin("daily_logs",
  368. "B.log_date = A.report_date AND B.channel=0 AND B.accountId=@dailys_accountId",
  369. "total_count, B.abandon_count, B.success_count, B.abandon_percentage, B.success_percentage," +
  370. "B.parse_total_count, B.parse_abandon_count, B.parse_success_count, B.parse_abandon_percentage, B.parse_success_percentage," +
  371. "B.coupon_total_count, B.coupon_abandon_count, B.coupon_success_count, B.coupon_abandon_percentage, B.coupon_success_percentage," +
  372. "B.tool_total_count, B.tool_abandon_count, B.tool_success_count, B.tool_abandon_percentage, B.tool_success_percentage")
  373. .Where(filter, new { dailys_accountId, dailys_accountName, filterHours, stime, etime })
  374. .Page(size, page)
  375. .Order(orderBy)
  376. .PageList<TkReportDTO>(getTotal);
  377. foreach (var item in result.List)
  378. {
  379. if (item.total_count == 0)
  380. {
  381. item.total_count = await TkLogCore.GetTotalAsync($":total:tb:{item.report_date:yyyyMMddHH}");
  382. if (item.total_count > 0)
  383. {
  384. item.success_count = await TkLogCore.GetTotalAsync($":total:tb:success:{item.report_date:yyyyMMddHH}");
  385. item.abandon_count = await TkLogCore.GetTotalAsync($":total:tb:放弃转链:{item.report_date:yyyyMMddHH}");
  386. if (item.total_count > 0)
  387. {
  388. item.success_percentage = $"{item.success_count / (double)item.total_count * 100:f2}%";
  389. item.abandon_percentage = $"{item.abandon_count / (double)item.total_count * 100:f2}%";
  390. }
  391. }
  392. }
  393. if (item.parse_total_count == 0)
  394. {
  395. item.parse_total_count = await TkLogCore.GetTotalAsync($":parse_total:tb:{item.report_date:yyyyMMddHH}");
  396. if (item.parse_total_count > 0)
  397. {
  398. item.parse_success_count = await TkLogCore.GetTotalAsync($":parse_total:tb:success:{item.report_date:yyyyMMddHH}");
  399. item.parse_abandon_count = await TkLogCore.GetTotalAsync($":parse_total:tb:放弃转链:{item.report_date:yyyyMMddHH}");
  400. if (item.parse_total_count > 0)
  401. {
  402. item.parse_success_percentage = $"{item.parse_success_count / (double)item.parse_total_count * 100:f2}%";
  403. item.parse_abandon_percentage = $"{item.parse_abandon_count / (double)item.parse_total_count * 100:f2}%";
  404. }
  405. }
  406. }
  407. if (item.coupon_total_count == 0)
  408. {
  409. item.coupon_total_count = await TkLogCore.GetTotalAsync($":coupon_total:tb:{item.report_date:yyyyMMddHH}", false);
  410. if (item.coupon_total_count > 0)
  411. {
  412. item.coupon_success_count = await TkLogCore.GetTotalAsync($":coupon_total:tb:success:{item.report_date:yyyyMMddHH}", false);
  413. item.coupon_abandon_count = await TkLogCore.GetTotalAsync($":coupon_total:tb:放弃转链:{item.report_date:yyyyMMddHH}", false);
  414. if (item.coupon_total_count > 0)
  415. {
  416. item.coupon_success_percentage = $"{item.coupon_success_count / (double)item.coupon_total_count * 100:f2}%";
  417. item.coupon_abandon_percentage = $"{item.coupon_abandon_count / (double)item.coupon_total_count * 100:f2}%";
  418. }
  419. }
  420. }
  421. if (item.tool_total_count == 0)
  422. {
  423. item.tool_total_count = await TkLogCore.GetTotalAsync($":parse_total:tool:{item.report_date:yyyyMMddHH}");
  424. if (item.tool_total_count > 0)
  425. {
  426. item.tool_success_count = await TkLogCore.GetTotalAsync($":parse_total:tool:success:{item.report_date:yyyyMMddHH}");
  427. item.tool_abandon_count = await TkLogCore.GetTotalAsync($":parse_total:tool:放弃转链:{item.report_date:yyyyMMddHH}");
  428. if (item.tool_total_count > 0)
  429. {
  430. item.tool_success_percentage = $"{item.tool_success_count / (double)item.tool_total_count * 100:f2}%";
  431. item.tool_abandon_percentage = $"{item.tool_abandon_count / (double)item.tool_total_count * 100:f2}%";
  432. }
  433. }
  434. }
  435. }
  436. return new APIResult(new
  437. {
  438. data = result
  439. });
  440. }
  441. [HttpPost]
  442. public async Task<ActionResult> report_list([FromBody] JsonElement form)
  443. {
  444. int page = form.Read("current", 1);
  445. int size = form.Read("pageSize", 10);
  446. bool getTotal = form.Read("getTotal", true);
  447. string sort = form.Read<string>("sort");
  448. string order = form.Read<string>("order");
  449. var report_date = form.PathReadArray<string>("query_date[]");
  450. string accountName = form.Read<string>("accountName");
  451. string filter = string.Empty;
  452. if (!string.IsNullOrEmpty(accountName))
  453. {
  454. filter += $" AND accountName=@accountName";
  455. }
  456. DateTime stime = DateTime.MinValue, etime = DateTime.MinValue;
  457. if (report_date.Count == 2)
  458. {
  459. if (DateTime.TryParse(report_date[0], out stime) && DateTime.TryParse(report_date[1], out etime))
  460. {
  461. etime = etime.AddDays(1).AddSeconds(-1);
  462. filter += $" AND report_date BETWEEN @stime AND @etime";
  463. }
  464. }
  465. filter = filter.StringTrimStart(" AND ");
  466. //排序
  467. string orderBy = "id DESC";
  468. if (!string.IsNullOrEmpty(order))
  469. {
  470. order = "descending".Equals(order) ? "DESC" : "ASC";
  471. orderBy = sort switch
  472. {
  473. _ => $"{sort} {order}",
  474. };
  475. }
  476. var result = new DBContext.Table("tk_report")
  477. .Where(filter, new { accountName, stime, etime })
  478. .Page(size, page)
  479. .Order(orderBy)
  480. .PageList<TkReportDTO>(getTotal);
  481. var tb_accounts = await TkPoolCore.AllListAsync();
  482. var tb_hide_ids = tb_accounts.Where(e => e.is_hide).Select(e => e.id).ToList();
  483. result.List = result.List.Where(e => !tb_hide_ids.Contains(e.accountId));
  484. foreach (var item in result.List)
  485. {
  486. #if DEBUG
  487. #else
  488. if (item.report_date.Date < DateTime.Now.Date) continue;
  489. #endif
  490. //var tk = TkPoolCore.GetOne(item.accountId);
  491. //if (tk != null) item.accountName = tk.company;
  492. string redisAccountName = $"{TkChannelEnum.tb}_{item.accountId}";
  493. if (item.total_count == 0)
  494. {
  495. string totalAccountName = redisAccountName;
  496. item.total_count = await TkLogCore.GetTotalAsync($":total:{totalAccountName}:{item.report_date:yyyyMMdd}");
  497. if (item.total_count == 0 && !string.Equals(item.accountName, totalAccountName, StringComparison.Ordinal))
  498. {
  499. //todo 过度用, 0613 跑两天就可以删掉
  500. totalAccountName = item.accountName;
  501. item.total_count = await TkLogCore.GetTotalAsync($":total:{totalAccountName}:{item.report_date:yyyyMMdd}");
  502. }
  503. if (item.total_count > 0)
  504. {
  505. item.success_count = await TkLogCore.GetTotalAsync($":total:{totalAccountName}:success:{item.report_date:yyyyMMdd}");
  506. item.abandon_count = await TkLogCore.GetTotalAsync($":total:{totalAccountName}:放弃转链:{item.report_date:yyyyMMdd}");
  507. if (item.total_count > 0)
  508. {
  509. item.success_percentage = $"{item.success_count / (double)item.total_count * 100:f2}%";
  510. item.abandon_percentage = $"{item.abandon_count / (double)item.total_count * 100:f2}%";
  511. }
  512. }
  513. }
  514. string parseAccountName = redisAccountName;
  515. int parseTotalCount = await TkLogCore.GetTotalAsync($":parse_total:{parseAccountName}:{item.report_date:yyyyMMdd}");
  516. if (parseTotalCount == 0 && !string.Equals(item.accountName, parseAccountName, StringComparison.Ordinal))
  517. {
  518. parseAccountName = item.accountName;
  519. parseTotalCount = await TkLogCore.GetTotalAsync($":parse_total:{parseAccountName}:{item.report_date:yyyyMMdd}");
  520. }
  521. // Today's DB row may be an earlier snapshot. Prefer the live Redis values
  522. // whenever they exist instead of only filling an initially-zero total.
  523. if (parseTotalCount > 0)
  524. {
  525. item.parse_total_count = parseTotalCount;
  526. item.parse_success_count = await TkLogCore.GetTotalAsync($":parse_total:{parseAccountName}:success:{item.report_date:yyyyMMdd}");
  527. item.parse_abandon_count = await TkLogCore.GetTotalAsync($":parse_total:{parseAccountName}:放弃转链:{item.report_date:yyyyMMdd}");
  528. item.parse_success_percentage = $"{item.parse_success_count / (double)item.parse_total_count * 100:f2}%";
  529. item.parse_abandon_percentage = $"{item.parse_abandon_count / (double)item.parse_total_count * 100:f2}%";
  530. }
  531. if (item.coupon_total_count == 0)
  532. {
  533. item.coupon_total_count = await TkLogCore.GetTotalAsync($":coupon_total:{redisAccountName}:{item.report_date:yyyyMMdd}", false);
  534. if (item.coupon_total_count > 0)
  535. {
  536. item.coupon_success_count = await TkLogCore.GetTotalAsync($":coupon_total:{redisAccountName}:success:{item.report_date:yyyyMMdd}", false);
  537. item.coupon_abandon_count = await TkLogCore.GetTotalAsync($":coupon_total:{redisAccountName}:放弃转链:{item.report_date:yyyyMMdd}", false);
  538. if (item.coupon_total_count > 0)
  539. {
  540. item.coupon_success_percentage = $"{item.coupon_success_count / (double)item.coupon_total_count * 100:f2}%";
  541. item.coupon_abandon_percentage = $"{item.coupon_abandon_count / (double)item.coupon_total_count * 100:f2}%";
  542. }
  543. }
  544. }
  545. if (item.tool_total_count == 0)
  546. {
  547. item.tool_total_count = await TkLogCore.GetTotalAsync($":parse_total:tool:{item.report_date:yyyyMMdd}");
  548. if (item.tool_total_count > 0)
  549. {
  550. item.tool_success_count = await TkLogCore.GetTotalAsync($":parse_total:tool:success:{item.report_date:yyyyMMdd}");
  551. item.tool_abandon_count = await TkLogCore.GetTotalAsync($":parse_total:tool:放弃转链:{item.report_date:yyyyMMdd}");
  552. if (item.tool_total_count > 0)
  553. {
  554. item.tool_success_percentage = $"{item.tool_success_count / (double)item.tool_total_count * 100:f2}%";
  555. item.tool_abandon_percentage = $"{item.tool_abandon_count / (double)item.tool_total_count * 100:f2}%";
  556. }
  557. }
  558. }
  559. }
  560. return new APIResult(new { data = result });
  561. }
  562. [HttpPost]
  563. public async Task<ActionResult> report_hourtrend([FromBody] JsonElement form)
  564. {
  565. int page = form.Read("current", 1);
  566. int size = form.Read("pageSize", 10);
  567. bool getTotal = form.Read("getTotal", true);
  568. string sort = form.Read<string>("sort");
  569. string order = form.Read<string>("order");
  570. var filterHours = form.Read<int?>("filterHours", null);
  571. string accountName = form.Read<string>("accountName");
  572. var report_date = form.PathReadArray<string>("query_date[]");
  573. int accountId = form.Read("accountId", 0);
  574. string filter = string.Empty;
  575. if (!string.IsNullOrEmpty(accountName))
  576. {
  577. filter += $" AND accountName=@accountName";
  578. }
  579. if (accountId != 0)
  580. {
  581. filter += $" AND accountId=@accountId";
  582. }
  583. DateTime stime = DateTime.MinValue, etime = DateTime.MinValue;
  584. if (report_date.Count == 2)
  585. {
  586. if (DateTime.TryParse(report_date[0], out stime) && DateTime.TryParse(report_date[1], out etime))
  587. {
  588. etime = etime.AddDays(1).AddSeconds(-1);
  589. if (etime > DateTime.Now) etime = DateTime.Now;
  590. filter += $" AND report_date BETWEEN @stime AND @etime";
  591. }
  592. }
  593. if (filterHours != null)
  594. {
  595. filterHours--;
  596. filter += $" AND HOUR(report_date) = @filterHours";
  597. }
  598. filter = filter.StringTrimStart(" AND ");
  599. //排序
  600. string orderBy = "id ASC";
  601. if (!string.IsNullOrEmpty(order))
  602. {
  603. order = "descending".Equals(order) ? "DESC" : "ASC";
  604. orderBy = sort switch
  605. {
  606. _ => $"{sort} {order}",
  607. };
  608. }
  609. using var conn = DBContext.GetOpenConnection();
  610. var result = new DBContext.Table(conn, "tk_report_hourtrend")
  611. .Where(filter, new { accountId, stime, etime, accountName, filterHours })
  612. .Page(size, page)
  613. .Order(orderBy)
  614. .PageList<TkReportDTO>(getTotal);
  615. foreach (var item in result.List)
  616. {
  617. #if DEBUG
  618. #else
  619. if (item.report_date.Date < DateTime.Now.Date) continue;
  620. #endif
  621. accountName = $"{TkChannelEnum.tb}_{item.accountId}";
  622. if (item.total_count == 0)
  623. {
  624. item.total_count = await TkLogCore.GetTotalAsync($":total:{accountName}:{item.report_date:yyyyMMddHH}");
  625. if (item.total_count == 0)
  626. {
  627. //todo 过度用, 0613 跑两天就可以删掉
  628. accountName = item.accountName;
  629. item.total_count = await TkLogCore.GetTotalAsync($":total:{accountName}:{item.report_date:yyyyMMddHH}");
  630. }
  631. if (item.total_count == 0) continue;
  632. item.success_count = await TkLogCore.GetTotalAsync($":total:{item.accountName}:success:{item.report_date:yyyyMMddHH}");
  633. item.abandon_count = await TkLogCore.GetTotalAsync($":total:{item.accountName}:放弃转链:{item.report_date:yyyyMMddHH}");
  634. if (item.total_count > 0)
  635. {
  636. item.success_percentage = $"{item.success_count / (double)item.total_count * 100:f2}%";
  637. item.abandon_percentage = $"{item.abandon_count / (double)item.total_count * 100:f2}%";
  638. }
  639. }
  640. if (item.parse_total_count == 0)
  641. {
  642. item.parse_total_count = await TkLogCore.GetTotalAsync($":parse_total:{accountName}:{item.report_date:yyyyMMddHH}");
  643. if (item.parse_total_count > 0)
  644. {
  645. item.parse_success_count = await TkLogCore.GetTotalAsync($":parse_total:{item.accountName}:success:{item.report_date:yyyyMMddHH}");
  646. item.parse_abandon_count = await TkLogCore.GetTotalAsync($":parse_total:{item.accountName}:放弃转链:{item.report_date:yyyyMMddHH}");
  647. if (item.parse_total_count > 0)
  648. {
  649. item.parse_success_percentage = $"{item.parse_success_count / (double)item.parse_total_count * 100:f2}%";
  650. item.parse_abandon_percentage = $"{item.parse_abandon_count / (double)item.parse_total_count * 100:f2}%";
  651. }
  652. }
  653. }
  654. if (item.coupon_total_count == 0)
  655. {
  656. item.coupon_total_count = await TkLogCore.GetTotalAsync($":coupon_total:{accountName}:{item.report_date:yyyyMMddHH}", false);
  657. if (item.coupon_total_count > 0)
  658. {
  659. item.coupon_success_count = await TkLogCore.GetTotalAsync($":coupon_total:{item.accountName}:success:{item.report_date:yyyyMMddHH}", false);
  660. item.coupon_abandon_count = await TkLogCore.GetTotalAsync($":coupon_total:{item.accountName}:放弃转链:{item.report_date:yyyyMMddHH}", false);
  661. if (item.coupon_total_count > 0)
  662. {
  663. item.coupon_success_percentage = $"{item.coupon_success_count / (double)item.coupon_total_count * 100:f2}%";
  664. item.coupon_abandon_percentage = $"{item.coupon_abandon_count / (double)item.coupon_total_count * 100:f2}%";
  665. }
  666. }
  667. }
  668. if (item.tool_total_count == 0)
  669. {
  670. item.tool_total_count = await TkLogCore.GetTotalAsync($":tool_total:{accountName}:{item.report_date:yyyyMMddHH}");
  671. if (item.tool_total_count > 0)
  672. {
  673. item.tool_success_count = await TkLogCore.GetTotalAsync($":tool_total:{item.accountName}:success:{item.report_date:yyyyMMddHH}");
  674. item.tool_abandon_count = await TkLogCore.GetTotalAsync($":tool_total:{item.accountName}:放弃转链:{item.report_date:yyyyMMddHH}");
  675. if (item.tool_total_count > 0)
  676. {
  677. item.tool_success_percentage = $"{item.tool_success_count / (double)item.tool_total_count * 100:f2}%";
  678. item.tool_abandon_percentage = $"{item.tool_abandon_count / (double)item.tool_total_count * 100:f2}%";
  679. }
  680. }
  681. }
  682. }
  683. return new APIResult(new { data = result });
  684. }
  685. [HttpPost]
  686. public async Task<ActionResult> chartData([FromBody] JsonElement form)
  687. {
  688. var result = new List<dynamic>();
  689. var reason_result = new List<dynamic>();
  690. var report_date = form.PathReadArray<string>("query_date[]");
  691. var accountName = form.Read("accountName", string.Empty);
  692. var accountId = form.Read("accountId", 0);
  693. var isHourtrend = form.Read<bool>("isLeaf", false);
  694. var total_key = form.Read("total_key", "total");
  695. DateTime stime = DateTime.MinValue;
  696. if (!DateTime.TryParse(report_date[0], out stime)) return new APIResult(new { data = result, data2 = reason_result });
  697. string _report_date = stime.ToString("yyyyMMdd");
  698. if (isHourtrend) _report_date = stime.ToString("yyyyMMddHH");
  699. if (string.IsNullOrEmpty(accountName)) accountName = "tb";
  700. if (total_key == "tool_total")
  701. {
  702. accountName = "tool";
  703. total_key = "parse_total";
  704. string cacheKey = $":{total_key}:{accountName}:{_report_date}";
  705. double total = await TkLogCore.GetTotalAsync(cacheKey);
  706. if (total > 0)
  707. {
  708. string[] keys = ["bdpan", "wemeet"];
  709. foreach (var keyname in keys)
  710. {
  711. // string[] keys = ["bdpan:success", "bdpan:fail", "wemeet:success", "wemeet:fail"];
  712. cacheKey = $":{total_key}:{keyname}:{_report_date}";
  713. total = await TkLogCore.GetTotalAsync(cacheKey);
  714. cacheKey = $":{total_key}:{keyname}:success:{_report_date}";
  715. int value = await TkLogCore.GetTotalAsync(cacheKey);
  716. if (value == 0) continue;
  717. result.Add(new { name = $"{keyname}-成功", value, increases = Math.Round(value / total * 100, 2) });
  718. cacheKey = $":{total_key}:{keyname}:fail:{_report_date}";
  719. value = await TkLogCore.GetTotalAsync(cacheKey);
  720. if (value == 0) continue;
  721. result.Add(new { name = $"{keyname}-失败", value, increases = Math.Round(value / total * 100, 2) });
  722. }
  723. cacheKey = $":{total_key}:{accountName}:reason:{_report_date}";
  724. string[] reason_keys = await TkLogCore.GetTotalKeysAsync(cacheKey);
  725. foreach (var keyname in reason_keys)
  726. {
  727. cacheKey = $":{total_key}:{accountName}:{keyname}:{_report_date}";
  728. int value = await TkLogCore.GetTotalAsync(cacheKey);
  729. if (value == 0) continue;
  730. reason_result.Add(new { name = keyname, value, increases = Math.Round(value / total * 100, 2) });
  731. }
  732. reason_result = reason_result.OrderByDescending(item => item.value).ToList();
  733. }
  734. return new APIResult(new { total, data = result, data2 = reason_result });
  735. }
  736. else
  737. {
  738. // The report row is identified by tk_pool.id. This is independent of the
  739. // riskStrategy/launchScene label (for example tbpush-220), which can be shared
  740. // by multiple accounts.
  741. string requestedAccountName = accountName;
  742. if (accountId > 0)
  743. {
  744. accountName = $"{TkChannelEnum.tb}_{accountId}";
  745. }
  746. string cacheKey = $":{total_key}:{accountName}:{_report_date}";
  747. double total = await TkLogCore.GetTotalAsync(cacheKey, false);
  748. if (total == 0 &&
  749. accountId > 0 &&
  750. !string.IsNullOrEmpty(requestedAccountName) &&
  751. !string.Equals(requestedAccountName, "all", StringComparison.OrdinalIgnoreCase) &&
  752. !string.Equals(requestedAccountName, TkChannelEnum.tb.ToString(), StringComparison.OrdinalIgnoreCase) &&
  753. !string.Equals(requestedAccountName, accountName, StringComparison.Ordinal))
  754. {
  755. cacheKey = $":{total_key}:{requestedAccountName}:{_report_date}";
  756. total = await TkLogCore.GetTotalAsync(cacheKey, false);
  757. if (total > 0)
  758. {
  759. accountName = requestedAccountName;
  760. }
  761. }
  762. if (total > 0)
  763. {
  764. string[] keys = ["success"];
  765. cacheKey = $":{total_key}:{accountName}:message:{_report_date}";
  766. string[] message_keys = await TkLogCore.GetTotalKeysAsync(cacheKey, false);
  767. var combinedKeys = keys.Union(message_keys).ToList();
  768. combinedKeys.RemoveAll(item => item == "fail");
  769. combinedKeys.RemoveAll(item => item == "OK");
  770. foreach (var keyname in combinedKeys)
  771. {
  772. cacheKey = $":{total_key}:{accountName}:{keyname}:{_report_date}";
  773. int value = await TkLogCore.GetTotalAsync(cacheKey, false);
  774. if (value == 0) continue;
  775. result.Add(new { name = keyname, value, increases = Math.Round(value / total * 100, 2) });
  776. }
  777. result = result.OrderByDescending(item => item.value).ToList();
  778. cacheKey = $":{total_key}:{accountName}:reason:{_report_date}";
  779. string[] reason_keys = await TkLogCore.GetTotalKeysAsync(cacheKey, false);
  780. foreach (var keyname in reason_keys)
  781. {
  782. if ("没有优惠券".Equals(keyname)) continue;
  783. cacheKey = $":{total_key}:{accountName}:{keyname}:{_report_date}";
  784. int value = await TkLogCore.GetTotalAsync(cacheKey, false);
  785. if (value < 50) continue;
  786. reason_result.Add(new { name = keyname, value, increases = Math.Round(value / total * 100, 2) });
  787. }
  788. reason_result = reason_result.OrderByDescending(item => item.value).ToList();
  789. }
  790. return new APIResult(new { total, data = result, data2 = reason_result });
  791. }
  792. }
  793. [HttpPost]
  794. public async Task<ActionResult> chartData2([FromBody] JsonElement form)
  795. {
  796. var result = new List<dynamic>();
  797. var reason_result = new List<dynamic>();
  798. var report_date = form.PathReadArray<string>("query_date[]");
  799. var accountName = form.Read("accountName", string.Empty);
  800. var isHourtrend = form.Read<bool>("isLeaf", false);
  801. var total_key = form.Read("total_key", "total");
  802. if (string.IsNullOrEmpty(accountName)) accountName = "tb";
  803. DateTime stime = DateTime.MinValue;
  804. if (!DateTime.TryParse(report_date[0], out stime)) return new APIResult(new { data = result, data2 = reason_result });
  805. string _report_date = stime.ToString("yyyyMMdd");
  806. if (isHourtrend) _report_date = stime.ToString("yyyyMMddHH");
  807. string cacheKey = $":{total_key}:{accountName}:{_report_date}";
  808. double total = await TkLogCore.GetTotalAsync(cacheKey);
  809. if (total > 0)
  810. {
  811. string[] keys = ["success"];
  812. cacheKey = $":{total_key}:{accountName}:message:{_report_date}";
  813. string[] message_keys = await TkLogCore.GetTotalKeysAsync(cacheKey);
  814. var combinedKeys = keys.Union(message_keys).ToList();
  815. combinedKeys.RemoveAll(item => item == "fail");
  816. combinedKeys.RemoveAll(item => item == "OK");
  817. foreach (var keyname in combinedKeys)
  818. {
  819. cacheKey = $":{total_key}:{accountName}:{keyname}:{_report_date}";
  820. int value = await TkLogCore.GetTotalAsync(cacheKey);
  821. if (value == 0) continue;
  822. result.Add(new { name = keyname, value, increases = Math.Round(value / total * 100, 2) });
  823. }
  824. result = result.OrderByDescending(item => item.value).ToList();
  825. cacheKey = $":{total_key}:{accountName}:reason:{_report_date}";
  826. string[] reason_keys = await TkLogCore.GetTotalKeysAsync(cacheKey);
  827. foreach (var keyname in reason_keys)
  828. {
  829. if ("没有优惠券".Equals(keyname)) continue;
  830. cacheKey = $":{total_key}:{accountName}:{keyname}:{_report_date}";
  831. int value = await TkLogCore.GetTotalAsync(cacheKey);
  832. if (value == 0) continue;
  833. reason_result.Add(new { name = keyname, value, increases = Math.Round(value / total * 100, 2) });
  834. }
  835. reason_result = reason_result.OrderByDescending(item => item.value).ToList();
  836. }
  837. return new APIResult(new { total, data = result, data2 = reason_result });
  838. }
  839. [HttpPost]
  840. public ActionResult settle_bills_total([FromBody] JsonElement form)
  841. {
  842. int page = form.Read("current", 1);
  843. int size = form.Read("pageSize", 10);
  844. bool getTotal = form.Read("getTotal", true);
  845. string sort = form.Read<string>("sort");
  846. string order = form.Read<string>("order");
  847. var belongTime = form.PathReadArray<string>("query_date[]");
  848. string filter = string.Empty;
  849. DateTime stime = DateTime.MinValue, etime = DateTime.MinValue;
  850. if (belongTime.Count == 2)
  851. {
  852. if (DateTime.TryParse(belongTime[0], out stime) && DateTime.TryParse(belongTime[1], out etime))
  853. {
  854. etime = etime.AddDays(1).AddSeconds(-1);
  855. filter += $" AND belongTime BETWEEN @stime AND @etime";
  856. }
  857. }
  858. filter = filter.StringTrimStart(" AND ");
  859. //排序
  860. string orderBy = "belongTime DESC";
  861. if (!string.IsNullOrEmpty(order))
  862. {
  863. order = "descending".Equals(order) ? "DESC" : "ASC";
  864. orderBy = sort switch
  865. {
  866. _ => $"{sort} {order}",
  867. };
  868. }
  869. var result = new DBContext.Table("v_tk_report_bills")
  870. .Where(filter, new { stime, etime })
  871. .Page(size, page)
  872. .Order(orderBy)
  873. .PageList<TkSettleBillDTO>(getTotal);
  874. return new APIResult(new { data = result });
  875. }
  876. [HttpPost]
  877. public ActionResult settle_bills([FromBody] JsonElement form)
  878. {
  879. int page = form.Read("current", 1);
  880. int size = form.Read("pageSize", 10);
  881. bool getTotal = form.Read("getTotal", true);
  882. string sort = form.Read<string>("sort");
  883. string order = form.Read<string>("order");
  884. string name = form.Read<string>("keyword");
  885. var belongTime = form.PathReadArray<string>("query_date[]");
  886. string filter = string.Empty;
  887. if (!string.IsNullOrEmpty(name))
  888. {
  889. filter += $" AND accountId IN (SELECT ID FROM tk_pool WHERE company=@name)";
  890. }
  891. DateTime stime = DateTime.MinValue, etime = DateTime.MinValue;
  892. if (belongTime.Count == 2)
  893. {
  894. if (DateTime.TryParse(belongTime[0], out stime) && DateTime.TryParse(belongTime[1], out etime))
  895. {
  896. etime = etime.AddDays(1).AddSeconds(-1);
  897. filter += $" AND belongTime BETWEEN @stime AND @etime";
  898. }
  899. }
  900. filter = filter.StringTrimStart(" AND ");
  901. //排序
  902. string orderBy = "belongTime DESC";
  903. if (!string.IsNullOrEmpty(order))
  904. {
  905. order = "descending".Equals(order) ? "DESC" : "ASC";
  906. orderBy = sort switch
  907. {
  908. _ => $"{sort} {order}",
  909. };
  910. }
  911. var result = new DBContext.Table("tk_settle_bill")
  912. .Where(filter, new { name, stime, etime })
  913. .Page(size, page)
  914. .Order(orderBy)
  915. .PageList<TkSettleBillDTO>(getTotal);
  916. //foreach (var item in result.List)
  917. //{
  918. // if (string.IsNullOrEmpty(name))
  919. // {
  920. // item.accountName = "-";
  921. // }
  922. //}
  923. return new APIResult(new { data = result });
  924. }
  925. }
  926. }