PCR图书馆辅助计算器

辅助计算PCR手游的所需体力,总次数

  1. /* eslint-disable require-jsdoc */
  2.  
  3. // ==UserScript==
  4. // @name PCR图书馆辅助计算器
  5. // @namespace http://tampermonkey.net/
  6.  
  7. // @version 3.1.6
  8. // @description 辅助计算PCR手游的所需体力,总次数
  9. // @author winrey,colin,hymbz
  10. // @license MIT
  11. // @icon https://pcredivewiki.tw/static/images/unit/icon_unit_108831.png
  12. // @supportURL https://github.com/winrey/pcr-wiki-helper/issues
  13. // @homepage https://github.com/winrey/pcr-wiki-helper
  14. // @run-at document-start
  15. // @connect cdn.jsdelivr.net
  16. // @match *://pcredivewiki.tw/*
  17. // @grant unsafeWindow
  18. // @grant GM_getValue
  19. // @grant GM_setValue
  20. // @grant GM_info
  21. // @grant GM.getValue
  22. // @grant GM.setClipboard
  23. // @grant GM.setValue
  24. // @grant GM.deleteValue
  25. // @grant GM.info
  26. // @grant GM_addStyle
  27. // @require https://cdn.jsdelivr.net/npm/jquery@3.4.0/dist/jquery.min.js
  28. // @require https://cdn.jsdelivr.net/gh/winrey/pcr-wiki-helper@eea66a67d2a0f3794d905fd6447b66329dc34d2e/js/solver.js
  29. // @require https://cdn.jsdelivr.net/gh/winrey/pcr-wiki-helper@21de4a7a288c0cdf5d3cea248eee31301d36c105/js/html2canvas.min.js
  30. // ==/UserScript==
  31.  
  32. (function() {
  33. 'use strict';
  34.  
  35. const sleep = (time) => new Promise((r) => setTimeout(r, time));
  36.  
  37. $(document).ready(function() {
  38. GM_addStyle(`
  39. .helper--calc-result-cell.helper--show-deleted-btn::after {
  40. content: '\u2716';
  41. position: absolute;
  42. bottom: 70px;
  43. background-color: #ff0000;
  44. color: #fff;
  45. line-height: 0.9rem;
  46. border-radius: 30%;
  47. padding: 3px;
  48. opacity: 50%;
  49. cursor: pointer;
  50. z-index: 10000;
  51. }
  52. .helper--calc-result-cell.helper--show-deleted-btn.multiSelect-no::after {
  53. content: '\u00A0\u00A0\u00A0';
  54. }
  55. .helper--calc-result-cell.helper--show-deleted-btn.multiSelect-yes::after {
  56. content: '\u2714';
  57. }
  58. .Unique.helper-cell.mapDrop-item.mr-2.p-2.text-center{
  59. background-color: rgba(255,193,7,.5);
  60. border-radius: 0.7vw;
  61. }
  62. table.table-bordered.mapDrop-table.helper .result-cell-td{
  63. vertical-align: middle;
  64. text-align: justify;
  65. text-align-last: justify;
  66. }
  67. .topToView{
  68. z-index: 96000;
  69. white-space: break-spaces;
  70. }
  71. div.ClpMeue{
  72. visibility: hidden;
  73. transition: all 0.3s;
  74. position: relative;
  75. top: 3rem;
  76. opacity:0;
  77. max-width: 0px;
  78. }
  79. button#toImage {
  80. position: absolute;
  81. font-size: 0.2375rem;
  82. padding: 0.075rem 0.05rem;
  83. bottom: 4.4rem;
  84.  
  85. }
  86. button#toText{
  87. position: absolute;
  88. font-size: 0.2375rem;
  89. padding: 0.075rem 0.05rem;
  90. bottom: 2.8rem;
  91. }
  92. div.ClpMeue.active{
  93. visibility: visible;
  94. display: inline-block;
  95. opacity:1;
  96. }
  97.  
  98. .mapDrop-table .helper-oddTri {
  99. right: .3rem;
  100. top: 1.6rem;
  101. color: black;
  102. }
  103. .mapDrop-table .mapDrop-item {
  104. max-width: 106px;
  105. }
  106. .mapDrop-table .helper--calc-result-cell{
  107. width: 70px;
  108. height: 70px;
  109. margin: 0 auto;
  110. position: relative;
  111. }
  112. .mapDrop-table .helper--calc-result-cell.un--wanted{
  113. opacity: 0.4;
  114. }
  115. .mapDrop-table .helper-block {
  116. top: 1.6rem;
  117. right: .12rem;
  118. }
  119. #helper--bottom-btn-group {
  120. position: fixed;
  121. right: calc(60px + 1% - 2px);
  122. bottom: 90px;
  123. overflow: visible;
  124. display: flex;
  125. flex-wrap: wrap;
  126. flex-direction: column;
  127. }
  128. .helper--nav-to-level.helper--important::after {
  129. content: "独";
  130. color: #e60c0c;
  131. font-size: .5em;
  132. position: relative;
  133. top: -0.8em;
  134. right: 1em;
  135. }
  136. span.dropsProgress.hide{
  137. display: none;
  138. }
  139. #helper--modal-content:not(.helper--drop) input[item-name], #helper--modal-content:not(.helper--drop) input[orig-item-name] {
  140. display: none;
  141. }
  142. #helper--modal-content input[item-name], #helper--modal-content input[orig-item-name]{
  143. width: 6em;
  144. }
  145. a.singleSelect{
  146. display: none
  147. }
  148. a.singleSelect.ready{
  149. display: inline
  150. }
  151. .switch-multiSelectBtnState {
  152. display: none;
  153. width: 70px;
  154. height: 32px;
  155. border: solid 2px #ddd;
  156. border-radius: 30px;
  157. background-color: #FFF;
  158. position: relative;
  159. padding-left: 2.6rem;
  160. -webkit-transition: background-color 0.3s;
  161. transition: background-color 0.3s;
  162. -webkit-user-select: none;
  163. font-size: 14px;
  164. left: 5.1rem;
  165. }
  166. .switch-multiSelectBtnState.ready {
  167. display: inline;
  168. }
  169. .switch-handler.ready{
  170. display: inline-block;
  171. }
  172. .switch-multiSelectBtnState.selected-completedBtn{
  173. pointer-events: none;
  174. }
  175. .switch-multiSelectBtnState::before {
  176. right: 4rem;
  177. content: '多选';
  178. position: absolute;
  179. width: 2rem;
  180. font-size: 15px;
  181. top: -0.1rem;
  182. margin-right: -1rem;
  183. transition: width 0s 0s,margin-right .3s ,top 0.3s,content 0s 1s;
  184. }
  185. .switch-multiSelectBtnState.active.selected-completedBtn::before {
  186. right: 3rem;
  187. content: '已选完成';
  188. font-size: 14px;
  189. top: -0.08rem;
  190. margin-right: 0rem;
  191. border-radius: 11%;
  192. width: 4rem;
  193. border: 2px outset #f5d68e;
  194. pointer-events: all;
  195. line-height: 15.9px;
  196. transition: box-shadow 0.3s
  197. }
  198. .switch-multiSelectBtnState.selected-completedBtn:hover::before {
  199. box-shadow: -0.7px 1px 5.1px #000;
  200. }
  201. .switch-handler {
  202. position: relative;
  203. left: 2.5rem;
  204. top: 0.25rem;
  205. width: 1rem;
  206. height: 1rem;
  207. background-color: #FFF;
  208. border-radius: 100% 100%;
  209. -webkit-box-shadow: 1px 2px 5px rgba(0, 0, 0, 0.52);
  210. box-shadow: 1px 2px 5px rgba(0, 0, 0, 0.52);
  211. -webkit-transition: all 0.3s;
  212. transition: all 0.3s;
  213. display: none;
  214. }
  215. .switch-multiSelectBtnState.active {
  216. border-color: #4cd964;
  217. background-color: #4cd964;
  218. }
  219. .switch-handler.ready.active {
  220. left: 3.9rem;
  221. }
  222. .switch-handler::after {
  223. color: #000000;
  224. content: '关';
  225. position: relative;
  226. bottom: 0.25rem;
  227. left: -0.6rem;
  228. padding-left: 1rem;
  229. -webkit-transition: color .3s 0.1s;
  230. }
  231. .switch-handler.active::after {
  232. content: ' ';
  233. color: #fff0;
  234. position: relative;
  235. left: -4rem;
  236. }
  237. .switch-handler.active::before {
  238. content: '开';
  239. color: #f5f5f5;
  240. right: 1.4rem;
  241. padding-right: 1.4rem;
  242. }
  243. .switch-handler::before {
  244. content: '\u00A0\u00A0\u00A0';
  245. color: #fff0;
  246. width: 2.6rem;
  247. bottom: 0.2rem;
  248. -webkit-transition: color .3s .1s;
  249. position: relative;
  250. }
  251. .form-control.active{
  252. transition:border linear .2s,box-shadow linear .5s;
  253. -moz-transition:border linear .2s,-moz-box-shadow linear .5s;
  254. -webkit-transition:border linear .2s,-webkit-box-shadow linear .5s;
  255. outline:none;
  256. border-color: rgba(12, 255, 0, 0.75);
  257. box-shadow:0 0 8px rgba(59, 224, 9, 0.75);
  258. -moz-box-shadow:0 0 8px rgba(93,149,242,.5);
  259. -webkit-box-shadow:0 0 8px rgba(93,149,242,3);
  260. }
  261. `);
  262. /**
  263. * @global
  264. * @namespace onceItemchange
  265. * @type {object[]}
  266. * @property {string} onceItemchange[].id - 碎片id.
  267. * @property {number} onceItemchange[].count - 碎片数量.
  268. */
  269.  
  270. const onceItemchange = [];
  271. let vue;
  272. /**
  273. * 点击“存储队伍”按钮
  274. */
  275.  
  276. const saveTeamData = () => {
  277. // findOnePCRelem(`.sticky-top>button.pcbtn.primary`, '儲存隊伍').click();
  278. vue.saveTeam();
  279. const d = document.querySelector('a[href="##"]');
  280. d && d.click();
  281. };
  282. /**
  283. * 自动切换到地图掉落模式
  284. *
  285. */
  286. async function autoSwitch2MapList() {
  287. vue = document.querySelector('div.container').__vue__;
  288. // findOnePCRelem(`.armory-function.p-1.pb-3>button`, '地圖掉落模式').click();
  289. vue.isLoading = true;
  290. await sleep(20);
  291. vue.changeDisplayMode(3);
  292. vue.pageSize = 1000;
  293. await sleep(1000);
  294. }
  295. // eslint-disable-next-line require-jsdoc
  296. function toPage(num) {
  297. const $table = $('.mapDrop-table:not(.helper)');
  298. const $pages = $($table.find('tr').toArray().pop());
  299. const $frist = $($pages.find('li').toArray()[num || 1]);
  300. $frist.children()[0].click();
  301. }
  302. async function getMapData() {
  303. function rowParser($tr, page, index) {
  304. function parseItem($item) {
  305. const url = $($item.find('a')[0]).attr('href');
  306. const name = $($item.find('img')[0]).attr('title');
  307. const img = $($item.find('img')[0]).attr('src');
  308. const odd = parseInt($($item.find('h6.dropOdd')[0]).text()) / 100; // %不算在parseInt内
  309. const count = parseInt(
  310. (!/無需|溢/.test($($item.find('.py-1')[0]).text()) &&
  311. $($item.find('.py-1')[0]).text()) ||
  312. 0,
  313. );
  314. const id = /\d+/.exec(img)[0];
  315. return {url, name, img, odd, count, id};
  316. }
  317. const children = $tr.children().map(function() {
  318. return $(this);
  319. });
  320. const name = children[0].text();
  321. const requirement = parseInt(children[1].text());
  322. const items = $(children[2].children()[0])
  323. .children()
  324. .toArray()
  325. .map((v) => parseItem($(v)));
  326. return {name: name, requirement: requirement, items: items, page: page, index: index};
  327. }
  328. function next($table) {
  329. const $pages = $($table.find('tr').toArray().pop());
  330. const $next = $($pages.find('li').toArray().pop());
  331. if ($next.hasClass('disabled')) return false;
  332. $next.children()[0].click();
  333. return true;
  334. }
  335. let $table = $('.mapDrop-table:not(.helper)');
  336. const data = [];
  337. toPage(1);
  338. let page = 1;
  339. await sleep(20);
  340. do {
  341. await sleep(20);
  342. $table = $('.mapDrop-table:not(.helper)');
  343. // 判断简易计算
  344. const start = $table.find('thead>tr').length;
  345. let pageData = $table.find('tbody>tr');
  346. const dataTd = $table.find('tbody>td');
  347. pageData = pageData.toArray().map($);
  348. pageData = pageData.slice(0, -1); // 最后一行是分页栏
  349. if (start === 1) {
  350. pageData = pageData.slice(start, -1); // 最后一行是分页栏
  351. } else {
  352. // pageData = pageData
  353. // .filter(function (i, v) { return v !== this && v % 2 === 0 || false }.bind(pageData.length - 1)) //结果过滤偶数 //edit "Comments "by cool_delete
  354. const paeD = (_i, v) => ~~/建議:\s(\d+)/.exec($(dataTd.get(v)).text())[1]; // 结果过滤0数
  355.  
  356. pageData = pageData.filter(paeD);
  357. }
  358. pageData = pageData.map((m, i) => rowParser(m, page, i));
  359. data.push.apply(data, pageData);
  360. page += 1;
  361. } while (next($table));
  362. toPage(1);
  363. return data;
  364. }
  365. function getCost(name) {
  366. if (name === '1-1') return 6;
  367. if (name.startsWith('1-')) return 8;
  368. if (name.startsWith('2-')) return 8;
  369. if (name.startsWith('3-')) return 8;
  370. if (name.startsWith('4-')) return 9;
  371. if (name.startsWith('5-')) return 9;
  372. if (name.startsWith('6-')) return 9;
  373. return 10;
  374. }
  375. function calcResult(data) {
  376. data = data.map((chan) => {
  377. const sum = (...arr) => [].concat(...arr).reduce((acc, val) => acc + val, 0);
  378. chan.exception = sum(chan.items.map((v) => v.count * v.odd));
  379. chan.max = Math.max.apply(
  380. null,
  381. chan.items.map((v) => v.count / v.odd),
  382. );
  383. chan.min = Math.min.apply(
  384. null,
  385. chan.items.filter((v) => v.count).map((v) => v.count / v.odd),
  386. );
  387. chan.effective = sum.apply(
  388. null,
  389. chan.items.map((v) => (v.count ? v.odd : 0)),
  390. );
  391. return chan;
  392. });
  393. const model = {
  394. optimize: 'cost',
  395. opType: 'min',
  396. constraints: (() => {
  397. const equis = {};
  398. data.forEach((c) => c.items.forEach((e) => (equis[e.name] = {min: e.count})));
  399. return equis;
  400. })(),
  401. variables: (() => {
  402. const challs = {};
  403. data.forEach((c) => {
  404. const cMap = {};
  405. c.items.forEach((item) => (cMap[item.name] = item.odd));
  406. cMap.cost = getCost(c.name);
  407. challs[c.name] = cMap;
  408. });
  409. return challs;
  410. })(),
  411. };
  412. console.log('model', model);
  413. const lp_result = solver.Solve(model);
  414. console.log(lp_result);
  415. for (const k in lp_result) {
  416. if (!k.includes('-')) continue;
  417. const target = data.find((c) => c.name === k);
  418. if (target) target.times = lp_result[k] || 0;
  419. }
  420. return {
  421. total: lp_result.result,
  422. map: data.sort((a, b) => b.times - a.times).sort((a, b) => b.effective - a.effective),
  423. };
  424. }
  425.  
  426. const BOUNS_KEY = '___bouns';
  427.  
  428. function askBouns() {
  429. const bouns =
  430. parseInt(
  431. prompt('请输入目前倍数(N3或N2,非活动期可取消)').split('').reverse().join('') || '1',
  432. ) || 1;
  433. sessionStorage.setItem(BOUNS_KEY, bouns);
  434. return bouns;
  435. }
  436. function getBouns() {
  437. let bouns = parseInt(sessionStorage.getItem('___bouns'));
  438. if (!bouns) {
  439. bouns = askBouns();
  440. }
  441. return bouns;
  442. }
  443. function showResult(data) {
  444. const bouns = getBouns();
  445. const table = genTable(data.map.filter((m) => m.times));
  446. const comment = $.parseHTML('<a href>说明</a>');
  447. const commentLines = [];
  448. commentLines.push(
  449. '推荐使用方法:按照列表顺序刷图,数量不要超过「适用」和「推荐」两者的最小值,完成后修改数量,重新根据新情景计算。',
  450. );
  451. commentLines.push('');
  452. commentLines.push(
  453. '注意:如果您尚缺好感,可考虑以30体/次为倍数单位扫荡刷图,能最大化获取发情蛋糕。',
  454. );
  455. commentLines.push('');
  456. commentLines.push('---表头说明---');
  457. commentLines.push(
  458. '『章节』关卡编号。点击编号可以自动跳转到图书馆原表中关卡详细介绍。点击『章节』能切换排序',
  459. );
  460. commentLines.push(
  461. '『独』标识。代表当前结果中仅有该图能出的装备碎片。赶进度的话刷满黄色碎片数。',
  462. );
  463. commentLines.push('『需求』关卡需求。图中所需装备总数。');
  464. commentLines.push('『效率』装备效率。图中所有有效装备掉落的概率和。');
  465. commentLines.push('『适用』有效次数。预计能保持「效率」不变的次数。');
  466. commentLines.push(
  467. '『推荐』推荐次数。假设概率固定,由考虑体力的线性规划算法计算出的总最优刷图次数。',
  468. );
  469. commentLines.push('『最大』最大次数。最近该图需要的最高次数。');
  470. $(comment[0]).click((e) => {
  471. tips('说明', commentLines.join('\n'));
  472. e.preventDefault();
  473. e.stopPropagation();
  474. });
  475. const quickModifyBtn = $.parseHTML(`<a href="##" style='margin-left: 1rem;'>快速修改</a>`);
  476. $(quickModifyBtn[0]).click(async () => {
  477. const modifyState = !document.querySelector('.singleSelect.ready');
  478. [...document.querySelectorAll('span.dropsProgress')].reduce(
  479. (t, i) => i.classList.toggle('hide', modifyState),
  480. document.querySelector('span.dropsProgress'),
  481. );
  482. // 点击快速修改 如果找不到输入框就没法设置
  483. vue.showFastStock();
  484. document.querySelector('#popBox.modal.fade.show') &&
  485. document.querySelector('#popBox.modal.fade.show').click();
  486. document
  487. .getElementById('helper--modal-content')
  488. .classList.toggle('helper--drop', modifyState);
  489. deleteItem(modifyState);
  490. modifyState &&
  491. document
  492. .querySelector('span.switch-multiSelectBtnState')
  493. .addEventListener(`click`, multiItemChange);
  494. modifyState &&
  495. document.querySelector('span.switch-handler').addEventListener(`click`, (e) => {
  496. multiSelectState(
  497. switchMultBtnState(
  498. 'active',
  499. !document.querySelector('span.switch-multiSelectBtnState.active'),
  500. ),
  501. );
  502. e.stopImmediatePropagation();
  503. });
  504. modifyState &&
  505. (document.querySelector('.singleSelect.ready').parentElement.scrollLeft = 3000);
  506. return false;
  507. });
  508. const reCalcBtn = $.parseHTML(
  509. `<a href class=singleSelect style='margin-left: 1rem;'title='修改所有装备后 点击自动保存和计算'>重新计算</a>`,
  510. );
  511. const multipleBtn = $.parseHTML(
  512. `<span class=switch-multiSelectBtnState title='切换后能快速满足碎片数'></span><span class="switch-handler"></span>`,
  513. );
  514. $(reCalcBtn[0]).click(() => {
  515. TranslateRefresh_the_interface();
  516. handleClickCalcBtn();
  517. return false;
  518. });
  519. showModalByDom(
  520. `总体力需求:${Math.round(
  521. data.total / bouns,
  522. )} &nbsp;&nbsp; 当前倍率:${bouns} &nbsp;&nbsp; `,
  523. comment,
  524. quickModifyBtn,
  525. reCalcBtn,
  526. multipleBtn,
  527. table,
  528. );
  529. }
  530. function createModal(...content) {
  531. const containerStyle = `
  532. top: 0;
  533. left: 0;
  534. width: 100%;
  535. height: 100%;
  536. position: fixed;
  537. z-index: 10000;
  538. display: flex;
  539. align-items: center;
  540. justify-content: center;
  541. opacity: 0;
  542. pointer-events: none;
  543. transition: all ease-in-out 0.5s;
  544. `;
  545. const maskStyle = `
  546. top: 0;
  547. left: 0;
  548. width: 100%;
  549. height: 100%;
  550. background: rgba(0,0,0,0.7);
  551. position: absolute;
  552. z-index: 11000;
  553. `;
  554. const boxStyle = `
  555. min-width: 80%;
  556. z-index: 12000;
  557. `;
  558. const contentStyle = `
  559. width: 100%;
  560. margin-bottom: 10px;
  561. max-height: 80vh;
  562. overflow: scroll;
  563. `;
  564. const html = `
  565. <div id="helper--modal" style="${containerStyle}">
  566. <div id="helper--modal-mask" style="${maskStyle}"></div>
  567. <div class="breadcrumb" style="${boxStyle}">
  568. <div id="helper--modal-content" style="${contentStyle}">${content.join(
  569. '',
  570. )}</div>
  571. <button id="helper--modal-close" type="button" class="pcbtn mr-3"> 关闭 </button>
  572. <button id="helper--modal-Clipboard" type="button" class="pcbtn mr-3" title='导出到粘贴板'> >&#128203 </button>
  573. <div class = 'ClpMeue'>
  574. <button id="toText" type="button" class="pcbtn mr-3" title='导出全部数据'>全局</button>
  575. <button id="toImage" type="button" class="pcbtn mr-3" title='当前计算结果的截图'>截图</button></div>
  576. </div>
  577. </div>
  578. `;
  579. $('#app').after(html);
  580. $('#helper--modal-close').click(() => hideModal());
  581. $('#helper--modal-mask').click(() => hideModal());
  582. $('#helper--modal-Clipboard').click(showToClpMeue);
  583. $('button#toText').click(() => {
  584. return showToClpMeue(), txtToClipboard();
  585. });
  586. $('button#toImage').click(() => {
  587. return showToClpMeue(), clpSetImage();
  588. });
  589. }
  590. const showToClpMeue = () => {
  591. document.querySelector('div.ClpMeue').classList.toggle('active');
  592. };
  593. function genItemsGroup(items) {
  594. items = boundLocatStrong(items); // ${item.Unique?`唯一`:``}
  595.  
  596. const html = `
  597. <div class="d-flex flex-nowrap justify-content-center">
  598. ${items
  599. .map(
  600. (item) => `
  601. <div class="p-2 text-center mapDrop-item mr-2 helper-cell ${item.Unique && 'Unique' || ''
  602.  
  603. } ${(!item.count && `un--wanted`) || ''
  604. }">
  605. <div class='helper--calc-result-cell ${(!item.count && `un--wanted`) || ''
  606. }'
  607. onclick
  608. ${`data-item-count=${item.count}`}
  609. data-item_id=${item.id}
  610. data-item_name=${item.name}
  611. title="满足了"
  612. >
  613. <a
  614. href="${item.url}"
  615. class=""
  616. target="_blank"
  617. >
  618. <img
  619. width="70"
  620. title="${item.name + ` `}${(item.information && item.information) || ``
  621. }${(item.Unique && ` 该图限定`) || ``}"
  622. src="${item.img}"
  623. class="aligncenter"
  624. >
  625. <span class="oddTri helper-oddTri">
  626. <i class="dropOdd text-center helper-block ">
  627. ${Math.round(item.odd * 100)}%</i></span>
  628. </a>
  629. </div>
  630. <span class="text-center py-1 d-block"
  631. ${!item.count && `style="opacity:0.4"`}
  632. title="${item.information}"
  633. data-total-need=${item.count}
  634. > ${(item.count && `总需` + item.count) || `已满`} </span>
  635. <span><input type="number" class="form-control" item-name="${item.name
  636. }" value="${item.has || 0
  637. }"title="边框需要变荧光绿才算保存成功" onclick="this.select()"></span>
  638. <span><input type="number" class="form-control" orig-item-name="${item.name
  639. }" placeholder="增量" title="适用合成单次刷图 可每次输入掉落数量,回车确认并跳转下个物品"></span>
  640. <span class= 'dropsProgress ${(item.count && ' ') || 'hide'} '>进度:${item.has || 0
  641. }</span>
  642. </div>
  643. `,
  644. )
  645. .join('')}
  646. </div>
  647. `;
  648. return html;
  649. }
  650. function boundLocatStrong(items) {
  651. for (const item of items) {
  652. try {
  653. const p = ~~new RegExp('"equipment_id":' + item.id + ',"count":([^,]+),')
  654. .exec(localStorage.itemList)[1]
  655. .replace(/^\"|\"$/g, '');
  656. item.information = `有` + p + ' 缺' + item.count;
  657. item.has = p;
  658. } catch (e) {
  659. item.count = 0;
  660. }
  661. }
  662. return items;
  663. }
  664. const changeItemCount = (e) => {
  665. // 快速完成
  666. const singleItem = () => {
  667. const $this = $(e.target);
  668. const count = $this[0].dataset.itemCount;
  669. if (!count) return;
  670. const ID = $this[0].dataset.item_id;
  671. const name = $this[0].dataset.item_name;
  672. if (confirm(`${name}的数量达到了${count}。页面刷新后自动计算`)) {
  673. itemCountChage(ID, count);
  674. GM.setValue(`mount`, `(()=>{ setTimeout(handleClickCalcBtn,2000) })()`);
  675. location.reload();
  676. }
  677. };
  678. const multiItem = () => {
  679. e.target.classList.toggle(
  680. `multiSelect-yes`,
  681. !(e.target.classList[e.target.classList.length - 1] == `multiSelect-yes`),
  682. );
  683. const cls = document.querySelector('.switch-multiSelectBtnState').classList;
  684. cls.toggle(
  685. `selected-completedBtn`,
  686. document.querySelectorAll('.multiSelect-yes').length != 0,
  687. );
  688. };
  689. (e.target.classList[e.target.classList.length - 1] == `helper--show-deleted-btn` &&
  690. !singleItem()) ||
  691. multiItem();
  692. };
  693. const multiItemChange = () => {
  694. const cell = document.querySelectorAll('.multiSelect-yes');
  695. if (
  696. cell.length &&
  697. confirm(`你目前选了${cell.length}个装备,开始修改,点击确定刷新页面自动计算`)
  698. ) {
  699. for (const dom of [...cell]) {
  700. itemCountChage(dom.dataset.itemId, dom.dataset.itemCount);
  701. }
  702. GM.setValue(`mount`, `(()=>{ setTimeout(handleClickCalcBtn,2000) })()`);
  703. location.reload();
  704. }
  705. };
  706. function itemCountChage(equipment_id, count) {
  707. const p = new RegExp('"equipment_id":' + equipment_id + ',"count":([^,]+)', 'g');
  708. const t = new RegExp(`\\d+`, 'g');
  709. localStorage.setItem(
  710. `itemList`,
  711. localStorage.itemList.replace(p, (match, p1) => {
  712. return match.substr(0, 30) + p1.replace(t, count); // match[match.length-1]match.length-3
  713. }),
  714. );
  715. }
  716. function uniqueItem(mapData) {
  717. const itmes = [];
  718. for (let i = 0; i < mapData.length; i++) {
  719. itmes.push(...mapData[i].items);
  720. }
  721. for (const t of itmes) {
  722. itmes[t.name] = (itmes[t.name] && itmes[t.name] + 1) || 1;
  723. }
  724. for (let i = 0; i < mapData.length; i++) {
  725. for (const item of mapData[i].items) {
  726. if (item.count > 0 && itmes[item.name] < 2) {
  727. mapData[i].IsuniqueItem = true;
  728. item.Unique = true;
  729. }
  730. }
  731. }
  732. }
  733. function sortColumn(e) {
  734. // -1>a,b 1>b,a//greedy
  735. const trList = [...e.target.closest('table').querySelectorAll(`tbody>tr`)];
  736. const greedy = () => {
  737. trList
  738. .sort((a) => {
  739. return (~~a.dataset.isUniqueItem && -1) || (~~a.dataset.isUniqueItem && 1) || 0;
  740. })
  741. .sort((a, b) => {
  742. return (
  743. (~~a.dataset.isUniqueItem &&
  744. ~~b.dataset.isUniqueItem &&
  745. ~~b.children[2].dataset.dropEffective - ~~a.children[2].dataset.dropEffective) ||
  746. 0
  747. );
  748. });
  749. return 1;
  750. };
  751. const dropEffective = () => {
  752. trList.sort((a, b) => {
  753. return ~~b.children[2].dataset.dropEffective - ~~a.children[2].dataset.dropEffective || 0;
  754. });
  755. return 0;
  756. };
  757. e.target.dataset.sortType = (!~~e.target.dataset.sortType && greedy()) || dropEffective(); // 切换状态保存
  758. const tbody = e.target.closest('table').querySelector('tbody');
  759. tbody.innerHTML = '';
  760. for (const t of trList) {
  761. tbody.appendChild(t);
  762. }
  763. }
  764. async function txtToClipboard() {
  765. const 数据条目 = '20'; // (条)
  766. const trList = [
  767. ...document.querySelectorAll(
  768. `table.table.table-bordered.mapDrop-table.helper>tbody tr:nth-child(-n+${数据条目})`,
  769. ),
  770. ];
  771. const howMuchSpace = (sum = 12, a = []) => {
  772. return sum < 1 && (sum = 0), (a.length = sum), a.fill(space, 0, sum).join(``);
  773. };
  774. const surroundedByaBar = (text, Rows = 6, horizontal = text.length + 8) => {
  775. Rows = (Rows & 1 && Rows) || Rows + 1; // only odd
  776. let str = enter;
  777. const blank = (horizontal - text.length) / 2;
  778. const half = Math.ceil(Rows / 2);
  779. for (let i = 1; i <= Rows; i++) {
  780. str += '|';
  781. for (let k = 0; k < horizontal; k++) {
  782. ((Rows === i || 1 === i) && (str += '-')) || i === half || (str += ' ');
  783. // 中间行k已到居中文本位置
  784. i === half &&
  785. ((blank <= k &&
  786. k < blank + text.length - 2 &&
  787. ((k = text.length + blank - 1), (str += text))) ||
  788. (str += ' '));
  789. }
  790. str += '|' + enter;
  791. }
  792. str.substr(0, str.length - 2);
  793. return str;
  794. };
  795. const space = ' ';
  796. const enter = '\r\n';
  797. let text = `\u200E ${howMuchSpace(3)}章节${howMuchSpace(6)}效率${howMuchSpace(
  798. 6,
  799. )}各效率${enter}`;
  800. for (const t of trList) {
  801. text += howMuchSpace(5);
  802. for (let b = 1; b < 9; b += 2) {
  803. const lent = t.childNodes[b].innerText.length;
  804. text += t.childNodes[b].innerText + howMuchSpace(10 - lent);
  805. }
  806. text = text.trim();
  807. text += enter;
  808. }
  809. // 设置dom移除监听 负责在生成链接后设置粘贴板
  810.  
  811. vue.isLoading = true;
  812.  
  813.  
  814. const toClip=async () => {
  815. GM.setClipboard(
  816. `7天内打开链接,装备、角色数据完整保留,但将于${((d) => `${d.getMonth() + 1}月${d.getDate()}号`)(
  817. new Date(new Date().getTime() + 7 * 86400000),
  818. )}失效!${enter}请尽快打开链接:${surroundedByaBar(
  819. vue.exportNotice || 'network error,copy Text below',
  820. )}${enter}${howMuchSpace(4)}${enter}${howMuchSpace(
  821. 4,
  822. )}并点击储存队伍${enter}${enter}${enter}${howMuchSpace(
  823. 4,
  824. )}如果链接失效,可复制""(不含引号)内的字符"到文字汇入队伍的输入框${enter}"${vue.zipMyTeam()}"`,
  825. );
  826. tips('备份成功', '复制完成,请尽快拷贝到其他地方保存');
  827. };
  828. backupTream(toClip);
  829. }
  830. function backupTream(callback) {
  831. const uuid = vue.uuid();
  832. const armory = _.concat([vue.teamList], [vue.itemList]);
  833. let teamList = JSON.stringify(armory);
  834. teamList = vue.b64EncodeUnicode(teamList);
  835. const url = '/static/php/mysqlAdd.php';
  836. const data = {teamList: teamList, uuid: uuid};
  837. $.ajax({
  838. type: 'POST',
  839. url: url,
  840. data: data,
  841. success: function(data) {
  842. const res = data.toString().trim();
  843. if (res == '200') {
  844. vue.isLoading = false;
  845. vue.exportNotice = 'https://pcredivewiki.tw/Armory?s=' + uuid;
  846. callback();
  847. }
  848. },
  849. });
  850. }
  851.  
  852. async function clpSetImage() {
  853. vue.isLoading = true;
  854. await sleep(200);
  855. const shareContent = document.querySelector(
  856. 'table.table.table-bordered.mapDrop-table.helper tbody',
  857. );
  858. const width = shareContent.offsetWidth;
  859. const height = shareContent.offsetHeight;
  860. const canvas = document.createElement('canvas');
  861. const scale = 1;
  862. canvas.width = width * scale;
  863. canvas.height = height * scale;
  864. const content = canvas.getContext('2d');
  865. content.scale(scale, scale);
  866. const opts = {
  867. scale: scale,
  868. width: width,
  869. height: height,
  870. canvas: canvas,
  871. allowTaint: true,
  872. width: width,
  873. heigth: height,
  874. y: window.pageYOffset + shareContent.getBoundingClientRect().top,
  875. }; // 局部元素带滚动时候 截图需要指定window的x,y 元素的getBoundingClientRect挺重要的
  876. html2canvas(shareContent, opts).then((canvas) => {
  877. const content = canvas.getContext('2d');
  878. content.mozImageSmoothingEnabled = false;
  879. content.webkitImageSmoothingEnabled = false;
  880. content.msImageSmoothingEnabled = false;
  881. content.ImgSmoothingEnabled = false;
  882. canvas.toBlob((blob) => {
  883. navigator.clipboard.write([new ClipboardItem({'image/png': blob})]);
  884. vue.isLoading = false;
  885. tips('图片复制成功', '复制完成,可直接复制到微信或qq。');
  886. });
  887. });
  888. }
  889. const deleteItem = (switchOn) => {
  890. switchMultBtnState(`ready`, switchOn);
  891. for (const i of $('table .p-2.text-center.mapDrop-item.mr-2>div.helper--calc-result-cell')) {
  892. (~~i.dataset.itemCount && switchOn && !!$(i).addClass('helper--show-deleted-btn')) ||
  893. $(i).removeClass('helper--show-deleted-btn');
  894. }
  895. !switchOn && multiSelectState();
  896. };
  897. const switchMultBtnState = (cls, switchOn = false) => {
  898. const state = ['ready', 'active', 'selected-completedBtn'];
  899. !switchOn &&
  900. cls == state[1] &&
  901. document.querySelector('a.singleSelect').classList.toggle(state[0], !switchOn);
  902. if (
  903. !switchOn &&
  904. cls == state[0] &&
  905. !state.forEach((i) => {
  906. document.querySelector('span.switch-multiSelectBtnState').classList.toggle(i, switchOn);
  907. document.querySelector('span.switch-handler').classList.toggle(i, switchOn);
  908. document.querySelector('a.singleSelect').classList.toggle(i, switchOn);
  909. })
  910. ) {
  911. return switchOn;
  912. }
  913. if (
  914. !switchOn &&
  915. cls == (state.shift() && state)[0] &&
  916. !state.forEach((i) => {
  917. document.querySelector('span.switch-multiSelectBtnState').classList.toggle(i, switchOn);
  918. document.querySelector('span.switch-handler').classList.toggle(i, switchOn);
  919. })
  920. ) {
  921. return switchOn;
  922. }
  923. document.querySelector('span.switch-multiSelectBtnState').classList.toggle(cls, switchOn);
  924. document.querySelector('span.switch-handler').classList.toggle(cls, switchOn);
  925. switchOn && cls == state[1] ?
  926. document.querySelector('a.singleSelect').classList.toggle(state[0], !switchOn) :
  927. document.querySelector('a.singleSelect').classList.toggle(state[0], switchOn);
  928. return switchOn;
  929. };
  930. const multiSelectState = (switchOn = false) => {
  931. for (const i of $('table .p-2.text-center.mapDrop-item.mr-2>div.helper--calc-result-cell')) {
  932. const c = ~~i.dataset.itemCount;
  933. c && i.classList.toggle('multiSelect-no', switchOn);
  934. c && !switchOn && i.classList.toggle('multiSelect-yes', switchOn);
  935. }
  936. };
  937. const toDetailsTheMap = (map) => {
  938. const genUri = () => {
  939. /* 日后地图更新
  940. 打开https://pcredivewiki.tw/Map 打开控制台按下Exc 在console中输入
  941. ` $$('.btn.btn-info.p-3')
  942. .map(el => (el.innerText.replace(/\d+\./,'')+'N'))
  943. .reduce((sum, value) =>{return sum .push(value),sum},[]).join('","')
  944. `
  945. 不含反引号 输出后模仿格式(注意前后引号!!)复制到下面maps中
  946. */
  947. console.log(`如果地图更新的话看我,点右边的超链接`);
  948. const levelsForMapUir = new Map();
  949. const maps = [
  950. '朱諾平原N',
  951. '帕拉斯高原N',
  952. '赫柏丘陵N',
  953. '維斯塔溪谷N',
  954. '刻瑞斯森林N',
  955. '佛洛拉湖畔N',
  956. '墨提斯大瀑布N',
  957. '伊麗絲樹海N',
  958. '弗麗嘉雪原N',
  959. '洛麗泰海岸N',
  960. '蓋奴亞荒漠N',
  961. '波諾尼亞砂丘N',
  962. '朵羅西亞溼地N',
  963. '尤金尼亞熱地N',
  964. '塔利亞火山N',
  965. '泰美斯銀嶺N',
  966. '菲得斯冰原N',
  967. '法艾頓草原N',
  968. '法艾頓草原‧南部N',
  969. '卡斯塔利亞樹林‧西部N',
  970. '卡斯塔利亞樹林‧東部N',
  971. '馬提爾德岩峰‧南部N',
  972. '馬提爾德岩峰‧北部N',
  973. '雷蒂烏斯群峰‧西麓N',
  974. '雷蒂烏斯群峰‧東麓N',
  975. '佩特羅大森林‧西部N',
  976. '佩特羅大森林‧東部N',
  977. '迪茲塔爾河蝕岸‧北部N',
  978. '迪茲塔爾河蝕岸‧南部N',
  979. '弗泰拉斷崖‧北部N',
  980. '弗泰拉斷崖‧南部N',
  981. '法斯奇亞森林‧南部N',
  982. '法斯奇亞森林‧東部N',
  983. '迪克斯提亞岩崖‧西壁N',
  984. '迪克斯提亞岩崖‧東壁N',
  985. '維娜湖畔道‧南部N',
  986. '維娜湖畔道‧北部N',
  987. '拉圖斯斷崖‧南部N',
  988. '拉圖斯斷崖‧北部N',
  989. 'スカプ山系・西麓N',
  990. 'スカプ山系・東麓N',
  991. 'ペクトス氷峰・西壁N',
  992. 'ペクトス氷峰・東壁N',
  993. ];
  994. let i = 1;
  995. for (const m of maps) {
  996. levelsForMapUir.set(i, `https://pcredivewiki.tw/Map/Detail/${encodeURI(m)}`);
  997. i += 1;
  998. }
  999. return levelsForMapUir;
  1000. };
  1001. const mapIndex = map.split('-');
  1002. const p = mapIndex.shift() >> 0;
  1003. const d = genUri();
  1004. (d.has(p) && GM.setValue(`toMap`, mapIndex.shift() >> 0) && unsafeWindow.open(d.get(p))) ||
  1005. alert(
  1006. `地图可能更新了,请按下F12 ,再按下Esc,找到‘如果地图更新的话看我,点右边的超链接’字样,按提示修改脚本`,
  1007. );
  1008. };
  1009. function genTable(mapData) {
  1010. uniqueItem(mapData);
  1011. const bouns = getBouns(); //
  1012. const html = `
  1013. <table width="1000px" class="table table-bordered mapDrop-table helper">
  1014. <thead>
  1015. <th style="min-width: 71px; vertical-align: baseline;cursor: pointer;" data-sort-type='0' title='点击可转换成贪心排序'>章节</th>
  1016. <th style="min-width: 67px; vertical-align: baseline;">效率</th>
  1017. <th style="min-width: 67px; vertical-align: baseline;">各次数</th>
  1018. <th> 掉落一覽 </th>
  1019. </thead>
  1020. <tbody>
  1021. ${mapData.map((m) => `
  1022. <tr data-is-unique-item=${(m.IsuniqueItem && 1) || 0}>
  1023. <td class='result-cell-td'>
  1024. <a href="#" class="helper--nav-to-level ${m.IsuniqueItem && 'helper--important'}" data-pag:e="${m.page}" data-index="${m.index
  1025. }" title="查看对手阵容">
  1026. ${m.name}
  1027. </a>
  1028. </td>
  1029. <td data-drop-effective=${Math.round(
  1030. m.effective * 100,
  1031. )} class='result-cell-td'> ${Math.round(m.effective * 100)}% </td>
  1032. <td>适用<br/>
  1033. &nbsp;&nbsp;&nbsp;&nbsp;${Math.ceil(m.min / bouns)}<br/>
  1034. 推荐<br/>
  1035. &nbsp;&nbsp;&nbsp;&nbsp;${Math.ceil(m.times / bouns)}<br/>
  1036. 最大<br/>
  1037. &nbsp;&nbsp;&nbsp;&nbsp;${Math.ceil(m.max / bouns)} </td>
  1038. <td align="center">
  1039. ${genItemsGroup(m.items)}
  1040. </td>
  1041. </tr>
  1042. `).join('')}
  1043. </tbody>
  1044. </table>
  1045. `.trim();
  1046. const table = $.parseHTML(html).pop(); // 0是一堆逗号,我也不造这是什么鬼
  1047. $(table)
  1048. .find('a.helper--nav-to-level')
  1049. .click(function(e) {
  1050. const $this = $(e.currentTarget);
  1051. // hideModal();
  1052. toDetailsTheMap($this.text());
  1053. /*
  1054. setTimeout(() => {
  1055. const $table = $(".mapDrop-table:not(.helper)");
  1056. const elem = $table.find("tr")[index];
  1057. elem.scrollIntoView({
  1058. behavior: "smooth",
  1059. block: "center",
  1060. inline: "center",
  1061. })
  1062. }, 200)
  1063. */
  1064. });
  1065. $(table)
  1066. .find('.p-2.text-center.mapDrop-item.mr-2>div.helper--calc-result-cell')
  1067. .click(changeItemCount);
  1068.  
  1069. const inputEntry = async (e) => {
  1070. // 只有回车触发更改
  1071. if (e.type !== 'blur' && e.keyCode != 13) {
  1072. return;
  1073. }
  1074. if (isWanted(e)) {
  1075. const itemName = e.target.getAttribute('item-name');
  1076. const id = e.target.parentElement.parentElement.children[0].dataset.item_id;
  1077. const newNum = e.srcElement.valueAsNumber;
  1078. // 通过图书馆的快速修改功能来进行库存的修改
  1079. // const inputDoms=[...document.querySelectorAll(`#app table img[title="${itemName}"]`)]
  1080. // const Refresh_the_interface = () => {
  1081. // let i=inputDoms.shift().closest('div').querySelector('input')
  1082. // i.valueAsNumber = newNum;
  1083. // inputDoms.length&&
  1084. // window.requestAnimationFrame(Refresh_the_interface)||
  1085. // i.dispatchEvent(new KeyboardEvent("keyup", { key: "Enter", keyCode: 13 }))
  1086. // };
  1087. // window.requestAnimationFrame(Refresh_the_interface)
  1088. // 卡顿原因自pcr的vue计算dom挤在一个宏任务了 无法优化
  1089.  
  1090. singleFragmentGlobalSave(id, newNum);
  1091. e.target.classList.toggle('active', 1);
  1092. // 在修改库存后,修改结果页的库存显示
  1093. // table.querySelectorAll(`input[item-name=${itemName}]`).forEach(dom => {
  1094. // })
  1095. // 在输入掉落数时同步所有相同装备下的 input 的 value
  1096. const c = [...table.querySelectorAll(`input[item-name=${itemName}]`)];
  1097. c.reduce((t, i) => {
  1098. i.value = newNum;
  1099. const itemSpanDom = i.closest('div').querySelector('span.text-center');
  1100. const totalNeed = itemSpanDom.getAttribute('data-total-need');
  1101. itemSpanDom.innerText = newNum < totalNeed ? `总需${totalNeed}` :(i.closest('div').classList.toggle('un--wanted', true), i.closest('div').querySelector('div').classList.toggle('un--wanted', true), '已满');
  1102. itemSpanDom.setAttribute('title', `有${newNum} ${Math.max(totalNeed - newNum, 0)}`);
  1103. i.closest('div')
  1104. .querySelector('img')
  1105. .setAttribute('title', `有${newNum} ${Math.max(totalNeed - newNum, 0)}`);
  1106. i.closest('div').querySelector('span.dropsProgress').innerText = `进度:${newNum}`;
  1107. }, c[0]);
  1108. }
  1109.  
  1110. // 如有下个物品,跳转焦点
  1111. jump(e);
  1112. };
  1113. const fnChanged = _.debounce(inputEntry, 300);
  1114. table.querySelectorAll('input[item-name]').forEach((inputDom) => {
  1115. inputDom.addEventListener('input', fnChanged);
  1116. inputDom.addEventListener('keyup', fnChanged);
  1117. inputDom.addEventListener('blur', inputEntry);
  1118. });
  1119. const deltaInputEntry = async (e) => {
  1120. // 只有回车触发更改
  1121. if (e.keyCode != 13) {
  1122. return;
  1123. }
  1124. // 修改上方总数量并触发修改事件 -> delegate to inputEntry()
  1125. const delta = +e.srcElement.value;
  1126. const origInputDom = e.target.closest('div').querySelector('input[item-name]');
  1127. origInputDom.value = +origInputDom.value + delta;
  1128. origInputDom.dispatchEvent(new KeyboardEvent('keyup', {key: 'Enter', keyCode: 13}));
  1129. e.target.value = '';
  1130. };
  1131. table.querySelectorAll('input[orig-item-name]').forEach((inputDom) => {
  1132. inputDom.addEventListener('input', _.debounce(deltaInputEntry, 500));
  1133. inputDom.addEventListener('keyup', _.debounce(deltaInputEntry, 500));
  1134. inputDom.addEventListener('blur', deltaInputEntry);
  1135. });
  1136. const isWanted = (e) => !e.target
  1137. .closest('div')
  1138. .classList.contains('un--wanted');
  1139. const jump = (e) => {
  1140. const nextItemDiv = e.target.closest('div').nextElementSibling &&
  1141. e.target
  1142. .closest('div')
  1143. .nextElementSibling.querySelector('div')
  1144. .classList.contains('un--wanted') && e.target.closest('div').nextElementSibling;
  1145. if (nextItemDiv) {
  1146. nextItemDiv
  1147. .querySelector('input[orig-item-name]')
  1148. .dispatchEvent(new KeyboardEvent('keyup', {key: 'Enter', keyCode: 13}));
  1149. } else {
  1150. (e.target.closest('div').nextElementSibling &&
  1151. !e.target
  1152. .closest('div')
  1153. .nextElementSibling.querySelector('input[orig-item-name]')
  1154. .focus()) ||
  1155. e.target.closest('tr').querySelector('div').querySelector('div:not(.un--wanted)').querySelector('input[orig-item-name]').focus();
  1156. }
  1157. return nextItemDiv;
  1158. };
  1159. return table;
  1160. }
  1161. function singleFragmentGlobalSave(id, newNum) {
  1162. // 直接存到local,vue中关闭再处理
  1163. itemCountChage(id, newNum);
  1164. onceItemchange.push({id: id, count: newNum});
  1165. }
  1166. async function hideModal() {
  1167. document.querySelector('#popBox.modal.fade.show') &&
  1168. document.querySelector('#popBox.modal.fade.show').click();
  1169. $('#helper--modal').css('opacity', 0);
  1170. $('#helper--modal').css('pointer-events', 'none');
  1171. window.requestAnimationFrame(Refresh_the_interface);
  1172. }
  1173. const Refresh_the_interface = () => {
  1174. const i = onceItemchange.shift();
  1175. i && vue.changeStock(i.count, i.id);
  1176. onceItemchange.length && window.requestAnimationFrame(Refresh_the_interface);
  1177. };
  1178. const TranslateRefresh_the_interface = () => {
  1179. const i = onceItemchange.shift();
  1180. i && vue.changeStock(i.count, i.id);
  1181. onceItemchange.length && TranslateRefresh_the_interface();
  1182. };
  1183. function showModal(...content) {
  1184. $('#helper--modal').css('opacity', 1);
  1185. $('#helper--modal').css('pointer-events', '');
  1186. if (content && content.length) {
  1187. debugger;
  1188. $('#helper--modal-content').html(content.join(''));
  1189. }
  1190. }
  1191.  
  1192. async function showModalByDom(...dom) {
  1193. $('#helper--modal').css('opacity', 1);
  1194. $('#helper--modal').css('pointer-events', '');
  1195. if (dom.length) {
  1196. $('#helper--modal-content').html('');
  1197. for (const i in dom) $('#helper--modal-content').append(dom[i]);
  1198. }
  1199. document
  1200. .querySelector('table.table.table-bordered.mapDrop-table.helper th')
  1201. .addEventListener(`click`, sortColumn);
  1202. }
  1203.  
  1204. async function handleClickCalcBtn() {
  1205. await autoSwitch2MapList();
  1206. await sleep(300);
  1207. saveTeamData();
  1208. // 自动调整至旧版数量
  1209. // const tempDom = document.querySelector('button[title="設計圖數量為舊版數量"]');
  1210. // if(![...tempDom.classList].includes('active'))
  1211. // tempDom.click();
  1212. // await sleep(100);
  1213. document.getElementById('helper--modal-content').classList.remove('helper--drop');
  1214. // if (selectNumInOnePage() != '1000') {
  1215. // selectNumInOnePage(1000);
  1216. // }
  1217. await sleep(100);
  1218. const data = await getMapData();
  1219. console.log('data', data);
  1220. const result = calcResult(data);
  1221. console.log('result', result);
  1222. showResult(result);
  1223. vue.pageSize = 10;
  1224. vue.isLoading = false;
  1225. document.querySelector('#popBox.modal.fade.show') &&
  1226. document.querySelector('#popBox.modal.fade.show').click(),
  1227. changeBtnGroup();
  1228. }
  1229.  
  1230. async function handleFastModifyBtn() {
  1231. const $table = $('.mapDrop-table:not(.helper)');
  1232. if ($table && $table.find('thead button').length) {
  1233. $table.find('thead button')[0].click();
  1234. } else {
  1235. alert('现在还不是地图掉落页面呢~');
  1236. }
  1237. }
  1238. function btnFactory(content, colorRotate, onClick) {
  1239. const btn = $.parseHTML(`
  1240. <div class="armory-function" style="padding: 0; padding-top: 1vh; overflow: visible; filter: hue-rotate(${colorRotate}deg);">
  1241. <button class="pcbtn primary" style="border-radius: 50%;"> ${content} </button>
  1242. </div>
  1243. `);
  1244. $(btn).click(onClick);
  1245. return btn;
  1246. }
  1247. function tips(title, text) {
  1248. vue.copyText('errrcolin');
  1249. vue.popMsg.title = title;
  1250. vue.popMsg.content = text;
  1251. const options = {
  1252. attributes: true,
  1253. attributeFilter: ['class'],
  1254. };
  1255. $('div#popBox')[0].classList.toggle('topToView', 1);
  1256. const mb = new MutationObserver(function(mutationRecord, observer) {
  1257. if (mutationRecord[0].target.classList.contains('show')) return;
  1258. observer.disconnect();
  1259. $('div#popBox')[0].classList.toggle('topToView', 0);
  1260. });
  1261. mb.observe($('div#popBox')[0], options);
  1262. $('div#popBox button').focus();
  1263. }
  1264. function createBtnGroup() {
  1265. const group = $.parseHTML(`
  1266. <div id="helper--bottom-btn-group" class="scroll-fixed-bottom"></div>
  1267. `);
  1268. const fastModifyBtn = btnFactory('快速<br>修改', 270, handleFastModifyBtn);
  1269. const bounsBtn = btnFactory('修改<br>倍数', 180, askBouns);
  1270. const calcBtn = btnFactory('计算<br>结果', 90, handleClickCalcBtn);
  1271. $(group).append(calcBtn);
  1272. $(group).append(fastModifyBtn);
  1273. $(group).append(bounsBtn);
  1274. $('#app .container').append(group);
  1275. }
  1276. function changeBtnGroup() {
  1277. const group = $('#helper--bottom-btn-group');
  1278. group.html('');
  1279. const fastModifyBtn = btnFactory('快速<br>修改', 188, handleFastModifyBtn);
  1280. const bounsBtn = btnFactory('修改<br>倍数', 216, askBouns);
  1281. const lastResultBtn = btnFactory('上次<br>结果', 144, () => showModal());
  1282. const calcBtn = btnFactory('重新<br>计算', 72, handleClickCalcBtn);
  1283. group.append(calcBtn);
  1284. group.append(bounsBtn);
  1285. group.append(fastModifyBtn);
  1286. group.append(lastResultBtn);
  1287. }
  1288. function appendName(mapName) {
  1289. document.querySelector('nav.navbar.navbar-expand-md.navbar-dark.fixed-top').style.visibility =
  1290. 'hidden'; // 隐藏导航条
  1291. document.querySelector('.main>div').__vue__.showMonster(); // 显示魔物
  1292. const toName = (
  1293. name,
  1294. ElementFindByNameDotParent = document.querySelector('#H' + name.mapName).parentElement,
  1295. ) => {
  1296. ElementFindByNameDotParent.scrollIntoView({block: 'center'}),
  1297. (ElementFindByNameDotParent.style.border = '3px solid #db1f77');
  1298. };
  1299. [...document.querySelectorAll('.item-title')].forEach(
  1300. (ele) => (ele.id = 'H' + ele.outerText.split('-').pop()),
  1301. ); // 添加id方便toName
  1302. toName({mapName});
  1303. }
  1304. createBtnGroup();
  1305. createModal();
  1306. (async () => {
  1307. try {
  1308. const before = await GM.getValue('mount', 0);
  1309. const after = await GM.getValue('toMap', 0);
  1310. before && eval(before);
  1311. await sleep(2000);
  1312. unsafeWindow.location.href.includes('https://pcredivewiki.tw/Map/Detail') &&
  1313. after &&
  1314. appendName(after);
  1315. } catch (e) {
  1316. console.log(`错误: ` + e);
  1317. } finally {
  1318. await GM.deleteValue('mount');
  1319. await GM.deleteValue('toMap');
  1320. }
  1321. })();
  1322. });
  1323. })();