You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

546 lines
18 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  6. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
  7. <link href="https://fonts.yecdn.com/css2?family=Noto+Serif+SC:wght@300;700&display=swap" rel="stylesheet">
  8. <link href="https://fonts.yecdn.com/css2?family=Noto+Sans+SC&display=swap" rel="stylesheet">
  9. <meta property="og:title" content="华清大学课程攻略共享计划" />
  10. <meta property="og:description" content="说人话就是往年考题" />
  11. <title>华清大学课程攻略共享计划</title>
  12. <style>
  13. body {
  14. background: linear-gradient(-45deg,
  15. #fff calc(50% - 1px),
  16. #ddd calc(50%),
  17. #fff calc(50% + 1px)
  18. );
  19. background-size: 6px 5px;
  20. }
  21. body,
  22. p,
  23. pre {
  24. font-family: 'Noto Sans SC', sans-serif;
  25. }
  26. .qbox pre {
  27. white-space: pre-wrap;
  28. }
  29. h1,
  30. h2,
  31. h3,
  32. h4,
  33. h5,
  34. h6,
  35. .num-info{
  36. font-family: 'Noto Serif SC', serif;
  37. font-weight: 300;
  38. }
  39. .num-info-active{
  40. font-family: 'Noto Serif SC', serif;
  41. font-weight: 700;
  42. }
  43. .num-infos {
  44. display: inline-block;
  45. }
  46. a,
  47. a:hover,
  48. .btn-link,
  49. .btn-link:hover {
  50. color: inherit;
  51. text-decoration: underline;
  52. }
  53. nav .page-link {
  54. color: #000;
  55. }
  56. nav .page-item.active .page-link {
  57. background-color: #000;
  58. border-color: #000;
  59. }
  60. .btn-lg {
  61. font-size: 2em;
  62. font-family: 'Noto Serif SC', serif;
  63. }
  64. .part1 {
  65. max-width: 500px;
  66. float: left;
  67. padding-right: 10px;
  68. position: relative;
  69. }
  70. .input-form {
  71. position: absolute;
  72. top: 0;
  73. overflow-y: auto;
  74. overflow-x: hidden;
  75. background-color: #0006;
  76. height: 100%;
  77. }
  78. .part2 {
  79. min-width: 200px;
  80. min-height: 100vh;
  81. overflow: hidden;
  82. padding-left: 25px;
  83. }
  84. .card-header {
  85. padding: .15em 1.25em;
  86. }
  87. .qbox {
  88. background: #fffe;
  89. padding: 5px 20px;
  90. color: black;
  91. margin: 5px 5px 20px;
  92. }
  93. .new .qbox {
  94. border: 2px black solid;
  95. background: white;
  96. color: black;
  97. }
  98. .new .qbox input,
  99. .new .qbox textarea {
  100. border: none;
  101. border-bottom: 1px solid black;
  102. background: transparent;
  103. color: black;
  104. border-radius: 0;
  105. }
  106. .new .qbox .custom-control-input:checked~.custom-control-label::before {
  107. background-color: #495057;
  108. border-color: #495057;
  109. }
  110. .liked {
  111. fill: #000;
  112. }
  113. .display_name {
  114. margin: 0;
  115. }
  116. .card-body {
  117. padding: 0.75em;
  118. }
  119. .cate {
  120. margin: 4px;
  121. display: inline-block;
  122. }
  123. .cate a {
  124. display: inline-block;
  125. background-color: #444;
  126. color: white;
  127. padding: 2px 4px;
  128. text-decoration: none;
  129. }
  130. .cate.selected a {
  131. background-color: white;
  132. color: #444;
  133. border: 1px black solid;
  134. }
  135. .cate .count {
  136. font-size: 12px;
  137. vertical-align: bottom;
  138. margin-left: -3px;
  139. }
  140. .footer {
  141. background: black;
  142. color: white;
  143. text-align: center;
  144. font-size: 80%;
  145. border-top: solid 1px white;
  146. }
  147. .footer p {
  148. margin: 10px 0 0;
  149. float: bottom;
  150. }
  151. .popover-body ul {
  152. padding-left: 15px;
  153. }
  154. .popover-body ul li {
  155. margin-bottom: 8px;
  156. }
  157. .user-info {
  158. position: fixed;
  159. top: 0;
  160. right: 0;
  161. z-index: 1030
  162. }
  163. .user-info:not(:hover) div:not(.show) .username{
  164. display: none;
  165. }
  166. .btn, input, select, textarea, label {
  167. box-shadow: none !important;
  168. }
  169. .mask {
  170. background: linear-gradient(25deg,
  171. #5558 calc(50% - 1px),
  172. #333 calc(50%),
  173. #5558 calc(50% + 1px)
  174. );
  175. background-size: 10px 5px;
  176. position: absolute;
  177. z-index: 999;
  178. width: 100%;
  179. height: 100%;
  180. top: -5px;
  181. left: -5px;
  182. border-radius: 0;
  183. }
  184. .wechat-share div {
  185. position: absolute;
  186. right: 50%;
  187. top: 100%;
  188. background-color: #fffd;
  189. }
  190. .wechat-share:not(:hover) div {
  191. display: none;
  192. }
  193. .wechat-share img {
  194. width: 196px;
  195. }
  196. .custom-file-label {
  197. overflow: hidden;
  198. }
  199. </style>
  200. </head>
  201. <body>
  202. <div class="container" style="overflow: hidden">
  203. <div class="pt-3 pl-3 pb-4 mb-4">
  204. <h1>华清大学<br>&nbsp;课程攻略<br>&nbsp;&nbsp;共享计划</h1>
  205. </div>
  206. <div class="user-info">
  207. <div class="btn-group">
  208. <button type="button" class="btn btn-dark rounded-0 p-1 pl-2">
  209. <img class="rounded-circle" src="{{avatar}}" width="24">
  210. <span class="username ml-2">{{username}}</span>
  211. </button>
  212. <button type="button" class="btn btn-dark rounded-0 dropdown-toggle dropdown-toggle-split" id="dropdownMenuReference" data-toggle="dropdown" data-reference="parent">
  213. <span class="sr-only">Toggle Dropdown</span>
  214. </button>
  215. <div class="dropdown-menu">
  216. <a class="dropdown-item" href="?my_upload=1#part2">我的上传</a>
  217. <a class="dropdown-item" href="?my_fav=1#part2">我的点赞</a>
  218. <div class="dropdown-divider"></div>
  219. <a class="dropdown-item" href="logout">退出账号</a>
  220. <div class="dropdown-divider"></div>
  221. <a class="dropdown-item wechat-share" href="##">
  222. 微信传播
  223. <div><img src="img/wechat-share.png"></div>
  224. </a>
  225. </div>
  226. </div>
  227. </div>
  228. <div class="part1 new">
  229. <form action="upload" method="post" enctype="multipart/form-data">
  230. <div class="form-group qbox">
  231. <h1 style="margin: -16px -26px 35px">上传</h1>
  232. <div class="form-group row">
  233. <label class="col-sm-3 col-form-label mb-0">课程名</label>
  234. <div class="col-sm-9">
  235. <input type="text" class="form-control" name="name" required placeholder="课程名,注意保持一致" maxlength="30">
  236. </div>
  237. </div>
  238. <div class="form-group row">
  239. <label class="col-sm-3 col-form-label">任课教师</label>
  240. <div class="col-sm-9">
  241. <input type="text" class="form-control" name="teacher" required placeholder="教师名或“不详”" value="不详" maxlength="30">
  242. </div>
  243. </div>
  244. <div class="form-group row">
  245. <label class="col-sm-3 col-form-label">年份</label>
  246. <div class="col-sm-9">
  247. <select class="custom-select" name="year">
  248. <option selected>不详/不适用</option>
  249. {% for y in range(curr_year, curr_year-10, -1) %}
  250. <option value="{{y}}">{{y}}</option>
  251. {% endfor %}
  252. </select>
  253. </div>
  254. </div>
  255. <div class="form-group mt-4 mb-4">
  256. <label>说明(可选)</label>
  257. <textarea class="form-control" name="notes" rows="2" placeholder="默认视为往年期末考题,也可能是其他资料" maxlength="200"></textarea>
  258. </div>
  259. <div class="custom-file">
  260. <input type="file" class="custom-file-input" name="files[]" multiple required>
  261. <label class="custom-file-label" for="customFile" data-browse="浏览">选择文件,可以多选</label>
  262. </div>
  263. <div class="custom-control custom-switch mb-2 mt-3 ml-1">
  264. <input type="checkbox" class="custom-control-input" id="upload-dir" name="upload-dir">
  265. <label class="custom-control-label" for="upload-dir">上传文件夹</label>
  266. </div>
  267. <div class="custom-control custom-switch mb-2 mt-3 ml-1">
  268. <input type="checkbox" class="custom-control-input" id="anon" name="anon">
  269. <label class="custom-control-label" for="anon">匿名分享</label>
  270. </div>
  271. <p> 开启匿名分享后,其他人在查看时作者会显示为“匿名”。 </p>
  272. <button type="submit" class="btn btn-link btn-lg mt-4 pr-1">分享</button>
  273. <span>
  274. <a href="##" role="button"data-toggle="popover" >
  275. <svg width="20px" viewBox="0 0 24 28"><path d="M15.07 11.25l-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2a2 2 0 0 0-2 2H8a4 4 0 0 1 4-4a4 4 0 0 1 4 4a3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z" fill="#626262"/></svg>
  276. </a>
  277. </span>
  278. </div>
  279. </form>
  280. {% if disable_upload %}
  281. <button class="mask" onclick="alert('目前guest无权限上传')"></button>
  282. {% endif %}
  283. <div style="font-size:80%;margin-bottom:70px">
  284. <ul>
  285. <li>
  286. 如果觉得操作太麻烦,也可将资料发给
  287. <a href="mailto:thu_courses@protonmail.com">thu_courses@protonmail.com</a>
  288. ,由工作人员后台添加。
  289. </li>
  290. <li>
  291. 如果你认为本项目侵犯了你的权益,请致信
  292. <a href="mailto:thu_courses@protonmail.com">thu_courses@protonmail.com</a>
  293. ,我们会在第一时间处理。
  294. </li>
  295. <li>
  296. 如无特别注明,由贡献者所编写部分使用知识共享许可协议
  297. <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">CC BY-NC-SA 4.0 (署名-非商业性使用-相同方式共享 4.0 国际)</a>
  298. ,其余部分的版权归属于原作者。
  299. </li>
  300. </ul>
  301. </div>
  302. </div>
  303. <div class="part2" id="part2">
  304. <div id="accordion">
  305. <div class="card">
  306. <div class="card-header" id="headingOne">
  307. <h5 class="mb-0">
  308. <button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne">
  309. 课程
  310. </button>
  311. </h5>
  312. </div>
  313. <div id="collapseOne" class="collapse {{'show' if has_course or ept else ''}}" data-parent="#accordion">
  314. <div class="card-body">
  315. {% for k, courses in all_courses_abc.items() %}
  316. <h5>{{k}}</h5>
  317. {% for c, count in courses %}
  318. <span class="cate {{'selected' if c==course else ''}}">
  319. <a href="?course={{'' if c==course else c}}#part2">{{c}}</a>
  320. <span class="count">({{count}})</span>
  321. </span>
  322. {% endfor %}
  323. {% endfor %}
  324. </div>
  325. </div>
  326. </div>
  327. <div class="card">
  328. <div class="card-header" id="headingTwo">
  329. <h5 class="mb-0">
  330. <button class="btn btn-link collapsed" data-toggle="collapse" data-target="#collapseTwo">
  331. 教师
  332. </button>
  333. </h5>
  334. </div>
  335. <div id="collapseTwo" class="collapse {{'show' if has_teacher else ''}}" data-parent="#accordion">
  336. <div class="card-body">
  337. {% for t, count in all_teachers %}
  338. <span class="cate {{'selected' if t==teacher else ''}}">
  339. <a href="?teacher={{'' if t==teacher else t}}#part2">{{t}}</a>
  340. <span class="count">({{count}})</span>
  341. </span>
  342. </span>
  343. {% endfor %}
  344. </div>
  345. </div>
  346. </div>
  347. <div class="card">
  348. <div class="card-header" id="headingThree">
  349. <h5 class="mb-0">
  350. <button class="btn btn-link collapsed" data-toggle="collapse" data-target="#collapseThree">
  351. 年份
  352. </button>
  353. </h5>
  354. </div>
  355. <div id="collapseThree" class="collapse {{'show' if has_year else ''}}" data-parent="#accordion">
  356. <div class="card-body">
  357. {% for y, count in all_years %}
  358. <span class="cate {{'selected' if y==year else ''}}">
  359. <a href="?year={{'' if y==year else y}}#part2">{{y or '/'}}</a>
  360. <span class="count">({{count}})</span>
  361. </span>
  362. </span>
  363. {% endfor %}
  364. </div>
  365. </div>
  366. </div>
  367. </div>
  368. <div class="ml-2 mt-2 mb-5">
  369. <p>*点击某一课程/教师/年份进行筛选</p>
  370. </div>
  371. <div class="mb-2">
  372. {% if is_my_upload %}
  373. <span class="cate selected"><a href="?my_upload=#part2">我的上传</a></span>
  374. {% endif %}
  375. {% if is_my_fav %}
  376. <span class="cate selected"><a href="?my_fav=#part2">我的点赞</a></span>
  377. {% endif %}
  378. </div>
  379. {% for p in pagination.items %}
  380. <div class="qbox">
  381. {% if showPrivate %}
  382. <form action="{{c.id}}/delete" method="post">
  383. <input type="hidden" name="key" value="{{key}}">
  384. <button type="submit" class="close">
  385. <span>×</span>
  386. </button>
  387. </form>
  388. {% endif %}
  389. <h5>{{p.course}}</h5>
  390. <p class="ml-3">
  391. {{p.teacher}} - {{p.year or '/'}}
  392. </p>
  393. <pre class="ml-3">{{p.notes}}</pre>
  394. <div class="text-right">
  395. <small>@{{'匿名用户' if p.anon else p.author}} | {{p.create_date}}</small>
  396. <div class="num-infos">
  397. <button class="btn btn-link" id="like-{{p.id}}" onclick="like('{{p.id}}')">
  398. <span class="num-info {{'num-info-active' if p.is_liked() else ''}}">好评(<span>{{p.like_num}}</span>)</span>
  399. </button>
  400. <span>
  401. <a href="{{p.id}}/download?v={{ipfs_version}}" target="_blank" class="btn btn-link px-0" id="download-{{p.id}}">
  402. <span class="num-info {{'num-info-active' if p.is_downloaded() else ''}}">去下载({{p.down_num}})</span>
  403. </a>
  404. <button type="button" class="btn btn-link px-0 dropdown-toggle dropdown-toggle-split" id="downloadDropdownMenuReference" data-toggle="dropdown" data-reference="parent">
  405. <span class="sr-only">Toggle Dropdown</span>
  406. </button>
  407. <div class="dropdown-menu" style="min-width: 5rem">
  408. <a class="dropdown-item" href="{{p.id}}/download?format=zip" target="_blank"><span class="num-info">打包下载 - zip</span></a>
  409. <a class="dropdown-item" href="{{p.id}}/download?format=tar" target="_blank"><span class="num-info">打包下载 - tar</span></a>
  410. <a class="dropdown-item" href="{{p.id}}/download?format=gztar" target="_blank"><span class="num-info">打包下载 - gzip</span></a>
  411. </div>
  412. </span>
  413. </div>
  414. </div>
  415. </div>
  416. {% endfor %}
  417. <nav>
  418. <ul class="pagination">
  419. {%- for page in pagination.iter_pages() %}
  420. {% if page %}
  421. {% if page != pagination.page %}
  422. <li class="page-item"><a class="page-link" href="{{ url_for('list', page=page, per_page=pagination.per_page, course=course, teacher=teacher, year=year) }}#part2">{{ page }}</a></li>
  423. {% else %}
  424. <li class="page-item active">
  425. <a class="page-link" href="#part2">{{ page }}<span class="sr-only">(current)</span></a>
  426. </li>
  427. {% endif %}
  428. {% else %}
  429. <li class="page-item"><span class=ellipsis></span></li>
  430. {% endif %}
  431. {%- endfor %}
  432. </ul>
  433. </nav>
  434. </div>
  435. </div>
  436. <div class="footer">
  437. <p>
  438. <a href="//closed.social" target="_blank">闭社</a>提供技术支持,本系统开源于<a href="//git.closed.social/closed-social/pastExam">碧茶</a>
  439. </p>
  440. <p> 🄯 2020 Copyleft: closed.social</p>
  441. </div>
  442. </body>
  443. <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
  444. <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>
  445. <script src="https://cdn.jsdelivr.net/npm/bs-custom-file-input/dist/bs-custom-file-input.min.js" crossorigin="anonymous"></script>
  446. <script>
  447. function like(toot) {
  448. var method = 'POST';
  449. if ($(`#like-${toot} .num-info`).hasClass("num-info-active")) {
  450. method = 'DELETE'
  451. }
  452. $.ajax({
  453. type: method,
  454. url: toot + '/like',
  455. success: (result, status, xhr) => {
  456. $(`#like-${toot} > span > span`).text(result);
  457. $(`#like-${toot} > span`).toggleClass("num-info-active");
  458. },
  459. error: (xhr, status, error) => {
  460. alert(xhr.status + ' ' + xhr.statusText);
  461. }
  462. });
  463. }
  464. $(document).ready(function () {
  465. bsCustomFileInput.init();
  466. $("#upload-dir").change(function() {
  467. var fi = $('.custom-file-input');
  468. var fl = $('.custom-file-label');
  469. console.log(fi);
  470. if(this.checked) {
  471. fi.attr('webkitdirectory', true);
  472. fl.text('选择文件夹,可以多选');
  473. }
  474. else {
  475. fi.removeAttr('webkitdirectory');
  476. fl.text('选择文件,可以多选');
  477. }
  478. });
  479. $('[data-toggle="popover"]').popover({
  480. html: true,
  481. placement: "top",
  482. trigger: "focus",
  483. title: "说明",
  484. content:`<ul>
  485. <li>文件可以多选,电脑端一般是按住ctrl选择,移动端一般是直接勾选多个。对文件数量和大小没有限制,总大小不要太过分就行。</li>
  486. <li>时间请填写该学期开始时的年份,课程名尽量与已有的保持一致。</li>
  487. </ul>`
  488. });
  489. })
  490. </script>
  491. </html>