index.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. <?php
  2. $blogs = DB::selectAll("select blogs.id, title, poster, post_time from important_blogs, blogs where is_hidden = 0 and important_blogs.blog_id = blogs.id order by level desc, important_blogs.blog_id desc limit 8");
  3. $activateusers = DB::selectAll("select submitter, count(*) as cnt from submissions where datediff(now(), submit_time) <= 30 group by submitter order by cnt desc limit 12;");
  4. $topusers = DB::selectAll("select u.username, u.rating, u.rating_rd, u.rating_vol, u.motto, u.qq, count(*) cnt from user_info u inner join contests_registrants c on u.username = c.username inner join contests s on s.id = c.contest_id where datediff(now(), s.start_time) <= 180 group by c.username having cnt >= 3 order by rating desc, username asc limit 12;");
  5. $hotusers = DB::selectAll("select username, rating, rating_rd, rating_vol, qq, motto from user_info order by rating_vol desc, username asc limit 12;");
  6. $topblogs = DB::selectAll("select id from blogs order by zan desc limit 10;");
  7. $songs_data = htmlspecialchars(json_encode(DB::selectAll("select * from songs;")), ENT_QUOTES, 'UTF-8');
  8. // 服务器数据看板
  9. $today_submit_num = DB::selectCount("select count(*) from submissions where date(submit_time) = date(now())");
  10. $today_ac_num = DB::selectCount("select count(*) from submissions where date(submit_time) = date(now()) and score = 100");
  11. $month_submit_num = DB::selectCount("select count(*) from submissions where year(submit_time) = year(now()) and month(submit_time) = month(now())");
  12. $month_ac_num = DB::selectCount("select count(*) from submissions where year(submit_time) = year(now()) and month(submit_time) = month(now()) and score = 100");
  13. $total_submit_num = DB::selectCount("select count(*) from submissions");
  14. $total_ac_num = DB::selectCount("select count(*) from submissions where score = 100");
  15. $total_problem_num = DB::selectCount("select count(*) from problems where is_hidden = 0");
  16. $total_user_num = DB::selectCount("select count(*) from user_info");
  17. // 最近比赛:未结束的按开始时间升序取,不足 5 场时补最近结束的
  18. $recent_contests = array();
  19. $result = DB::selectAll("select * from contests where status != 'finished' order by start_time asc, id asc limit 5");
  20. foreach ($result as $contest) {
  21. genMoreContestInfo($contest);
  22. $recent_contests[] = $contest;
  23. }
  24. if (count($recent_contests) < 5) {
  25. $need = 5 - count($recent_contests);
  26. $result = DB::selectAll("select * from contests where status = 'finished' order by start_time desc, id desc limit $need");
  27. foreach ($result as $contest) {
  28. genMoreContestInfo($contest);
  29. $recent_contests[] = $contest;
  30. }
  31. }
  32. ?>
  33. <?php echoUOJPageHeader(UOJConfig::$data['profile']['oj-name-short']) ?>
  34. <div id="songs-data" data-songs='<?php echo $songs_data; ?>'></div>
  35. <div class="row shadow my-4 wyoj-topcard">
  36. <div class="card-body">
  37. <div class="row">
  38. <!-- <div class="col-xs-6 col-sm-4 col-md-3">
  39. <img class="media-object img-thumbnail" src="/images/logo.png" alt="Logo" />
  40. </div>-->
  41. <div class="col-sm-12 col-md-9">
  42. <table class="table table-sm">
  43. <!-- <thead>
  44. <tr>
  45. <th style="width:60%"><?= UOJLocale::get('announcements') ?></th>
  46. <th style="width:20%"></th>
  47. <th style="width:20%"></th>
  48. </tr>
  49. </thead>-->
  50. <tbody>
  51. <?php $now_cnt = 0; ?>
  52. <?php foreach ($blogs as $blog): ?>
  53. <?php
  54. $now_cnt++;
  55. $new_tag = '';
  56. if ((time() - strtotime($blog['post_time'])) / 3600 / 24 <= 7) {
  57. $new_tag = '<sup style="color:red">&nbsp;new</sup>';
  58. }
  59. ?>
  60. <tr>
  61. <td><a href="/blogs/<?= $blog['id'] ?>"><?= $blog['title'] ?></a><?= $new_tag ?></td>
  62. <td>by <?= getUserLink($blog['poster']) ?></td>
  63. <td><small><?= $blog['post_time'] ?></small></td>
  64. </tr>
  65. <?php endforeach ?>
  66. <?php for ($i = $now_cnt + 1; $i <= 8; $i++): ?>
  67. <tr><td colspan="233">&nbsp;</td></tr>
  68. <?php endfor ?>
  69. <tr><td class="text-right" colspan="233">
  70. <span>本歌曲由 </span><span id="recommender"></span><span> 推荐</span>
  71. </td></tr>
  72. <tr><td class="text-right" colspan="233">
  73. <a href="https://git.ryp.org.cn/wyoj/" class="text-info font-weight-bold">WyOJ 以及所有相关项目均为自由软件。</a>
  74. <a href="/announcements"><?= UOJLocale::get('all the announcements') ?></a>
  75. </td></tr>
  76. <tr>
  77. <td class="text-right" colspan="233">
  78. <span class="text-danger font-weight-bold">声明:本网站属个人非经营性网站,仅用于学习交流,无任何盈利目的,与任何组织无关</span>
  79. <a href="/certs-manage/songs">我要推歌</a>
  80. </td>
  81. </tr>
  82. </tbody>
  83. </table>
  84. </div>
  85. <div class="col-xs-6 col-sm-4 col-md-3">
  86. <div class="card" style="max-width:300px; width:100%; border-radius:0; ">
  87. <div class="image-frame" style="aspect-ratio:1/1; position:relative;">
  88. <img id="photo" src="" alt="" style="width:100%; height:100%; object-fit:cover; display:block; cursor:pointer; -webkit-tap-highlight-color:transparent;">
  89. </div>
  90. <div class="intro" style="padding:1.6rem 1.8rem 1.2rem; text-align:center; background:#ffffff;">
  91. <p id="name" style="font-size:1.0rem; font-weight:800; letter-spacing:1px; margin-bottom:0.5rem; line-height:1.2; margin-block:0;"></p>
  92. <p id="amb" style="font-size:0.7rem; font-weight:400; color:#4f5d69; margin-bottom:0.25rem; line-height:1.5; border-top:1px dashed #cdd9e3; padding-top:0.8rem; white-space:pre-wrap; margin-block:0;"></p>
  93. <p id="writer" style="font-size:0.7rem; font-weight:400; color:#4f5d69; margin-bottom:0.25rem; line-height:1.5; white-space:pre-wrap; margin-block:0;"></p>
  94. </div>
  95. <div class="button-wrapper" style="padding:0.2rem 1.8rem 2rem 1.8rem; background:#ffffff;">
  96. <style>
  97. #randomBtn{
  98. display: inline-flex;
  99. align-items: center;
  100. justify-content: center;
  101. gap: 0.6rem;
  102. width: 100%;
  103. background: #1f2f3b;
  104. color: white;
  105. padding: 0.7rem 0;
  106. cursor: pointer;
  107. transition: all 0.2s ease;
  108. letter-spacing: 0.5px;
  109. border: 1px solid rgba(255, 255, 255, 0.2);
  110. backdrop-filter: blur(4px);
  111. font-family: inherit;
  112. line-height: 1;
  113. }
  114. </style>
  115. <button id="randomBtn">换一首</button>
  116. </div>
  117. </div>
  118. <script>
  119. (function() {
  120. let dataDiv = document.getElementById('songs-data');
  121. let library = JSON.parse(dataDiv.dataset.songs);
  122. const photoImg = document.getElementById('photo');
  123. const nameEl = document.getElementById('name');
  124. const ambEl = document.getElementById('amb');
  125. const writerEl = document.getElementById('writer');
  126. const randomBtn = document.getElementById('randomBtn');
  127. const recommenderEl = document.getElementById('recommender');
  128. let lastIndex = -1;
  129. let currentMusicLink = library[0].musiclink;
  130. photoImg.addEventListener('mousedown', function(e) {
  131. this.style.opacity = '0.8';
  132. });
  133. photoImg.addEventListener('mouseup', function(e) {
  134. this.style.opacity = '';
  135. });
  136. photoImg.addEventListener('mouseleave', function(e) {
  137. this.style.opacity = '';
  138. });
  139. photoImg.addEventListener('touchstart', function(e) {
  140. this.style.opacity = '0.8';
  141. });
  142. photoImg.addEventListener('touchend', function(e) {
  143. this.style.opacity = '';
  144. });
  145. photoImg.addEventListener('touchcancel', function(e) {
  146. this.style.opacity = '';
  147. });
  148. function setBtnActive() {
  149. randomBtn.style.background = '#17242e';
  150. randomBtn.style.transform = 'scale(0.98)';
  151. randomBtn.style.boxShadow = '0 4px 8px rgba(0,0,0,0.2)';
  152. }
  153. function setBtnNormal() {
  154. randomBtn.style.background = '#1f2f3b';
  155. randomBtn.style.transform = 'scale(1)';
  156. randomBtn.style.boxShadow = 'none';
  157. }
  158. randomBtn.addEventListener('mousedown', setBtnActive);
  159. randomBtn.addEventListener('mouseup', setBtnNormal);
  160. randomBtn.addEventListener('mouseleave', setBtnNormal);
  161. randomBtn.addEventListener('touchstart', setBtnActive);
  162. randomBtn.addEventListener('touchend', setBtnNormal);
  163. randomBtn.addEventListener('touchcancel', setBtnNormal);
  164. photoImg.addEventListener('click', function() {
  165. if (currentMusicLink) {
  166. window.open(currentMusicLink, '_blank');
  167. }
  168. });
  169. function randmusic() {
  170. let randid = lastIndex;
  171. while (randid === lastIndex) {
  172. randid = Math.floor(Math.random() * library.length);
  173. }
  174. if (lastIndex == -1) randid = 3;
  175. lastIndex = randid;
  176. const ys = library[randid];
  177. photoImg.src = ys.cover;
  178. photoImg.alt = ys.name;
  179. nameEl.textContent = ys.name;
  180. ambEl.textContent = ys.album;
  181. writerEl.textContent = ys.writer;
  182. recommenderEl.textContent = ys.user;
  183. currentMusicLink = ys.click;
  184. }
  185. randmusic();
  186. randomBtn.addEventListener('click', function() {
  187. randmusic();
  188. });
  189. })();
  190. </script>
  191. </div>
  192. </div>
  193. </div>
  194. </div>
  195. <div class="row shadow my-4 wyoj-topcard">
  196. <div class="col-lg-6 p-4">
  197. <h3>服务器数据</h3>
  198. <div class="row">
  199. <div class="col-6 col-lg-3 mb-3">
  200. <div class="card h-100 p-3 text-center stat-card">
  201. <div class="stat-icon"><span class="glyphicon glyphicon-flash"></span></div>
  202. <div class="stat-num"><?= $today_submit_num ?></div>
  203. <div class="stat-label">今日提交</div>
  204. </div>
  205. </div>
  206. <div class="col-6 col-lg-3 mb-3">
  207. <div class="card h-100 p-3 text-center stat-card">
  208. <div class="stat-icon"><span class="glyphicon glyphicon-ok"></span></div>
  209. <div class="stat-num"><?= $today_ac_num ?></div>
  210. <div class="stat-label">今日通过</div>
  211. </div>
  212. </div>
  213. <div class="col-6 col-lg-3 mb-3">
  214. <div class="card h-100 p-3 text-center stat-card">
  215. <div class="stat-icon"><span class="glyphicon glyphicon-send"></span></div>
  216. <div class="stat-num"><?= $month_submit_num ?></div>
  217. <div class="stat-label">本月提交</div>
  218. </div>
  219. </div>
  220. <div class="col-6 col-lg-3 mb-3">
  221. <div class="card h-100 p-3 text-center stat-card">
  222. <div class="stat-icon"><span class="glyphicon glyphicon-check"></span></div>
  223. <div class="stat-num"><?= $month_ac_num ?></div>
  224. <div class="stat-label">本月通过</div>
  225. </div>
  226. </div>
  227. <div class="col-6 col-lg-3 mb-3">
  228. <div class="card h-100 p-3 text-center stat-card">
  229. <div class="stat-icon"><span class="glyphicon glyphicon-tasks"></span></div>
  230. <div class="stat-num"><?= $total_submit_num ?></div>
  231. <div class="stat-label">总提交</div>
  232. </div>
  233. </div>
  234. <div class="col-6 col-lg-3 mb-3">
  235. <div class="card h-100 p-3 text-center stat-card">
  236. <div class="stat-icon"><span class="glyphicon glyphicon-star"></span></div>
  237. <div class="stat-num"><?= $total_ac_num ?></div>
  238. <div class="stat-label">总通过</div>
  239. </div>
  240. </div>
  241. <div class="col-6 col-lg-3 mb-3">
  242. <div class="card h-100 p-3 text-center stat-card">
  243. <div class="stat-icon"><span class="glyphicon glyphicon-list-alt"></span></div>
  244. <div class="stat-num"><?= $total_problem_num ?></div>
  245. <div class="stat-label">题目总数</div>
  246. </div>
  247. </div>
  248. <div class="col-6 col-lg-3 mb-3">
  249. <div class="card h-100 p-3 text-center stat-card">
  250. <div class="stat-icon"><span class="glyphicon glyphicon-user"></span></div>
  251. <div class="stat-num"><?= $total_user_num ?></div>
  252. <div class="stat-label">注册用户</div>
  253. </div>
  254. </div>
  255. </div>
  256. </div>
  257. <div class="col-lg-6 p-4">
  258. <h3>最近比赛</h3>
  259. <?php if (empty($recent_contests)): ?>
  260. <p class="text-muted">暂无比赛</p>
  261. <?php else: ?>
  262. <table class="table contest-table">
  263. <tbody>
  264. <?php foreach ($recent_contests as $contest): ?>
  265. <tr>
  266. <td class="contest-name">
  267. <a href="<?= HTML::url('/contest/' . $contest['id']) ?>"><?= $contest['name'] ?></a>
  268. <?php if ($contest['cur_progress'] == CONTEST_NOT_STARTED): ?>
  269. <span class="badge badge-info">即将开始</span>
  270. <span class="contest-countdown" id="recent-contest-countdown-<?= $contest['id'] ?>"></span>
  271. <?php elseif ($contest['cur_progress'] == CONTEST_IN_PROGRESS): ?>
  272. <span class="badge badge-success">进行中</span>
  273. <?php elseif ($contest['cur_progress'] == CONTEST_PENDING_FINAL_TEST): ?>
  274. <span class="badge badge-warning">等待出分</span>
  275. <?php elseif ($contest['cur_progress'] == CONTEST_TESTING): ?>
  276. <span class="badge badge-warning">最终评测中</span>
  277. <?php else: ?>
  278. <span class="badge badge-secondary">已结束</span>
  279. <?php endif ?>
  280. </td>
  281. <td class="contest-info"><?= $contest['start_time_str'] ?></td>
  282. <td class="contest-info"><?= round($contest['last_min'] / 60, 2) ?>h</td>
  283. </tr>
  284. <?php endforeach ?>
  285. </tbody>
  286. </table>
  287. <?php endif ?>
  288. </div>
  289. </div>
  290. <script type="text/javascript">
  291. <?php foreach ($recent_contests as $contest): ?>
  292. <?php if ($contest['cur_progress'] == CONTEST_NOT_STARTED): ?>
  293. $('#recent-contest-countdown-<?= $contest['id'] ?>').countdown(<?= $contest['start_time']->getTimestamp() - UOJTime::$time_now->getTimestamp() ?>);
  294. <?php endif ?>
  295. <?php endforeach ?>
  296. </script>
  297. <div class="row shadow my-4 wyoj-topcard">
  298. <div class="col-12 p-4">
  299. <h3>活跃排行榜</h3>
  300. </div>
  301. <?php foreach($activateusers as $username): ?>
  302. <?php $user = queryUser($username['submitter']); ?>
  303. <div class="col-md-3 mb-4">
  304. <div class="card h-100 p-3 text-center">
  305. <img class="uoj-avatar mx-auto mb-2" src=<?= "https://q.qlogo.cn/g?b=qq&nk=" . $user['qq'] . "&s=100" ?> alt="...">
  306. <span class="mb-2"><?= getUserLink($user['username']) ?></span>
  307. <span class="text-center text-bottom"><?= $user['motto'] ?></span>
  308. </div>
  309. </div>
  310. <?php endforeach ?>
  311. </div>
  312. <div class="row shadow my-4 wyoj-topcard">
  313. <div class="col-12 p-4">
  314. <h3>比赛排行榜(180天内三场及以上比赛)</h3>
  315. <a href="/ranklist">全部排名</a>
  316. </div>
  317. <?php foreach($topusers as $user): ?>
  318. <div class="col-md-3 mb-4">
  319. <div class="card h-100 p-3 text-center">
  320. <img class="uoj-avatar mx-auto mb-2" src=<?= "https://q.qlogo.cn/g?b=qq&nk=" . $user['qq'] . "&s=100" ?> alt="...">
  321. <span class="mb-2"><?= getUserLink($user['username']) ?></span>
  322. <strong style="color: red" class="mb-2"><?= $user['rating'] ?> (±<?= round($user['rating_rd']) * 2 ?>)</strong>
  323. <span class="text-center text-bottom"><?= $user['motto'] ?></span>
  324. </div>
  325. </div>
  326. <?php endforeach ?>
  327. </div>
  328. <div class="row shadow my-4 wyoj-topcard">
  329. <div class="col-12 p-4">
  330. <h3>黑马 / 爆冷榜</h3>
  331. </div>
  332. <?php foreach($hotusers as $user): ?>
  333. <div class="col-md-3 mb-4">
  334. <div class="card h-100 p-3 text-center">
  335. <img class="uoj-avatar mx-auto mb-2" src=<?= "https://q.qlogo.cn/g?b=qq&nk=" . $user['qq'] . "&s=100" ?> alt="...">
  336. <span class="mb-2"><?= getUserLink($user['username']) ?></span>
  337. <strong style="color: red" class="mb-2">Vol <?= round(1000 * $user['rating_vol']) / 1000 ?>, <?= $user['rating'] ?> (±<?= round($user['rating_rd']) * 2 ?>)</strong>
  338. <span class="text-center text-bottom"><?= $user['motto'] ?></span>
  339. </div>
  340. </div>
  341. <?php endforeach ?>
  342. </div>
  343. <div class="row shadow my-4 wyoj-topcard">
  344. <div class="col-12 p-4">
  345. <h3>博客广场</h3>
  346. </div>
  347. <?php
  348. foreach ($topblogs as $id) echo echoBlogCard(queryBlog($id['id']));
  349. ?>
  350. </div>
  351. <?php echoUOJPageFooter() ?>