index.html 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>S3 活动首页</title>
  7. <script src="https://cdn.tailwindcss.com"></script>
  8. <style>
  9. @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
  10. body { font-family: 'Roboto', sans-serif; }
  11. .content-bg {
  12. background: linear-gradient(180deg, #7aedff 0%, #047200 100%);
  13. min-height: 100vh;
  14. }
  15. .logo-bg {
  16. background-image: url('./static/logo/jbs.png');
  17. background-repeat: no-repeat;
  18. background-position: center;
  19. background-size: contain;
  20. }
  21. </style>
  22. </head>
  23. <body class="bg-gray-100">
  24. <div class="content-bg w-full flex flex-col relative">
  25. <!-- Top Bar -->
  26. <div class="w-full flex justify-end p-4 pt-8">
  27. <div class="flex items-center bg-black/30 rounded-xl px-3 py-1 gap-2 min-w-[90px] h-[40px]">
  28. <img src="https://img.icons8.com/ios-filled/50/ffffff/clock.png" class="w-5 h-5 object-contain">
  29. <div id="countdown" class="text-white text-lg font-bold text-center min-w-[60px]">--:--</div>
  30. </div>
  31. </div>
  32. <!-- Main Content -->
  33. <div class="flex-1 flex flex-col items-center justify-center gap-6 -mt-20">
  34. <!-- Logo -->
  35. <div class="w-[50vw] h-[50vw] logo-bg"></div>
  36. <!-- Type & Notice -->
  37. <div class="relative flex items-center justify-center w-full">
  38. <img id="notice-icon" src="./static/common/notice.png" class="absolute left-10 w-4 h-4 hidden" alt="notice">
  39. <span id="activity-type" class="text-white/60 text-xl font-bold">锦标赛</span>
  40. </div>
  41. <!-- Name -->
  42. <div id="activity-name" class="text-white text-2xl font-bold text-center px-4">正在加载...</div>
  43. <!-- Button -->
  44. <button id="action-btn" onclick="handleBtnClick()" class="bg-white text-black text-xl font-bold py-3 px-12 rounded-full shadow-lg active:scale-95 transition-transform mt-4">
  45. 开始比赛
  46. </button>
  47. </div>
  48. </div>
  49. <!-- Scripts -->
  50. <script src="./js/utils.js"></script>
  51. <script src="./js/bridge.js"></script>
  52. <script src="./js/api.js"></script>
  53. <script>
  54. const state = {
  55. ecId: 0,
  56. isJoin: false,
  57. isFinished: false,
  58. secondCardName: '',
  59. beginSecond: 0,
  60. endSecond: 0,
  61. timer: null,
  62. rankKey: ''
  63. };
  64. window.onload = function() {
  65. const token = Tools.getQueryParam('token');
  66. state.ecId = Tools.getQueryParam('id') || 0;
  67. state.ecId = 112;
  68. state.rankKey = `rank-tpl-style3-${state.ecId}`;
  69. if (window.API) {
  70. API.setToken(token);
  71. if (Tools.getQueryParam('env') === 'mock') {
  72. API.init({ useMock: true });
  73. if (!state.ecId) state.ecId = 'mock_id';
  74. }
  75. }
  76. const typeParam = Tools.getQueryParam('type');
  77. if (typeParam) document.getElementById('activity-type').innerText = decodeURIComponent(typeParam);
  78. const btnTextParam = Tools.getQueryParam('btnText');
  79. if (btnTextParam) document.getElementById('action-btn').innerText = decodeURIComponent(btnTextParam);
  80. loadCardBase();
  81. checkUserJoin();
  82. loadMatchDetail();
  83. };
  84. window.onunload = function() {
  85. if (state.timer) {
  86. clearInterval(state.timer);
  87. }
  88. };
  89. function loadCardBase() {
  90. if (!window.API) return;
  91. API.getCardBase(state.ecId).then(res => {
  92. if (res) {
  93. document.getElementById('activity-name').innerText = res.ecName || '未命名活动';
  94. state.beginSecond = res.beginSecond;
  95. state.endSecond = res.endSecond;
  96. state.secondCardName = res.secondCardName;
  97. startCountdown();
  98. }
  99. });
  100. }
  101. function checkUserJoin() {
  102. if (!window.API) return;
  103. API.getUserJoinStatus(state.ecId).then(res => {
  104. if (res && res.isJoin) {
  105. state.isJoin = true;
  106. }
  107. });
  108. }
  109. function loadMatchDetail() {
  110. if (!window.API) return;
  111. API.getMatchRsDetail(state.ecId,0).then(res => {
  112. if (!res) return;
  113. const rankStr = JSON.stringify(res);
  114. const cache = localStorage.getItem(state.rankKey);
  115. if (cache !== rankStr) {
  116. document.getElementById('notice-icon').classList.remove('hidden');
  117. localStorage.setItem(state.rankKey, rankStr);
  118. }
  119. });
  120. }
  121. function startCountdown() {
  122. const countdownEl = document.getElementById('countdown');
  123. const update = () => {
  124. if (state.endSecond > 0) {
  125. const diff = state.endSecond - Date.now() / 1000;
  126. if (diff > 0) {
  127. countdownEl.innerText = '距结束' + Tools.convertSecondsToDHM(diff);
  128. } else {
  129. countdownEl.innerText = '已结束';
  130. state.isFinished = true;
  131. clearInterval(state.timer);
  132. }
  133. }
  134. };
  135. update();
  136. state.timer = setInterval(update, 60000);
  137. }
  138. function handleBtnClick() {
  139. //const queryStr = window.location.search;
  140. const queryStr='?token='+ Tools.getQueryParam('token') +'&id=112';
  141. if (state.isJoin) {
  142. const target = `./ranklist.html${queryStr}&full=true`;
  143. Bridge.appAction(target);
  144. } else {
  145. if (!state.isFinished) {
  146. if (state.secondCardName === 'rankList') {
  147. const target = `./ranklist.html${queryStr}&full=true`;
  148. Bridge.appAction(target);
  149. } else {
  150. const target = `./signup.html${queryStr}&full=true`;
  151. Bridge.appAction(target);
  152. }
  153. } else {
  154. const target = `./ranklist.html${queryStr}&full=true`;
  155. Bridge.appAction(target);
  156. }
  157. }
  158. }
  159. </script>
  160. </body>
  161. </html>