TaobaoController.cs 50 KB

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