JackpotResults.cshtml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. @model LotteryWebApp.Models.HomeIndex_ViewModel
  2. @{
  3. ViewData["Title"] = "Millions - Kết quả Jackpot";
  4. Layout = "~/Areas/Millions/Views/Shared/_Layout.cshtml";
  5. }
  6. @using System
  7. @using System.Globalization
  8. @using LotteryWebApp.Languages;
  9. @using LotteryWebApp.Controllers;
  10. @using LotteryWebApp.Common;
  11. @section Styles {
  12. <link rel="preconnect" href="https://fonts.googleapis.com">
  13. <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  14. <link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@600;700;800&family=Bricolage+Grotesque:opsz,wght@12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&display=swap" rel="stylesheet">
  15. <link rel="stylesheet" href="/Millions/css/all.min.css"/>
  16. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr@4.6.13/dist/flatpickr.min.css"/>
  17. <link rel="stylesheet" href="/Millions/css/jackpot.css"/>
  18. <style>
  19. /* Mega Jackpot amount — spiral grow & shrink */
  20. .mega-jackpot-spiral {
  21. display: inline-block;
  22. transform-origin: center center;
  23. animation: megaJackpotSpiral 1.8s ease-in-out infinite;
  24. will-change: transform;
  25. }
  26. @@keyframes megaJackpotSpiral {
  27. 0% {
  28. transform: scale(0.25) rotate(0deg);
  29. }
  30. 30% {
  31. transform: scale(1.15) rotate(360deg);
  32. }
  33. 65% {
  34. transform: scale(1.15) rotate(360deg);
  35. }
  36. 100% {
  37. transform: scale(0.25) rotate(720deg);
  38. }
  39. }
  40. </style>
  41. }
  42. <div class="main-content h-dvh w-full max-w-[430px] mx-auto bg-[#0062ff] relative overflow-hidden font-bricolage">
  43. <!-- Header gradient -->
  44. <div class="header-bg absolute inset-x-0 top-0 h-[160px] flex items-start justify-between px-3 pt-4 z-0">
  45. <button onclick="location.href=subDomain + '@Url.Action("GameHome", "Home", new { area = "Millions" })';" class="js-back w-6 h-6 flex items-center justify-center">
  46. <img src="/Millions/assets/icons/arrow-left.svg" alt="Back" class="w-6 h-6"/>
  47. </button>
  48. <p class="text-white text-base font-bold">@Lang.millions_jackpot_results_title</p>
  49. <span class="w-6 h-6"></span>
  50. </div>
  51. <!-- White rounded body (overlaps header, scrollable) -->
  52. <div class="absolute inset-x-0 top-[56px] bottom-0 bg-white rounded-t-[40px] flex flex-col gap-3 px-3 pt-4 pb-[96px] overflow-y-auto hide-scrollbar z-10" style="box-shadow: 0 -4px 10px rgba(0, 0, 0, 0.1);">
  53. <!-- Date filter + search -->
  54. @{
  55. var fromFormatted = ViewBag.FromFormatted as string;
  56. var toFormatted = ViewBag.ToFormatted as string;
  57. var fromDisplay = DateTime.ParseExact(fromFormatted, "yyyy-MM-dd", CultureInfo.InvariantCulture).ToString("dd/MM/yyyy");
  58. var toDisplay = DateTime.ParseExact(toFormatted, "yyyy-MM-dd", CultureInfo.InvariantCulture).ToString("dd/MM/yyyy");
  59. }
  60. <form id="jackpotFilterForm" method="get" action="@Url.Action("JackpotResults", "Home", new { area = "Millions" })" class="flex items-center justify-between gap-3 shrink-0">
  61. <input type="hidden" name="termType" value="@Model.termType"/>
  62. <div class="relative flex-1">
  63. <button type="button" id="dateRangeToggle" class="date-range-toggle">
  64. <img src="/Millions/assets/icons/calendar.png" alt="" class="w-5 h-5"/>
  65. <span id="dateRangeLabel" class="text-xs font-bold text-black whitespace-nowrap">@fromDisplay - @toDisplay</span>
  66. <img src="/Millions/assets/icons/chevron-down-2.svg" alt="" class="w-3 h-3 ml-auto"/>
  67. </button>
  68. <input type="hidden" id="fromInput" name="fromFormatted" value="@fromFormatted"/>
  69. <input type="hidden" id="toInput" name="toFormatted" value="@toFormatted"/>
  70. <div id="dateRangePanel" class="date-range-panel">
  71. <input type="text" id="jackpotDateRange" class="date-range-picker-input" readonly/>
  72. </div>
  73. </div>
  74. <button type="submit" class="bg-[#0062ff] rounded-lg w-8 h-8 flex items-center justify-center shrink-0">
  75. <img src="/Millions/assets/icons/search.svg" alt="" class="w-4 h-4"/>
  76. </button>
  77. </form>
  78. <script src="https://cdn.jsdelivr.net/npm/flatpickr@4.6.13/dist/flatpickr.min.js"></script>
  79. <script>
  80. (function() {
  81. var toggle = document.getElementById('dateRangeToggle');
  82. var panel = document.getElementById('dateRangePanel');
  83. var fromInput = document.getElementById('fromInput');
  84. var toInput = document.getElementById('toInput');
  85. var pickerInput = document.getElementById('jackpotDateRange');
  86. var label = document.getElementById('dateRangeLabel');
  87. var picker = null;
  88. if (!toggle || !panel) return;
  89. function openPanel() {
  90. panel.classList.add('open');
  91. toggle.classList.add('open');
  92. if (picker) {
  93. picker.redraw();
  94. }
  95. }
  96. function closePanel() {
  97. panel.classList.remove('open');
  98. toggle.classList.remove('open');
  99. }
  100. function formatDateForDisplay(date) {
  101. return flatpickr.formatDate(date, "d/m/Y");
  102. }
  103. function formatDateForRequest(date) {
  104. return flatpickr.formatDate(date, "Y-m-d");
  105. }
  106. function getDateFromRequestValue(value) {
  107. return flatpickr.parseDate(value, "Y-m-d");
  108. }
  109. function setRangeText(fromDate, toDate) {
  110. if (label) {
  111. label.textContent = formatDateForDisplay(fromDate) + " - " + formatDateForDisplay(toDate);
  112. }
  113. }
  114. function syncRangeFields(selectedDates) {
  115. if (!selectedDates || selectedDates.length === 0) return;
  116. var fromDate = selectedDates[0];
  117. var toDate = selectedDates.length > 1 ? selectedDates[1] : selectedDates[0];
  118. fromInput.value = formatDateForRequest(fromDate);
  119. toInput.value = formatDateForRequest(toDate);
  120. setRangeText(fromDate, toDate);
  121. }
  122. toggle.addEventListener('click', function(e) {
  123. e.stopPropagation();
  124. if (panel.classList.contains('open')) {
  125. closePanel();
  126. } else {
  127. openPanel();
  128. }
  129. });
  130. panel.addEventListener('click', function(e) { e.stopPropagation(); });
  131. document.addEventListener('click', function(e) {
  132. if (!panel.contains(e.target) && !toggle.contains(e.target)) {
  133. closePanel();
  134. }
  135. });
  136. if (window.flatpickr) {
  137. var fromDate = getDateFromRequestValue(fromInput.value);
  138. var toDate = getDateFromRequestValue(toInput.value);
  139. setRangeText(fromDate, toDate);
  140. picker = flatpickr(pickerInput, {
  141. mode: "range",
  142. dateFormat: "Y-m-d",
  143. defaultDate: [fromDate, toDate],
  144. disableMobile: true,
  145. inline: true,
  146. appendTo: panel,
  147. monthSelectorType: "dropdown",
  148. onChange: function(selectedDates) {
  149. syncRangeFields(selectedDates);
  150. if (selectedDates.length === 2) {
  151. closePanel();
  152. }
  153. },
  154. onClose: function(selectedDates, dateStr, instance) {
  155. syncRangeFields(selectedDates);
  156. if (selectedDates.length === 1) {
  157. instance.setDate([selectedDates[0], selectedDates[0]], false);
  158. setRangeText(selectedDates[0], selectedDates[0]);
  159. }
  160. }
  161. });
  162. }
  163. })();
  164. </script>
  165. <!-- Mega Jackpot banner -->
  166. <div class="mega-banner relative rounded-[12px] overflow-hidden px-4 py-3 border-2 border-white/70 flex flex-col shrink-0">
  167. <span class="mega-glow" style="left:-79px; top:-101px;"></span>
  168. <span class="mega-glow" style="right:-78px; top:9px;"></span>
  169. <span class="mega-glow" style="right:-107px; top:20px;"></span>
  170. <p class="mega-title relative inline-block text-white text-[22px] font-futura leading-none">
  171. <img src="/Millions/assets/icons/crown.png" alt="" class="absolute -top-[5px] left-[26px] w-[12px] h-auto rotate-[10deg] pointer-events-none"/>
  172. @Lang.millions_mega_jackpot
  173. </p>
  174. <p class="text-white text-xs mt-2">@Lang.millions_estimate_jackpot_prize</p>
  175. <p class="leading-none mt-1 flex items-start" style="margin-bottom:18px;">
  176. <span class="mega-amount mega-jackpot-spiral text-[40px] font-condensed text-gold-gradient tracking-tight leading-none">@Utils.FormatMoney(Model.bolet ?? "30000000")</span>
  177. <span class="mega-jackpot-spiral text-gold-gradient text-sm font-bold uppercase ml-1">@Lang.v2_htg</span>
  178. </p>
  179. <p class="text-white text-[10px] mt-1">@Lang.millions_be_the_next_millionaire</p>
  180. <img src="/Millions/assets/images/crown-balls.png" alt="" class="absolute right-2 top-1/2 -translate-y-1/2 w-44 h-auto pointer-events-none"/>
  181. </div>
  182. <!-- List heading -->
  183. <div class="px-2 shrink-0">
  184. <div class="flex items-center justify-between font-bold">
  185. <p class="text-sm text-black">@Lang.millions_list_jackpot_results</p>
  186. <p class="text-xs text-[#0062ff]">@string.Format(Lang.millions_total_draws, Model.listTerm?.Count ?? 0)</p>
  187. </div>
  188. <!-- Results list -->
  189. <div class="flex flex-col gap-2 pb-2">
  190. @if (Model.listTerm != null && Model.listTerm.Count > 0)
  191. {
  192. foreach (var term in Model.listTerm)
  193. {
  194. var balls = !string.IsNullOrEmpty(term.result) ? term.result.Split(',') : new string[0];
  195. var mainBalls = new string[5];
  196. var mbBall = "0";
  197. for (int i = 0; i < 5; i++)
  198. {
  199. mainBalls[i] = i < balls.Length ? balls[i].Trim() : "0";
  200. }
  201. if (balls.Length >= 6)
  202. {
  203. mbBall = balls[5].Trim();
  204. }
  205. string dayOfWeek = "";
  206. string datePart = "";
  207. string timePart = "";
  208. DateTime drawDt;
  209. if (!string.IsNullOrEmpty(term.date_random) &&
  210. DateTime.TryParseExact(term.date_random, "dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out drawDt))
  211. {
  212. dayOfWeek = drawDt.ToString("dddd", new CultureInfo("en-US"));
  213. dayOfWeek = char.ToUpper(dayOfWeek[0]) + dayOfWeek.Substring(1);
  214. datePart = drawDt.ToString("dd/MM/yyyy");
  215. timePart = drawDt.ToString("HH:mm");
  216. }
  217. <a href="@Url.Action("JackpotDetail", "Home", new { area = "Millions", id = term.id, termType = Model.termType })" class="result-card bg-white rounded-xl flex items-center justify-between px-3 py-2 gap-2">
  218. <div class="flex flex-col gap-0.5 items-start shrink-0">
  219. <span class="bg-[#0062ff] text-white text-[10px] font-bold rounded px-1 py-0.5">@Lang.millions_draw_no_short@term.seq</span>
  220. <span class="text-xs text-[#8e8e93]">@dayOfWeek</span>
  221. <span class="text-[8px] font-bold text-[#8e8e93]">@datePart</span>
  222. <span class="text-[8px] font-bold text-[#8e8e93]">@timePart</span>
  223. </div>
  224. <div class="grid grid-cols-3 gap-1">
  225. @for (int i = 0; i < 5; i++)
  226. {
  227. <div class="ball ball-blue ball-mini">@mainBalls[i]</div>
  228. }
  229. <div class="relative">
  230. <img src="/Millions/assets/icons/crown.png" alt="" class="absolute -top-2.5 -right-1 w-4 h-auto rotate-[15deg] pointer-events-none z-0"/>
  231. <div class="ball ball-mb ball-mini relative z-10">@mbBall</div>
  232. <span class="absolute -bottom-1 -right-1 bg-[#ee0033] text-white text-[6px] font-bold px-1 rounded z-20">MB</span>
  233. </div>
  234. </div>
  235. <div class="flex flex-col gap-0.5 items-start shrink-0">
  236. <span class="text-xs font-bold text-black">@Lang.millions_jackpot</span>
  237. <p class="leading-none">
  238. <span class="text-base font-extrabold text-[#002bff]">@Utils.FormatMoney(term.bolet ?? term.money_winner ?? "0")</span><span class="text-[10.32px] font-extrabold text-black align-top">@Lang.v2_htg</span>
  239. </p>
  240. @if (!string.IsNullOrEmpty(term.split))
  241. {
  242. <span class="text-[8px] text-black">@string.Format(Lang.millions_subscribers_won, term.split)</span>
  243. }
  244. </div>
  245. <img src="/Millions/assets/icons/chevron-right.svg" alt="" class="w-2 h-3 shrink-0"/>
  246. </a>
  247. }
  248. }
  249. </div>
  250. <!-- Note -->
  251. <div class="flex items-center gap-2 bg-[#e6f0ff] rounded-lg px-3 py-2 mb-2 shrink-0">
  252. <svg class="w-4 h-4 shrink-0" viewBox="0 0 24 24" fill="#0062ff"><path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20Zm0 5a1.25 1.25 0 1 1 0 2.5A1.25 1.25 0 0 1 12 7Zm1 10h-2v-6h2v6Z"/></svg>
  253. <p class="text-[10px] font-bold text-[#0062ff]">@Lang.millions_note_results_updated</p>
  254. </div>
  255. </div>
  256. </div>
  257. @{
  258. ViewData["ActiveTab"] = "Home";
  259. }
  260. @await Html.PartialAsync("~/Areas/Millions/Views/Shared/_BottomNavbar.cshtml")
  261. </div>
  262. @section Scripts {
  263. <script src="/Millions/js/all.min.js"></script>
  264. }