index.html 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. <!DOCTYPE html>
  2. <head>
  3. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  4. <title>moe</title>
  5. <script type="text/javascript" src="/js/jquery.min.js"></script>
  6. <link rel="stylesheet" href="/css/bootstrap.min.css">
  7. <script type="text/javascript" src="/js/bootstrap.min.js"></script>
  8. <link rel="preconnect" href="https://fonts.googleapis.com">
  9. <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  10. <link href="/css/css2.css" rel="stylesheet">
  11. <link rel="stylesheet" href="/css/style.css">
  12. <script>
  13. var status = 0, oid, user, pwd, paused = []
  14. const rot = '43.143.233.184:81', root = 'https://43.143.233.184:81/'
  15. function getCookie(name) {
  16. let arr = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)"));
  17. if (arr != null) return arr[2];
  18. return null;
  19. }
  20. function delCookie(name, path = 'u') {
  21. var exp = new Date();
  22. exp.setTime(exp.getTime() - 1);
  23. var cval = getCookie(name);
  24. if (cval != null)
  25. document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString() + ((path == 'u') ? '' : ';path=' + path)
  26. }
  27. function getUrl(e) {
  28. return e.replace('dd.sdsz.com.cn', rot).replace(/^http:/, 'https:').replace(rot.split(':')[0] + '/', rot + '/').replace('service=http%3A%2F%2F' + root, 'service=http%3A%2F%2Fdd.sdsz.com.cn')
  29. }
  30. function setStatus(e, fast) {
  31. console.log('STATUS', e)
  32. status = e
  33. if (e == 1) {
  34. paused = []
  35. $('#loginSt').text('登录成功')
  36. $('.login').hide(200)
  37. $('#loginSt').addClass('label-success')
  38. $('#loginSt').removeClass('label-danger')
  39. $('.reqLogin').show(300)
  40. } else if (e == 2) {
  41. $('#loginSt').text('登录失败')
  42. $('#loginSt').removeClass('label-success')
  43. $('#loginSt').addClass('label-danger')
  44. } else {
  45. $('.login').show(200)
  46. $('#loginSt').text('未登录')
  47. $('#loginSt').removeClass('label-success')
  48. $('#loginSt').removeClass('label-danger')
  49. $('.reqLogin').hide(300 * !fast)
  50. $('#user').text('-')
  51. }
  52. }
  53. function delCookies(force = 0) {
  54. if (force) {
  55. delCookie('CASTGC', '/')
  56. delCookie('moe', '/')
  57. delCookie('gosh', '/score/')
  58. if (force <= 2) {
  59. delCookie('gosh', '/sso/')
  60. delCookie('gowd', '/sso/')
  61. }
  62. }
  63. if (force >= 2) {
  64. delCookie('JSESSIONID', '/bxn-portal/')
  65. delCookie('JSESSIONID', '/bxn-library/')
  66. delCookie('JSESSIONID', '/bxn-core-uic/')
  67. }
  68. delCookie('JSESSIONID', '/')
  69. delCookie('SSOID', '/')
  70. delCookie('JSESSIONID', '/sso/')
  71. }
  72. function gget(url, call) {
  73. fetch(url, {
  74. "headers": {
  75. "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
  76. },
  77. "method": "GET",
  78. "credentials": 'include'
  79. }).then(e => e.text()).then(call)
  80. }
  81. function getStatus(ds, dt) {
  82. let s = new Date(ds), t = new Date(dt), e = new Date();
  83. console.log(s, t, e)
  84. if (e < s) return '未开始'
  85. if (e < t) return '进行中'
  86. else return '已结束'
  87. }
  88. function adminStuff() {
  89. // $('.box-contest').append('<input type="date" id="start" min="2022-01-01">')
  90. }
  91. function contestSubmit() {
  92. fetch('contest/touch', {
  93. headers: { 'Content-type': 'application/json' },
  94. method: "POST",
  95. credentials: 'include',
  96. body: JSON.stringify({
  97. no: $('#tNo').val(),
  98. title: $('#tTitle').val(),
  99. description: $('#tDescription').val(),
  100. dates: new Date($('#tStart')[0].valueAsNumber).toUTCString(),
  101. datet: new Date($('#tEnd')[0].valueAsNumber).toUTCString()
  102. }),
  103. }).then(e => e.json()).then(e => {
  104. if (e.no) alert('您无权进行此操作')
  105. else {
  106. $('.tSend').addClass('glyphicon-success')
  107. setTimeout(() => $('.tSend').removeClass('glyphicon-success'), 1000)
  108. debug('TOUCH', 'affected ' + e.affectedRows + ' rows')
  109. }
  110. })
  111. }
  112. function postLogin() {
  113. debug('LOGIN DONE.', 'initiate fetching.')
  114. if (status != 1) return;
  115. if (!user) user = getCookie('gosh'), pwd = getCookie('gowd')
  116. document.cookie = "gosh=" + user + ";path=/score/;expires=Fri, 05 Feb 2077 12:34:56 GMT";
  117. document.cookie = "gosh=" + user + ";path=/sso/;expires=Fri, 05 Feb 2077 12:34:56 GMT";
  118. document.cookie = "gowd=" + pwd + ";path=/sso/;expires=Fri, 05 Feb 2077 12:34:56 GMT";
  119. if (getCookie('moe')[0] == '!') $('#user').text('admin')
  120. else get('bxn-portal/portal/api/proxy?username=true&userId=true&needvalidate=true&t=http%3A%2F%2F202.94.10.118%2Fbxn-library%2Fapi%2Flibrary%2FgetLatestBorrowBook%3Fcategory%3D1&resourceId=103519&cache=nocache&systime=0', e => {
  121. e = JSON.parse(e)
  122. $('#user').text(e.requestParams[0].ownerName)
  123. oid = e.requestParams[0].ownerId
  124. })
  125. gget('contest', e => {
  126. e = JSON.parse(e)
  127. $('#contest').empty()
  128. for (let i = 0; i < e.length; i++) {
  129. $('#contest').append(`\
  130. <li id="contest-${e[i].id}">\
  131. <span onclick="$(this).toggleClass('active').siblings('div').toggle(300)" class="title">第 ${e[i].no} 届${e[i].title}\
  132. <span class="pull-right" style="color:#999">${e[i].id} - ${getStatus(e[i].dates, e[i].datet)}</span>\
  133. </span>
  134. <div style="display:none">${e[i].description}</div>\
  135. </li>`)
  136. }
  137. })
  138. if (getCookie('moe')[0] == '!') adminStuff()
  139. }
  140. function debug(e, str = '') {
  141. $('.debugList').append(`<li class="auto-warp"><b>${e}</b> ${str} <span class="pull-right" style="color:#999">${status}</span></li>`)
  142. }
  143. function login() {
  144. debug('LOGIN.')
  145. if (status == 1) return;
  146. delCookies()
  147. user = $('#loginId').val(), pwd = $('#loginPwd').val()
  148. return fetch(root + "sso/login", {
  149. headers: {
  150. "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
  151. // "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"
  152. },
  153. method: "GET",
  154. mode: "cors",
  155. credentials: 'include'
  156. }).then(() => {
  157. return fetch('https://43.143.233.184/moelogin', {
  158. method: 'POST',
  159. headers: { 'Content-type': 'application/json' },
  160. body: JSON.stringify({
  161. user: user,
  162. pwd: pwd,
  163. cook: getCookie('JSESSIONID')
  164. }),
  165. credentials: 'include',
  166. })
  167. }).then(e => e.text()).then(e => { setStatus((e != 'success') + 1), Promise.resolve() })
  168. }
  169. function matches(e) {
  170. return e.match(/(^\[\]$|param":"|<tr>|DOCTYPE|in\?username=|requestParams|\"newmessage\"|Sorry, Page Not Found|北师大实验中学--登录)/s)
  171. }
  172. // 异步递归嘿嘿嘿,再多 302 也不怕;再加上回调函数,真是妙
  173. async function next(e, call, ac, login) {
  174. if (e.length < 3000 && !matches(e) && (!e.match('\/login\\?') || login)) {
  175. return fetch(getUrl(e), {
  176. method: 'GET',
  177. credentials: 'include',
  178. headers: {
  179. Accept: ac
  180. }
  181. }).then(e => e.text()).then(res => { next(res, call, ac, login) })
  182. }
  183. else return call(e), new Promise((resolve, reject) => { })
  184. }
  185. function pre(e, url, call) {
  186. if (e.match('北师大实验中学--登录')) {
  187. debug('OUTDATED CAS! NEED RELOGIN')
  188. delCookie('CASTGC', '/')
  189. tryLogin()
  190. }
  191. if (e.length < 3000 && e.match('\/login\\?')) {
  192. var name = url.split('/')[0], f = paused.filter(e => e.name == name)
  193. debug('FAILED', url)
  194. if (url.match('\/login\\?')) return
  195. if (f.length) f[0].arr.push(url), f[0].carr.push(call)
  196. else {
  197. paused.push({ name: name, arr: [url], carr: [call] })
  198. debug('GET COOKIE...')
  199. get(name + '/casfailed.jsp', () => {
  200. let f = paused.filter(e => e.name == name)[0]
  201. for (let i = 0; i < f.arr.length; i++)get(f.arr[i], f.carr[i])
  202. paused.splice(paused.indexOf(f), 1)
  203. }, '*/*', 1)
  204. }
  205. } else {
  206. $('#bxn' + url.split('bxn')[1].split(/(\/|%2F)/)[0]).addClass('bg-success').addClass('text-success')
  207. if (status == 1) call(e)
  208. }
  209. }
  210. function get(url, call = () => { }, ac = '*/*', login = 0) {
  211. if (getCookie('moe')[0] == '!') return
  212. console.log("GET", url)
  213. debug('GET', url)
  214. if (status != 1) return
  215. next(root + url, e => { pre(e, url, call); }, ac, login)
  216. }
  217. let trying = 0
  218. function tryLogin() {
  219. if (trying) return debug('LOGIN', 'already in progress.')
  220. if (getCookie('moe')[0] == '!') {
  221. debug('LOGIN', 'admin!')
  222. setStatus(1), postLogin()
  223. } else if (getCookie('CASTGC')) {
  224. debug('LOGIN', 'using CAS.')
  225. setStatus(1), postLogin()
  226. } else if (getCookie('gosh') && getCookie('gosh') != 'null' && getCookie('gowd') != 'null') {
  227. debug('LOGIN', 'using stored cookie.')
  228. setStatus(0)
  229. trying = 1
  230. $('#loginId').val(getCookie('gosh'))
  231. $('#loginPwd').val(getCookie('gowd'))
  232. login().then(() => { status == 2 ? setStatus(0, 1) : (trying = 0, postLogin()); })
  233. } else debug('LOGIN', 'no available method.'), setStatus(0, 1)
  234. }
  235. $().ready(() => {
  236. $('.e').addClass('reqLogin')
  237. $('.e').removeClass('e')
  238. tryLogin()
  239. $("[data-toggle='tooltip']").tooltip();
  240. $('.banner').text('庆祝 moe 建站 ' + Math.ceil((new Date().getTime() - 1676000714191) / 86400000) + ' 天')
  241. })
  242. </script>
  243. <style>
  244. .pass {
  245. font-weight: bold;
  246. font-family: 'Courier New', Courier, monospace;
  247. }
  248. li {
  249. border-bottom: 3px solid #eee;
  250. word-wrap: break-word;
  251. }
  252. li>.title {
  253. transition-duration: 300ms;
  254. display: inline-block;
  255. width: 100%;
  256. cursor: pointer;
  257. font-size: 18px
  258. }
  259. li>.active.title {
  260. font-size: 22px;
  261. font-weight: bold;
  262. }
  263. li>.active+div {
  264. background-image: linear-gradient(to right, #fffaf0, #f4f2ef);
  265. border-left: 3px solid #ccc;
  266. padding-left: 5px;
  267. }
  268. li:hover {
  269. background-color: #eee;
  270. }
  271. .box {
  272. transition-duration: 300ms;
  273. min-height: 210px;
  274. }
  275. .box::before {
  276. content: '';
  277. display: block;
  278. width: 100%;
  279. height: 3px;
  280. margin-top: 10px;
  281. border-bottom: 1px solid;
  282. border-image: linear-gradient(to right, transparent, #6aaad8, #75ddb6, transparent) 1;
  283. }
  284. .box:hover::before {
  285. border-bottom: 3px solid;
  286. border-image: linear-gradient(to right, transparent, #6aaad8, #75ddb6, transparent) 1;
  287. }
  288. .box:hover {
  289. background-image: linear-gradient(#faffef, transparent);
  290. }
  291. .page-header.nohr {
  292. margin-bottom: 0;
  293. border-bottom: none;
  294. }
  295. span.full {
  296. width: 100%;
  297. display: inline-block;
  298. cursor: pointer;
  299. }
  300. .breadcrumb {
  301. padding: 0;
  302. margin-bottom: 5px;
  303. }
  304. .auto-warp {
  305. word-wrap: break-word;
  306. word-break: break-all;
  307. overflow: hidden;
  308. transition-duration: 500ms;
  309. max-height: 22.4px;
  310. }
  311. .auto-warp:hover {
  312. max-height: 100px;
  313. }
  314. </style>
  315. </head>
  316. <body>
  317. <div class="page-header nohr">
  318. <h2>
  319. <!-- <img src="RC.png" width="32px" style="position:relative;top:-4px"> -->
  320. 实萌
  321. </h2>
  322. <span id="loginSt" class="label label-default">未登录</span>
  323. <span id="user" class="label label-default">-</span>
  324. <button class="btn btn-danger btn-xs e" onclick="postLogin()" title="刷新数据">
  325. <span class="glyphicon glyphicon-refresh"></span>
  326. </button>
  327. <button class="btn btn-danger btn-xs e" onclick="delCookies(1);setStatus(0)" onmouseenter="$('#double-off').css('scale','100%')" onmouseleave="$('#double-off').css('scale','0')" title="退出登录">
  328. <span class="glyphicon glyphicon-log-out"></span>
  329. </button>
  330. <button id="double-off" class="btn btn-danger btn-xs e" onclick="delCookies(2);location.reload()" onmouseenter="$('#double-off').css('scale','100%')" onmouseleave="$('#double-off').css('scale','0')" style="scale:0;transition-duration: 1000ms;" data-toggle="tooltip" data-placement="right" title="全部重置">
  331. <span class="glyphicon glyphicon-off"></span>
  332. </button>
  333. <button class="btn btn-danger btn-xs login" onclick="delCookies(2);location.reload()" data-toggle="tooltip" data-placement="right" title="全部重置">
  334. <span class="glyphicon glyphicon-off"></span>
  335. </button>
  336. </div>
  337. <div class="col-sm-12 e box box-contest">
  338. <div class="page-header">
  339. <h3><span class="glyphicon glyphicon-user"></span> 比赛列表
  340. </h3>
  341. </div>
  342. <ul id="contest" class="list-unstyled"></ul>
  343. <button class="btn btn-default" onclick="$('.contestNew').toggle(300)">新建比赛 <span class="glyphicon glyphicon-plus"></span></button>
  344. <div class="contestNew">
  345. <div class="col-md-4">
  346. 标题
  347. <div class="input-group">
  348. <div class="input-group-addon">第</div>
  349. <input id="tNo" class="form-control" placeholder="0">
  350. <div class="input-group-addon">届</div>
  351. <input id="tTitle" class="form-control" placeholder="测试赛">
  352. </div>
  353. </div>
  354. <div class="col-md-4">
  355. 开始时间
  356. <input class="form-control" type="date" id="tStart" min="2022-01-01" value="2023-02-10">
  357. </div>
  358. <div class="col-md-4">
  359. 结束时间
  360. <input class="form-control" type="date" id="tEnd" min="2022-01-01" value="2023-02-10">
  361. </div>
  362. <div class="col-sm-12" style="margin-top: 10px;">
  363. <textarea id="tDescription" class="form-control" placeholder="介绍" style="resize: vertical"></textarea>
  364. <button class="btn btn-default" onclick="contestSubmit()" style="margin-top: 10px;">提交 <span class="glyphicon glyphicon-send tSend"></span></button>
  365. </div>
  366. </div>
  367. </div>
  368. <div class="col-md-4 col-sm-6 box">
  369. <div class="page-header">
  370. <h3><span class="glyphicon glyphicon-user"></span> 账号
  371. <ul class="btn-group breadcrumb debug" style="display: none;font-size:10px;top:5px">
  372. <li id="bxn-portal" onclick="get('bxn-portal/portal/osforstudent/index')">bxn-portal</li>
  373. <li id="bxn-core-uic" onclick="get('bxn-core-uic/uic/index')">bxn-core-uic</li>
  374. <li id="bxn-library" onclick="get('bxn-library/library/jumpExamreport?jumpUrl=')">bxn-library</li>
  375. <li id="bxn-office" onclick="get('bxn-office/mail/index')">bxn-office</li>
  376. </ul>
  377. </h3>
  378. </div>
  379. <button class="btn btn-default e" onclick="$('.debug').toggle(200)">debug</button>
  380. <div class="login">
  381. <br>
  382. <div class="input-group">
  383. <span class="input-group-addon">账号</span>
  384. <input id="loginId" type="id" class="pass form-control" placeholder="20222222">
  385. </div>
  386. <br>
  387. <div class="input-group">
  388. <span class="input-group-addon">密码</span>
  389. <input id="loginPwd" type="password" class="pass form-control" placeholder="password">
  390. <span class="input-group-btn">
  391. <button class="btn btn-default" type="button" onclick="login().then(postLogin)">
  392. <span class="glyphicon glyphicon-log-out"></span> 登录
  393. </button>
  394. </span>
  395. </div>
  396. </div>
  397. <div class="debug" style="display: none;">
  398. <button class="btn btn-default btn-xs" onclick="$('.debugList').empty()"><span class="glyphicon glyphicon-trash"></span> 清除</button>
  399. <ul class="debugList list-unstyled" style="font-family: 'Courier New', Courier, monospace;"></ul>
  400. </div>
  401. </div>
  402. <div style="position:fixed;bottom:10px;left:10px;color:#ccc">
  403. 北师大实验中学
  404. </div>
  405. <div style="position:fixed;bottom:10px;right:10px;color:#ccc" class="banner"></div>
  406. </body>