当前位置:   article > 正文

12306抢票JS脚本

js能不能写一个插件自动在12306抢票
  1. // ==UserScript==
  2. // @name 12306.CN 订票助手 For Firefox&Chrome
  3. // @namespace http://www.u-tide.com/fish/
  4. // @author iFish@FishLee.net <ifish@fishlee.net> http://www.fishlle.net/
  5. // @developer iFish
  6. // @contributor
  7. // @description 帮你订票的小助手 :-)
  8. // @match http://dynamic.12306.cn/otsweb/*
  9. // @match https://dynamic.12306.cn/otsweb/*
  10. // @match https://www.12306.cn/otsweb/*
  11. // @require http://lib.sinaapp.com/js/jquery/1.8.3/jquery.min.js
  12. // @icon http://www.12306.cn/mormhweb/images/favicon.ico
  13. // @run-at document-idle
  14. // @version 4.2.4
  15. // @updateURL http://www.fishlee.net/Service/Download.ashx/44/47/12306_ticket_helper.user.js
  16. // @supportURL http://www.fishlee.net/soft/44/
  17. // @homepage http://www.fishlee.net/soft/44/
  18. // @contributionURL https://me.alipay.com/imfish
  19. // @contributionAmount ¥5.00
  20. // ==/UserScript==
  21. //=======START=======
  22. var version = "4.2.4";
  23. var updates = [
  24. "修改自动预定和自动提交逻辑,提示排队人数过多时自动重试 (不过此类情况成功率不高,建议多做打算)",
  25. "修改自动提交的重试过程可以通过取消勾选『自动提交』来取消",
  26. "修正改签的自动提交会生成一个新的订单",
  27. "修正自动提交在出现网络错误时,可能会卡住的BUG"
  28. ];
  29. var faqUrl = "http://www.fishlee.net/soft/44/faq.html";
  30. //标记
  31. var utility_emabed = false;
  32. //#region -----------------UI界面--------------------------
  33. function initUIDisplay() {
  34. injectStyle();
  35. }
  36. /**
  37. * 将使用的样式加入到当前页面中
  38. */
  39. function injectStyle() {
  40. var s = document.createElement("style");
  41. s.id = "12306_ticket_helper";
  42. s.type = "text/css";
  43. s.textContent = ".fish_running, .fish_clock, .fish_error, .fish_ok {\
  44. line-height:20px;\
  45. text-indent:18px;\
  46. background-repeat:no-repeat;\
  47. background-position:2px 50%;\
  48. font-size:12px;\
  49. }\
  50. .fish_running{background-image:url(data:image/gif;base64,R0lGODlhEAAQALMPAHp6evf394qKiry8vJOTk83NzYKCgubm5t7e3qysrMXFxe7u7pubm7S0tKOjoyH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCAAPACwAAAAAEAAQAAAETPDJSau9NRDAgWxDYGmdZADCkQnlU7CCOA3oNgXsQG2FRhUAAoWDIU6MGeSDR0m4ghRa7JjIUXCogqQzpRxYhi2HILsOGuJxGcNuTyIAIfkECQgADwAsAAAAABAAEAAABGLwSXmMmjhLAQjSWDAYQHmAz8GVQPIESxZwggIYS0AIATYAvAdh8OIQJwRAQbJkdjAlUCA6KfU0VEmyGWgWnpNfcEAoAo6SmWtBUtCuk9gjwQKeQAeWYQAHIZICKBoKBncTEQAh+QQJCAAPACwAAAAAEAAQAAAEWvDJORejGCtQsgwDAQAGGWSHMK7jgAWq0CGj0VEDIJxPnvAU0a13eAQKrsnI81gqAZ6AUzIonA7JRwFAyAQSgCQsjCmUAIhjDEhlrQTFV+lMGLApWwUzw1jsIwAh+QQJCAAPACwAAAAAEAAQAAAETvDJSau9L4QaBgEAMWgEQh0CqALCZ0pBKhRSkYLvM7Ab/OGThoE2+QExyAdiuexhVglKwdCgqKKTGGBgBc00Np7VcVsJDpVo5ydyJt/wCAAh+QQJCAAPACwAAAAAEAAQAAAEWvDJSau9OAwCABnBtQhdCQjHlQhFWJBCOKWPLAXk8KQIkCwWBcAgMDw4Q5CkgOwohCVCYTIwdAgPolVhWSQAiN1jcLLVQrQbrBV4EcySA8l0Alo0yA8cw+9TIgAh+QQFCAAPACwAAAAAEAAQAAAEWvDJSau9WA4AyAhWMChPwXHCQRUGYARgKQBCzJxAQgXzIC2KFkc1MREoHMTAhwQ0Y5oBgkMhAAqUw8mgWGho0EcCx5DwaAUQrGXATg6zE7bwCQ2sAGZmz7dEAAA7); color: green;}\
  51. .fish_clock{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAG/SURBVHjapJM/S8NQFMVvpaVfoEKojWL9U3DLIqjoooJDu/sFmnQoiIujQz+Aix3a1FUQXIR2UFA6+WeRUhBprERroGTopg6lSeo7iY1pq4sNHPpy3+8c7n0v9XW7XRrl8SFAlmVvbYFpmynOJHzXKkwlphOmxx4oiiL5sbAsi1KpFOVyuWQwGMzEYjEuGo0Sx3E2qOu6oKqqoChKst1u7zO2wNifDrLZLNbJUCgkLy2vEM/zv7araRrd3lxTq9US2WshnU7TGDZM01zwBwKZxaVlCkd4MtmxQDXlyVbvHXtgwMIDrx3Q6XS2Z2bnufDEJJkWuWIt2/LWwICFxw0wDCM+PTPXB0K4IGiwDhYeeP3fHQjjXIQMq3/mev3J/l0fqIOFxxtAxi+fg/rsBOztSE7QVpwpQT2PN6Dy1mgIYX7KNZcvipQ5yA+Fosum1rA93jMo1R6q7oxX50Va20wMzd4TWHi8t3BSvb/T1bpz4qsbf5vBgIXHDWB3+vj58b5fPj9jc9fcex8U9sCAhcc7Au1mDgtN7VU8Oz7SL0un9PbyTBYzQVijhj0wYOFxP2VJkv71Z8rn807AKM+XAAMArp1CsEFrDIIAAAAASUVORK5CYII=); color: blue;}\
  52. .fish_error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJFSURBVHjapJO/T1pRFMe/Dx7ypEXri4lUGUhsHF40hODSpQ61cTH+2HSoZaF1dHSxpU7+Ca04NE7dyuBiapcuLFokTdD4A01awNdBSkAf8ut5zhUoxq3e5OS+nPv5nnvuyfdJpmniPksSBd68aM1pFDMU4xS+ei5GsUHxmSLRJD9+hcx7rVqFZWwMtc3NIGy2Zam31yX19ABdXTdgNuszdd1nptNBlMtviQ0TC0ujg1LgGWNByelctQ4M4G8qhfN4HLmDA6HvpJzq9eJRXx+qlDPz+deUDrd9+i6KoFouazVg2erx4M/uLn5FItGLk5NX/qUliYO+I2o2C4vLBWaYZQ1rRYFyqTQDVXXl02mcb29HbXb7S+/CwjqKRSAaDXlHRqYwOoqdxUUww6zQNApUSqVxuaMDF8kk2hTlgxYIHMMwaHSxEB2/a4g7u7sjzDDLmn8dXF35ZJsNVWrzycTEOtxuYH//lpjWezqbZoZZ1rQ+AXyj3eEQO7a27oj9s7OhVkZoWjqIFXUdD1QVub29L3fEk5MhXF7y2RwzzLKmdQYb+UwGiqLwO6duiVdWxM2GrvfTfOaZYZY1TScmvE7NKsvf3B6PyzE8jB9ra6DJR2TTnBYXSNIcbfN021Mjl8Pv09OzaqXyXIvnE6LAT00RRlLa21cfk1kesgNpULBab5xITiUHokADzJDJioYhjDSUKNafUKlgaHAwXCCHJQ8Pz1JHRyhQm2RhEfzNOT5jhlnWNJ+w0y/918/kPzbrf+M91rUAAwCuQDz94e2kLwAAAABJRU5ErkJggg==); color: blue;}\
  53. .fish_ok{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHsSURBVHjapFNBSBtBFH2xgoqmKipEC6XkYqhUWXOxUAQhpyJ4Wgi0l0rNsdBbL/WgF2/eV8hNSBF68uhFkOrFhCAGS8mWgmYjG9lCKVGTuP1vsrvuIac68HZm/n/vz5/9fyKu6+IhI8IA5k4kbHsuSAsWBZpnKwh2BTlBySfGdTmcAX7kOJc5r5hfhyw7/86t21/EVVbgmjb6yPG4SqsyONtWGaz0Dk8aYzMf0R+b65ju3+oR7OImrp3vGdluJd646KKj1ZK0H0XXRqfeo390Emg6HUEfOeQqjQwVoNFAOvpkPjYw8kw2NRgfFtQchm8jh1xqggDNJhYHY3Jy41IhmXodrDvZyKWG2m4vA23gcR9wa6m7Jue1YO2PsI1casIB5GPBWM8ilZLyvFzu+BPNwyz29oDM5+W2JhSg8NsqaRSTMHycxfg4MDHRJlUqgCWHO/IvyRGu0gQB5D671Z+mlpiZFXEejjSInrw/OS4wjiWwNFx8ehZnRVNpwlXI/SrXqvbFOfS3TxWRAtNpwxfTRw651AQZSE1Lrfrd6mmhZky96IGejuJgX5rL9HpbrvBKbHbFxunJDa6F67e0X0YsLWHr6uouc/StXi3m/yCRkNTjbXBNG33kkEtN8Jh2Pv3fY9I3vLfwkPFPgAEApRUigcIVl3AAAAAASUVORK5CYII=); color: purple;}\
  54. .outerbox{border:5px solid #EAE3F7;}\
  55. .box{border:1px solid #6E41C2;color:#444;margin:auto;}\
  56. .box .title{padding:5px;line-height:20px;background-color:#B59DE2;color:#fff;}\
  57. .box .title a {color:white;}\
  58. .box .content{padding:5px;background-color:#fff;}\
  59. .box table{border-collapse:collapse; width:98%;}\
  60. .box table td{padding:5px;}\
  61. .box input[type=button],.fish_button {padding:5px;}\
  62. .box .name ,.box .caption,.box .caption td { background-color:#EAE3F7; font-weight:bold;-webkit-transition:all linear 0.2s;-moz-transition:all linear 0.2s;}\
  63. .fish_sep td {border-top:1px solid #A688DD;}\
  64. .lineButton { cursor:pointer; border: 1px solid green; border-radius:3px; font-size:12px; line-height: 16px; padding:3px; backround-color: lightgreen; color: green;-webkit-transition:all linear 0.2s;-moz-transition:all linear 0.2s;}\
  65. .lineButton:hover { color: white; background-color: green;-webkit-transition:all linear 0.1s;-moz-transition:all linear 0.1s; }\
  66. .fishTab {border: 5px solid #E5D9EC;font-size: 12px;}\
  67. .fishTab .innerTab {border-width: 1px;border-style: solid;border-color: #C7AED5;background-color: #fff;}\
  68. .fishTab .tabNav {font-weight:bold;color:#F5F1F8;background-color: #C7AED5;line-height:25px;overflow:hidden;margin:0px;padding:0px;}\
  69. .fishTab .tabNav li {float:left;list-style:none;cursor:pointer;padding-left: 20px;padding-right: 20px;}\
  70. .fishTab .tabNav li:hover {background-color:#DACAE3;}\
  71. .fishTab .tabNav li.current {background-color:#fff;color: #000;}\
  72. .fishTab .tabContent {padding:5px;display:none;}\
  73. .fishTab .tabContent p{margin:10px 0px 10px 0px;}\
  74. .fishTab div.current {display:block;}\
  75. .fishTab div.control {text-align:center;line-height:25px;background-color:#F0EAF4;}\
  76. .fishTab input[type=button] { padding: 5px; }\
  77. .hide {display:none;}\
  78. .fish_button {background-color:#7077DA;font-size:12px; font-family:微软雅黑; color:#fff; border: 1px solid #7077DA;margin-left:5px;margin-right:5px;-webkit-transition:all linear 0.2s;-moz-transition:all linear 0.2s;border-radius:3px;font-size:12px;}\
  79. .fish_button:hover{background:#fff;color:#7077DA;-webkit-transition:all linear 0.1s;-moz-transition:all linear 0.1s;cursor:pointer;}\
  80. tr.steps td{background-color:#E8B7C2!important;-webkit-transition:all linear 0.1s;-moz-transition:all linear 0.1s;}\
  81. tr.stepsok td{background-color:#BDE5BD!important;-webkit-transition:all linear 0.1s;-moz-transition:all linear 0.1s;}\
  82. tr.steps span.indicator {display:inline-block!important;}\
  83. tr.stepsok span.indicator {display:inline-block!important;}\
  84. .highlightrow td { background-color:#D0C0ED!important; color:red; }\
  85. #randCodeTxt{ font-weight: bold; font-size: 18px; text-align: center; padding: 3px 10px 3px 10px; font-family: verdana!important; text-transform: uppercase; }";
  86. document.head.appendChild(s);
  87. }
  88. function injectDom() {
  89. var html = [];
  90. html.push('<div id="fishOption" style="width: 600px; display:none; box-shadow: 7px 7px 10px #A67EBC;">');
  91. html.push('<div class="innerTab">');
  92. html.push('<ul class="tabNav" default="tabVersion">');
  93. html.push('<li tab="tabLogin">常规设置</li>');
  94. html.push('<li tab="tabReg">注册</li>');
  95. html.push('<li tab="tabFaq">常见问题</li>');
  96. html.push('<li tab="tabVersion">版本信息</li>');
  97. html.push('<li tab="tabLog">运行日志</li>');
  98. html.push('<li tab="tabLoginIE">登录到IE</li>');//获取登录到IE的代码 Add By XPHelper
  99. html.push('</ul>');
  100. html.push('<div class="tabContent tabLogin">');
  101. html.push('<table>');
  102. html.push('<tr>');
  103. html.push('<td>重试时间 ');
  104. html.push('<td>');
  105. html.push('<td><input type="text" name="login.retryLimit" size="6" value="2000" />');
  106. html.push('(ms)</td>');
  107. html.push('<td>');
  108. html.push('</td>');
  109. html.push('<td></td>');
  110. html.push('</tr>');
  111. html.push('</table>');
  112. html.push('</div>');
  113. html.push('<div class="tabContent tabReg" style="text-indent: 20px">');
  114. html.push('<p>为了阻止地球人他喵地拿作者无偿奉献的助手去卖钱钱,请注册唷。<strong>完全免费申请</strong>。</p>');
  115. html.push('<p style="color: red;"> <strong style="font-size:16px;">啊嘞……看这里!本助手完全免费啊诸位大人!</strong>任何在第三方网站上出售的软件全他喵的是侵权出售啊!!看到的时候请亲务必记得退款退货打差评向青天大老爷举报啊!!</p>');
  116. html.push('<p style="color:purple;"> 回家是一个单纯而简单的心愿,希望我们不会变得太复杂……</p>');
  117. html.push('<p>任何版本之间,功能上没有任何区别,So……不要问作者万一资助的话会有神马新功能,木有的说…… (= ̄ω ̄=) </p>');
  118. html.push('<p class="registered" style="display:none;">很高兴认识你,,<strong>fishcn@foxmail.com</strong>,谢谢你的出现~~~~已注册版本:<strong>正式版</strong>【<a href="javascript:;" id="unReg">重新注册</a>】</p>');
  119. html.push('<table class="regTable" style="display:none;width:98%;">');
  120. html.push('<tr>');
  121. html.push('<td>请粘贴注册码 【<a href="http://www.fishlee.net/Apps/Cn12306/GetNormalRegKey?v=1" target="_blank" style="color:blue;font-weight:bold;text-decoration:underline;">戳我直接申请注册码啊!为什么你们舍不得戳我啊 ╮(╯▽╰)╭</a>】</td>');
  122. html.push('</tr><tr>');
  123. html.push('<td style="text-align:center;"><textarea id="regContent" style="width:98%; height:50px;"></textarea></td>');
  124. html.push('</tr><tr>');
  125. html.push('<td><input type="button" id="regButton" value="注册" /></td>');
  126. html.push('</tr>');
  127. html.push('</table>');
  128. html.push('</div>');
  129. html.push('<div class="tabContent tabVersion" style="text-indent: 20px">');
  130. html.push('<h4 style="font-size:18px; font-weight:bold; margin: 0px; line-height: 26px; border-bottom: 1px dotted #ccc;">12306 订票助手 <small>ver ' + window.helperVersion + '</small></h4>');
  131. html.push('<p> 12306 订票助手是一款用于订票的助手软件,嗯……看到这里相信你已经知道它支持神马浏览器了 =。=<strong>完全免费,无需付费使用,仅接受捐助。</strong> </p>');
  132. html.push('<p style="color: red;"> <strong style="font-size:16px;">啊嘞……看这里!本助手完全免费啊诸位大人!</strong>任何在第三方网站上出售的软件全他喵的是侵权出售啊!!看到的时候请亲务必记得退款退货打差评向青天大老爷举报啊!!</p>');
  133. html.push('<p style="color:purple;"> 回家是一个单纯而简单的心愿,希望我们不会变得太复杂……</p>');
  134. html.push('<p> 有很多朋友资助作者,正在木有暖气的南方饱受煎熬的作者感激涕零 ≥ω≤。<a href="http://www.fishlee.net/soft/44/donate.html" target="_blank">戳这里了解捐助详情</a>。 </p>');
  135. html.push('<p style="color: blue;"> <strong style="font-size:16px;">那个,诸位票贩子们,放过本助手吧!!不要害作者啊!!!你们都去用什么自动识别验证码的好啦!离贫道远点!!</strong> ╮(╯▽╰)╭ </p>');
  136. html.push('<p style="font-weight:bold;">当前版本更新内容</p>');
  137. html.push('<ol>');
  138. $.each(utility.getPref("updates").split('\t'), function (i, n) {
  139. html.push("<li style='padding-left:20px;list-style:disc inside;'>" + n + "</li>");
  140. });
  141. html.push('</ol>');
  142. html.push('</div>');
  143. html.push('<div class="tabContent tabFaq">');
  144. html.push('<table>');
  145. html.push('<tr>');
  146. html.push('<td colspan="4"> 你在订票过程中可能……会遇到各种问题,由于介个12306网站本身呢……木有没有任何介绍 ╮(╯▽╰)╭ ,所以老衲整理了相关问题,供客官参考。如果还有不明白的问题,加群讨论呗 (= ̄ω ̄=) 。 <br /><br />');
  147. html.push('1.放票非正点也,So在将近放票的时候,务必保持刷新状态哈,而且……当整点没有放票时,不要放弃继续刷新喔;<br />\
  148. 2.动车都是11点放票撒,切记切记;<br />\
  149. 3.第一波放票悲催地木有订到时,请耐心等待,因为现在放票有N多节点,随时会有票出来,晚很久才放票也正常,铁老大经常秀下限嘀;<br />\
  150. 4.如果您的车票很难买,请尽量发动你的七大姑八大姨神马的一堆朋友过来集体帮忙,同时建议用多个浏览器刷票,因为缓存的关系不同的浏览器出现票的时间可能不同;<br />\
  151. 5.最新版3.9.0中的预先选择铺位功能有点淡化了……要用的话,使用优选席别,第一个优选的将会被自动选中 ^_^<br />\
  152. <br />\
  153. 好了,废话说完鸟,祝大家买票顺利,贫僧只希望不会帮倒忙就好了 ╮(╯▽╰)╭<br />\
  154. 如果您还有问题的话,<a href="http://www.fishlee.net/soft/44/tour.html" target="_blank">建议点击这里查看教程~~~~</a>\
  155. ');
  156. html.push('</td></tr>');
  157. html.push('<tr style="display:none;">');
  158. html.push('<td><a href="http://www.fishlee.net/soft/44/12306faq.html" target="_blank">订票常见问题</a></td>');
  159. html.push('<td><a href="http://www.fishlee.net/soft/44/faq.html" target="_blank">助手运行常见问题</a></td>');
  160. html.push('</tr>');
  161. html.push('</table>');
  162. html.push('</div><div class="tabLog tabContent"><div>下面是当前页面的记录。如果您的助手遇到功能上的问题,请全部复制后发成邮件给作者:ifish@fishlee.net 以便于老衲解决问题。<span style="color:red;font-weight:bold;">请在发送前务必剔除记录中包含的个人隐私如密码等信息。</span></div><textarea id="runningLog" style="width:100%;height:200px;"></textarea></div>');
  163. //获取登录到IE的代码 Add By XPHelper
  164. html.push('<div class="tabLoginIE tabContent"><div><strong>先在IE中打开 https://dynamic.12306.cn/otsweb,</strong>再将以下代码复制到IE浏览器的地址栏。确认地址栏最前面有“javascript:”字样,没有请手动加上(IE10会自动删除这样的代码),然后敲回车,等待页面刷新后,即可自动登录。</div><textarea id="LoginIECode" style="width:100%;height:200px;"></textarea></div>');
  165. html.push('<div class="control">');
  166. html.push('<input type="button" class="close_button" value="关闭" />');
  167. html.push('</div>');
  168. html.push('</div>');
  169. html.push('</div>');
  170. $("body").append(html.join(""));
  171. var opt = $("#fishOption");
  172. $("#regButton").click(function () {
  173. var sn = $.trim($("#regContent").val());
  174. var rt = utility.verifySn(false, "", sn);
  175. if (rt.result != 0) {
  176. alert("很抱歉, 注册失败. 代码 " + rt.result + ", " + rt.msg);
  177. } else {
  178. utility.setSnInfo("", sn);
  179. alert("注册成功, 请刷新浏览器。\n注册给 - " + rt.name + " , 注册类型 - " + rt.typeDesc.replace(/<[^>]*>/gi, ""));
  180. try {
  181. utility.getTopWindow().location.reload();
  182. } catch (e) {
  183. alert("权限不足无法刷新页面, 请手动刷新当前页!");
  184. }
  185. }
  186. });
  187. $("#unReg, a.reSignHelper").live("click", function () {
  188. if (!confirm("确定要重新注册吗?")) return;
  189. utility.setSnInfo("", "");
  190. utility.getTopWindow().location.reload();
  191. });
  192. //初始化设置
  193. utility.configTab = utility.fishTab(opt);
  194. opt.find("input[name]").each(function () {
  195. var el = $(this);
  196. var key = el.attr("name");
  197. var value = window.localStorage.getItem(key);
  198. if (!value) return;
  199. if (el.attr("type") == "checkbox") {
  200. el.attr("checked", value == "1");
  201. } else {
  202. el.val(value);
  203. }
  204. }).change(function () {
  205. var el = $(this);
  206. var key = el.attr("name");
  207. if (el.attr("type") == "checkbox") {
  208. window.localStorage.setItem(key, el[0].checked ? 1 : 0);
  209. } else {
  210. window.localStorage.setItem(key, el.val());
  211. }
  212. });
  213. $("#configLink, .configLink").live("click", function () {
  214. var el = $(this);
  215. var dp = el.attr("tab");
  216. utility.getTopWindow().utility.showLoginIE();
  217. utility.getTopWindow().utility.showOptionDialog(dp || "");
  218. });
  219. //新版本更新显示提示
  220. if (utility.getPref("helperVersion") != window.helperVersion) {
  221. //检测老版本设置
  222. if (utility.getAudioUrl().indexOf("github") != -1 || utility.getAudioUrl().indexOf("https://") != -1) {
  223. utility.resetAudioUrl();
  224. }
  225. utility.setPref("helperVersion", window.helperVersion);
  226. //仅顶层页面显示
  227. try {
  228. if (parent == self)
  229. utility.showOptionDialog("tabVersion");
  230. } catch (ex) {
  231. //跨域了,也是顶级
  232. utility.showOptionDialog("tabVersion");
  233. }
  234. }
  235. //注册
  236. var result = utility.verifySn(true);
  237. if (result.result == 0) {
  238. var info = opt.find(".registered").show().find("strong");
  239. info.eq(0).html(result.name);
  240. info.eq(1).html(result.typeDesc);
  241. } else {
  242. opt.find(".regTable").show();
  243. if (location.pathname == "/otsweb/" || location.pathname == "/otsweb/main.jsp") {
  244. alert("为了阻止地球人趁火打劫然后拿着老衲免费奉献的东东去卖钱,贫僧斗胆麻烦客官……啊不,施主注册下下,一下子就好了啦!");
  245. window.open("http://www.fishlee.net/Apps/Cn12306/GetNormalRegKey");
  246. utility.showOptionDialog("tabReg");
  247. }
  248. }
  249. utility.regInfo = result;
  250. }
  251. //#endregion
  252. //#region -----------------执行环境兼容----------------------
  253. var utility = {
  254. configTab: null,
  255. icon: "http://www.12306.cn/mormhweb/images/favicon.ico",
  256. notifyObj: null,
  257. timerObj: null,
  258. regInfo: null,
  259. isWebKit: function () {
  260. return navigator.userAgent.indexOf("WebKit") != -1;
  261. },
  262. trim: function (data) {
  263. if (typeof ($) != 'undefined') return $.trim(data);
  264. return data.replace(/(^\s+|\s+$)/g, "");
  265. },
  266. getTopWindow: function () {
  267. try {
  268. if (parent == self) return self;
  269. else return parent.window.utility.getTopWindow();
  270. } catch (e) {
  271. //跨域的话,也是顶层
  272. return self;
  273. }
  274. },
  275. init: function () {
  276. $.extend({
  277. any: function (array, callback) {
  278. var flag = false;
  279. $.each(array, function (i, v) {
  280. flag = callback.call(this, i, v);
  281. if (flag) return false;
  282. });
  283. return flag;
  284. },
  285. first: function (array, callback) {
  286. var result = null;
  287. $.each(array, function (i, v) {
  288. result = callback.call(this, i, v);
  289. if (result) return false;
  290. });
  291. return result;
  292. }
  293. });
  294. (function (n) { var t = /["\\\x00-\x1f\x7f-\x9f]/g, i = { "\b": "\\b", "\t": "\\t", "\n": "\\n", "\f": "\\f", "\r": "\\r", '"': '\\"', "\\": "\\\\" }, r = Object.prototype.hasOwnProperty; n.toJSON = typeof JSON == "object" && JSON.stringify ? JSON.stringify : function (t) { var i, a, l, v, p, y, f; if (t === null) return "null"; if (i = typeof t, i === "undefined") return undefined; if (i === "number" || i === "boolean") return "" + t; if (i === "string") return n.quoteString(t); if (i === "object") { if (typeof t.toJSON == "function") return n.toJSON(t.toJSON()); if (t.constructor === Date) { var e = t.getUTCMonth() + 1, o = t.getUTCDate(), w = t.getUTCFullYear(), s = t.getUTCHours(), h = t.getUTCMinutes(), c = t.getUTCSeconds(), u = t.getUTCMilliseconds(); return e < 10 && (e = "0" + e), o < 10 && (o = "0" + o), s < 10 && (s = "0" + s), h < 10 && (h = "0" + h), c < 10 && (c = "0" + c), u < 100 && (u = "0" + u), u < 10 && (u = "0" + u), '"' + w + "-" + e + "-" + o + "T" + s + ":" + h + ":" + c + "." + u + 'Z"' } if (t.constructor === Array) { for (a = [], l = 0; l < t.length; l++) a.push(n.toJSON(t[l]) || "null"); return "[" + a.join(",") + "]" } y = []; for (f in t) if (r.call(t, f)) { if (i = typeof f, i === "number") v = '"' + f + '"'; else if (i === "string") v = n.quoteString(f); else continue; (i = typeof t[f], i !== "function" && i !== "undefined") && (p = n.toJSON(t[f]), y.push(v + ":" + p)) } return "{" + y.join(",") + "}" } }, n.evalJSON = typeof JSON == "object" && JSON.parse ? JSON.parse : function (src) { return eval("(" + src + ")") }, n.secureEvalJSON = typeof JSON == "object" && JSON.parse ? JSON.parse : function (src) { var filtered = src.replace(/\\["\\\/bfnrtu]/g, "@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]").replace(/(?:^|:|,)(?:\s*\[)+/g, ""); if (/^[\],:{}\s]*$/.test(filtered)) return eval("(" + src + ")"); throw new SyntaxError("Error parsing JSON, source is not valid."); }, n.quoteString = function (n) { return n.match(t) ? '"' + n.replace(t, function (n) { var t = i[n]; return typeof t == "string" ? t : (t = n.charCodeAt(), "\\u00" + Math.floor(t / 16).toString(16) + (t % 16).toString(16)) }) + '"' : '"' + n + '"' } })(jQuery)
  295. },
  296. runningQueue: null,
  297. appendLog: function (settings) {
  298. /// <summary>记录日志</summary>
  299. if (!utility.runningQueue) utility.runningQueue = [];
  300. var log = { url: settings.url, data: settings.data, response: null, success: null };
  301. if (log.url.indexOf("Passenger") != -1) return; //不记录对乘客的请求
  302. utility.runningQueue.push(log);
  303. settings.log = log;
  304. },
  305. showLog: function () {
  306. if (!utility.runningQueue) {
  307. alert("当前页面尚未产生日志记录。");
  308. return;
  309. }
  310. var log = [];
  311. $.each(utility.runningQueue, function () {
  312. log.push("成功:" + (this.success ? "是" : "否") + "\r\n地址:" + this.url + "\r\n提交数据:" + utility.formatData(this.data) + "\r\n返回数据:" + utility.formatData(this.response));
  313. });
  314. $("#runningLog").val(log.join("\r\n----------------------------------\r\n"));
  315. utility.showOptionDialog("tabLog");
  316. },
  317. //获取登录到IE的代码 Add By XPHelper
  318. showLoginIE: function () {
  319. var strCookie = document.cookie;
  320. var arrCookie = strCookie.split("; ");
  321. var IECode = "javascript:";
  322. var cookie = [];
  323. for (var i = 0; i < arrCookie.length; i++) {
  324. var arr = arrCookie[i].split("=");
  325. if (arr.length < 2 || arr[0].indexOf("helper.") != -1) continue;
  326. cookie.push("document.cookie=\"" + arr[0] + "=" + arr[1] + "\";");
  327. }
  328. IECode += cookie.join("");
  329. IECode += "self.location.reload();";
  330. $("#LoginIECode").val(IECode);
  331. },
  332. formatData: function (data) {
  333. if (!data) return "(null)";
  334. if (typeof (data) == "string") return data;
  335. var html = [];
  336. for (var i in data) {
  337. html.push('"' + i + '":\"' + (this[i] + "").replace(/(\r|\n|")/g, function (a) { "\\" + a; }) + '\"');
  338. }
  339. return "{" + html.join(",") + "}";
  340. },
  341. notify: function (msg, timeout) {
  342. console.log("信息提示: " + msg);
  343. if (window.webkitNotifications) {
  344. if (window.webkitNotifications.checkPermission() == 0) {
  345. utility.closeNotify();
  346. if (utility.notifyObj == null)
  347. utility.notifyObj = webkitNotifications.createNotification(utility.icon, '订票', msg);
  348. utility.notifyObj.show();
  349. if (!timeout || timeout != 0) utility.timerObj = setTimeout(utility.closeNotify, timeout || 5000);
  350. } else {
  351. alert("【啊喂!!桌面通知还木有开启!请戳界面中的『点击启用桌面通知』按钮来开启!】\n\n" + msg);
  352. }
  353. } else {
  354. if (typeof (GM_notification) != 'undefined') {
  355. GM_notification(msg);
  356. } else {
  357. console.log("主页面中脚本信息, 无法提示, 写入通知区域.");
  358. utility.notifyOnTop(msg);
  359. }
  360. }
  361. },
  362. notifyOnTop: function (msg) {
  363. window.localStorage.setItem("notify", msg);
  364. },
  365. closeNotify: function () {
  366. if (!utility.notifyObj) return;
  367. utility.notifyObj.cancel();
  368. if (utility.timerObj) {
  369. clearTimeout(utility.timerObj);
  370. }
  371. utility.timerObj = null;
  372. utility.notifyObj = null;
  373. },
  374. setPref: function (name, value) {
  375. window.localStorage.setItem(name, value);
  376. },
  377. getPref: function (name) {
  378. return window.localStorage.getItem(name);
  379. },
  380. unsafeCallback: function (callback) {
  381. if (typeof (unsafeInvoke) == "undefined") callback();
  382. else unsafeInvoke(callback);
  383. },
  384. getTimeInfo: function () {
  385. var d = new Date();
  386. return d.getHours() + ":" + (d.getMinutes() < 10 ? "0" : "") + d.getMinutes() + ":" + (d.getSeconds() < 10 ? "0" : "") + d.getSeconds();
  387. },
  388. savePrefs: function (obj, prefix) {
  389. var objs = obj.find("input");
  390. objs.change(function () {
  391. var type = this.getAttribute("type");
  392. if (type == "text") utility.setPref(prefix + "_" + this.getAttribute("id"), $(this).val());
  393. else if (type == "checkbox") utility.setPref(prefix + "_" + this.getAttribute("id"), this.checked ? 1 : 0);
  394. })
  395. },
  396. reloadPrefs: function (obj, prefix) {
  397. var objs = obj.find("input");
  398. prefix = prefix || "";
  399. objs.each(function () {
  400. var e = $(this);
  401. var type = e.attr("type");
  402. var id = e.attr("id");
  403. var value = utility.getPref(prefix + "_" + id);
  404. if (typeof (value) == "undefined" || value == null) return;
  405. if (type == "text") e.val(value);
  406. else if (type == "checkbox") this.checked = value == "1";
  407. e.change();
  408. });
  409. utility.savePrefs(obj, prefix);
  410. },
  411. getErrorMsg: function (msg) {
  412. /// <summary>获得给定信息中的错误信息</summary>
  413. var m = msg.match(/var\s+message\s*=\s*"([^"]*)/);
  414. return m && m[1] ? m[1] : "<未知信息>";
  415. },
  416. delayInvoke: function (target, callback, timeout) {
  417. target = target || "#countEle";
  418. var e = typeof (target) == "string" ? $(target) : target;
  419. if (timeout <= 0) {
  420. e.html("正在执行").removeClass("fish_clock").addClass("fish_running");
  421. callback();
  422. } else {
  423. var str = (Math.floor(timeout / 100) / 10) + '';
  424. if (str.indexOf(".") == -1) str += ".0";
  425. e.html(str + " 秒后再来!...").removeClass("fish_running").addClass("fish_clock");
  426. setTimeout(function () {
  427. utility.delayInvoke(target, callback, timeout - 500);
  428. }, 500);
  429. }
  430. },
  431. saveList: function (name) {
  432. /// <summary>将指定列表的值保存到配置中</summary>
  433. var dom = document.getElementById(name);
  434. window.localStorage["list_" + name] = utility.getOptionArray(dom).join("\t");
  435. },
  436. loadList: function (name) {
  437. /// <summary>将指定的列表的值从配置中加载</summary>
  438. var dom = document.getElementById(name);
  439. var data = window.localStorage["list_" + name];
  440. if (!data) return;
  441. if (data.indexOf("\t") != -1)
  442. data = data.split('\t');
  443. else data = data.split('|');
  444. $.each(data, function () {
  445. dom.options[dom.options.length] = new Option(this, this);
  446. });
  447. },
  448. addOption: function (dom, text, value) {
  449. /// <summary>在指定的列表中加入新的选项</summary>
  450. dom.options[dom.options.length] = new Option(text, value);
  451. },
  452. getOptionArray: function (dom) {
  453. /// <summary>获得选项的数组格式</summary>
  454. return $.map(dom.options, function (o) { return o.value; });
  455. },
  456. inOptionList: function (dom, value) {
  457. /// <summary>判断指定的值是否在列表中</summary>
  458. for (var i = 0; i < dom.options.length; i++) {
  459. if (dom.options[i].value == value) return true;
  460. }
  461. return false;
  462. },
  463. getAudioUrl: function () {
  464. /// <summary>获得音乐地址</summary>
  465. return window.localStorage["audioUrl"] || (navigator.userAgent.indexOf("Firefox") != -1 ? "http://www.w3school.com.cn/i/song.ogg" : "http://www.w3school.com.cn/i/song.ogg");
  466. },
  467. getFailAudioUrl: function () {
  468. return (utility.isWebKit() ? "http://resbak.fishlee.net/res/" : "http://resbak.fishlee.net/res/") + "music3.ogg";
  469. },
  470. playFailAudio: function () {
  471. if (!window.Audio) return;
  472. new Audio(utility.getFailAudioUrl()).play()
  473. },
  474. resetAudioUrl: function () {
  475. /// <summary>恢复音乐地址为默认</summary>
  476. window.localStorage.removeItem("audioUrl");
  477. },
  478. parseDate: function (s) { /(\d{4})[-/](\d{1,2})[-/](\d{1,2})/.exec(s); return new Date(RegExp.$1, RegExp.$2 - 1, RegExp.$3); },
  479. getDate: function (s) {
  480. /// <summary>获得指定日期的天单位</summary>
  481. return new Date(s.getFullYear(), s.getMonth(), s.getDate());
  482. },
  483. formatDate: function (d) {
  484. /// <summary>格式化日期</summary>
  485. var y = d.getFullYear();
  486. return y + "-" + utility.formatDateShort(d);
  487. },
  488. formatDateShort: function (d) {
  489. /// <summary>格式化日期</summary>
  490. var mm = d.getMonth() + 1;
  491. var d = d.getDate();
  492. return (mm > 9 ? mm : "0" + mm) + "-" + (d > 9 ? d : "0" + d);
  493. },
  494. formatTime: function (d) {
  495. function padTo2Digit(digit) {
  496. return digit < 10 ? '0' + digit : digit;
  497. }
  498. return utility.formatDate(d) + " " + padTo2Digit(d.getHours()) + ":" + padTo2Digit(d.getMinutes()) + ":" + padTo2Digit(d.getSeconds());
  499. },
  500. addTimeSpan: function (date, y, mm, d, h, m, s) {
  501. /// <summary>对指定的日期进行偏移</summary>
  502. return new Date(date.getFullYear() + y, date.getMonth() + mm, date.getDate() + d, date.getHours() + h, date.getMinutes() + m, date.getSeconds() + s);
  503. },
  504. serializeForm: function (form) {
  505. /// <summary>序列化表单为对象</summary>
  506. var v = {};
  507. var o = form.serializeArray();
  508. for (var i in o) {
  509. if (typeof (v[o[i].name]) == 'undefined') v[o[i].name] = o[i].value;
  510. else v[o[i].name] += "," + o[i].value;
  511. }
  512. return v;
  513. },
  514. getSecondInfo: function (second) {
  515. var show_time = "";
  516. var hour = parseInt(second / 3600); //时
  517. if (hour > 0) {
  518. show_time = hour + "小时";
  519. second = second % 3600;
  520. }
  521. var minute = parseInt(second / 60); //分
  522. if (minute >= 1) {
  523. show_time = show_time + minute + "分";
  524. second = second % 60;
  525. } else if (hour >= 1 && second > 0) {
  526. show_time = show_time + "0分";
  527. }
  528. if (second > 0) {
  529. show_time = show_time + second + "秒";
  530. }
  531. return show_time;
  532. },
  533. post: function (url, data, dataType, succCallback, errorCallback) {
  534. $.ajax({
  535. url: url,
  536. data: data,
  537. timeout: 10000,
  538. type: "POST",
  539. success: succCallback,
  540. error: errorCallback,
  541. dataType: dataType
  542. });
  543. },
  544. get: function (url, data, dataType, succCallback, errorCallback) {
  545. $.ajax({
  546. url: url,
  547. data: data,
  548. timeout: 10000,
  549. type: "GET",
  550. success: succCallback,
  551. error: errorCallback,
  552. dataType: dataType
  553. });
  554. },
  555. showDialog: function (object, optx) {
  556. /// <summary>显示对话框。其中带有 close_button 样式的控件会自动作为关闭按钮</summary>
  557. return (function (opt) {
  558. var dataKey = "fs_dlg_opt";
  559. if (this.data(dataKey)) {
  560. //this.data(dataKey).closeDialog();
  561. return;
  562. }
  563. opt = $.extend({ bindControl: null, removeDialog: this.attr("autoCreate") == "1", onClose: null, animationMove: 20, speed: "fast", fx: "linear", show: "fadeInDown", hide: "fadeOutUp", onShow: null, timeOut: 0 }, opt);
  564. this.data("fs_dlg_opt", opt);
  565. var top = "0px";
  566. var left = "50%";
  567. this.css({
  568. "position": opt.parent ? "absolute" : "fixed",
  569. "left": left,
  570. "top": top,
  571. "margin-left": "-" + (this.width() / 2) + "px",
  572. "margin-top": "0px",
  573. "z-index": "9999"
  574. });
  575. var obj = this;
  576. this.changeLoadingIcon = function (icon) {
  577. /// <summary>更改加载对话框的图标</summary>
  578. obj.removeClass().addClass("loadingDialog loadicon_" + (icon || "tip"));
  579. return obj;
  580. };
  581. this.autoCloseDialog = function (timeout) {
  582. /// <summary>设置当前对话框在指定时间后自动关闭</summary>
  583. setTimeout(function () { obj.closeDialog(); }, timeout || 2500);
  584. return obj;
  585. };
  586. this.setLoadingMessage = function (msgHtml) {
  587. obj.find("div").html(msgHtml);
  588. return obj;
  589. };
  590. this.closeDialog = function () {
  591. /// <summary>关闭对话框</summary>
  592. obj.removeData(dataKey);
  593. obj.animate({ "marginTop": "+=" + opt.animationMove + "px", "opacity": "hide" }, opt.speed, opt.fx, function () {
  594. if (opt.bindControl) opt.bindControl.enable();
  595. if (opt.onClose) opt.onClose.call(obj);
  596. if (opt.removeDialog) obj.remove();
  597. })
  598. return obj;
  599. };
  600. $('.close_button', this).unbind("click").click(obj.closeDialog);
  601. //auto close
  602. if (opt.timeOut > 0) {
  603. var handler = opt.onShow;
  604. opt.onShow = function () {
  605. setTimeout(function () { $(obj).closeDialog(); }, opt.timeOut);
  606. if (handler != null) handler.call(this);
  607. };
  608. }
  609. //show it
  610. if (opt.bindControl) opt.bindControl.disable();
  611. this.animate({ "marginTop": "+=" + opt.animationMove + "px", "opacity": "show" }, opt.speed, opt.fx, function () { opt.onShow && opt.onShow.call(obj); })
  612. this.data(dataKey, this);
  613. return this;
  614. }).call(object, optx);
  615. },
  616. fishTab: function (obj, opt) {
  617. return (function (opt) {
  618. var self = this;
  619. opt = $.extend({ switchOnHover: false, switchOnClick: true }, opt);
  620. this.addClass("fishTab");
  621. this.showTab = function (tabid) {
  622. self.find(".current").removeClass("current");
  623. self.find("ul.tabNav li[tab=" + tabid + "], div." + tabid).addClass("current");
  624. };
  625. self.find(".tabNav li").hover(function () {
  626. if (!opt.switchOnHover) return;
  627. self.showTab($(this).attr("tab"));
  628. }).click(function () {
  629. if (!opt.switchOnClick) return;
  630. self.showTab($(this).attr("tab"));
  631. });
  632. this.showTab(self.find(".tabNav").attr("default") || self.find(".tabNav li:eq(0)").attr("tab"));
  633. return this;
  634. }).call(obj, opt);
  635. },
  636. getLoginRetryTime: function () {
  637. return parseInt(window.localStorage.getItem("login.retryLimit")) || 2000;
  638. },
  639. showOptionDialog: function (tab) {
  640. if (tab) utility.configTab.showTab(tab);
  641. utility.showDialog($("#fishOption"));
  642. },
  643. addCookie: function (name, value, expDays) {
  644. var cook = name + "=" + value + "; path=/; domain=.12306.cn";
  645. if (expDays > 0) {
  646. cook += "; expires=" + new Date(new Date().getTime() + expDays * 3600 * 1000 * 24).toGMTString();
  647. }
  648. document.cookie = cook;
  649. },
  650. getCookie: function (name) {
  651. var cook = document.cookie;
  652. var arr = cook.split("; ");
  653. for (var i = 0; i < arr.length; i++) {
  654. var arg = arr[i].split('=');
  655. if (arg[0] == name) return arg[1];
  656. }
  657. },
  658. setSnInfo: function (name, sn) {
  659. utility.setPref("helper.regUser", name);
  660. utility.setPref("helper.regSn", sn);
  661. utility.addCookie("helper.regUser", name, 999);
  662. utility.addCookie("helper.regSn", sn, 999);
  663. },
  664. verifySn: function (skipTimeVerify, name, sn) {
  665. name = name || utility.getPref("helper.regUser") || utility.getCookie("helper.regUser");
  666. sn = sn || utility.getPref("helper.regSn") || utility.getCookie("helper.regSn");
  667. if (!name && sn) return utility.verifySn2(skipTimeVerify, sn);
  668. if (!name || !sn) return { result: -4, msg: "未注册" };
  669. utility.setSnInfo(name, sn);
  670. var args = sn.split(',');
  671. if (!skipTimeVerify) {
  672. if ((new Date() - args[0]) / 60000 > 5) {
  673. return { result: -1, msg: "序列号注册已失效" };
  674. }
  675. }
  676. var dec = [];
  677. var encKey = args[0] + args[1];
  678. var j = 0;
  679. for (var i = 0; i < args[2].length; i += 4) {
  680. dec.push(String.fromCharCode(parseInt(args[2].substr(i, 4), 16) ^ encKey.charCodeAt(j)));
  681. j++;
  682. if (j >= encKey.length) j = 0;
  683. }
  684. var data = dec.join("");
  685. data = { result: null, type: data.substring(0, 4), name: data.substring(4) };
  686. data.result = data.name == name ? 0 : -3;
  687. data.msg = data.result == 0 ? "成功验证" : "注册无效"
  688. data.typeDesc = data.type == "NRML" ? "正式版" : (data.type == "GROP" ? "内部版, <span style='color:blue;'>感谢您参与我们之中</span>!" : "<span style='color:red;'>捐助版, 非常感谢您的支持</span>!");
  689. return data;
  690. },
  691. verifySn2: function (skipTimeVerify, data) {
  692. data = utility.trim(data);
  693. try {
  694. var nameLen = parseInt(data.substr(0, 2), 16);
  695. var name = data.substr(2, nameLen);
  696. data = data.substring(2 + nameLen);
  697. var arr = [];
  698. for (var i = 0; i < data.length; i++) {
  699. var c = data.charCodeAt(i);
  700. if (c >= 97) arr.push(String.fromCharCode(c - 49));
  701. else arr.push(data.charAt(i));
  702. }
  703. data = arr.join("");
  704. var ticket = parseInt(data.substr(0, 14), 16);
  705. var key = parseInt(data.substr(14, 1), 16);
  706. var encKey = ticket.toString(16).toUpperCase() + key.toString().toUpperCase();
  707. data = data.substring(15);
  708. var dec = [];
  709. var j = 0;
  710. for (var i = 0; i < data.length; i += 4) {
  711. dec.push(String.fromCharCode(parseInt(data.substr(i, 4), 16) ^ encKey.charCodeAt(j)));
  712. j++;
  713. if (j >= encKey.length) j = 0;
  714. }
  715. dec = dec.join("").split('|');
  716. var regVersion = dec[0].substr(0, 4);
  717. var regName = dec[0].substring(4);
  718. var bindAcc = dec.slice(1, dec.length);
  719. if (!bindAcc && !skipTimeVerify && (new Date() - ticket) / 60000 > 5) {
  720. return { result: -1, msg: "注册码已失效, 请重新申请" };
  721. }
  722. if (regName != name) {
  723. return { result: -3, msg: "注册失败,用户名不匹配" };
  724. }
  725. var data = { name: name, type: regVersion, bindAcc: bindAcc, ticket: ticket, result: 0, msg: "成功注册" };
  726. switch (data.type) {
  727. case "NRML": data.typeDesc = "正式版"; break;
  728. case "GROP": data.typeDesc = "内部版, <span style='color:blue;'>感谢您参与我们之中</span>!"; break;
  729. case "DONT": data.typeDesc = "<span style='color:red;'>捐助版, 非常感谢您的支持</span>!"; break;
  730. case "PART": data.typeDesc = "合作版,欢迎您的使用";
  731. }
  732. data.regTime = new Date(ticket);
  733. data.regVersion = 2;
  734. return data;
  735. } catch (e) {
  736. return { result: -4, msg: "数据错误" };
  737. }
  738. },
  739. allPassengers: null,
  740. getAllPassengers: function (callback) {
  741. if (utility.allPassengers) {
  742. callback(utility.allPassengers);
  743. }
  744. //开始加载所有乘客
  745. utility.allPassengers = [];
  746. var pageIndex = 0;
  747. function loadPage() {
  748. utility.post("/otsweb/passengerAction.do?method=getPagePassenger", { pageSize: 10, pageIndex: pageIndex }, "json", function (json) {
  749. $.each(json.rows, function () { utility.allPassengers.push(this); });
  750. if (utility.allPassengers.length >= json.recordCount) {
  751. callback(utility.allPassengers);
  752. } else {
  753. pageIndex++;
  754. setTimeout(loadPage, 1000);
  755. }
  756. }, function () {
  757. setTimeout(loadPage, 3000);
  758. });
  759. }
  760. loadPage();
  761. },
  762. regCache: {},
  763. getRegCache: function (value) {
  764. return utility.regCache[value] || (utility.regCache[value] = new RegExp("^(" + value + ")$", "i"));
  765. },
  766. preCompileReg: function (optionList) {
  767. var data = $.map(optionList, function (e) {
  768. return e.value;
  769. });
  770. return new RegExp("^(" + data.join("|") + ")$", "i");
  771. },
  772. enableLog: function () {
  773. $("body").append('<button style="width:100px;position:fixed;right:0px;top:0px;height:35px;" οnclick="utility.showLog();">显示运行日志</button>');
  774. $(document).ajaxSuccess(function (a, b, c) {
  775. if (!c.log) return;
  776. c.log.response = b.responseText;
  777. c.log.success = true;
  778. }).ajaxSend(function (a, b, c) {
  779. utility.appendLog(c);
  780. }).ajaxError(function (a, b, c) {
  781. if (!c.log) return;
  782. c.log.response = b.responseText;
  783. });
  784. },
  785. //获取登录到IE的代码 Add By XPHelper
  786. enableLoginIE: function () {
  787. $("body").append('<button style="width:150px;position:fixed;right:0px;top:0px;height:35px;" class="configLink" tab="tabLoginIE">获取登录到IE的代码</button>');
  788. },
  789. analyzeForm: function (html) {
  790. var data = {};
  791. //action
  792. var m = /<form.*?action="([^"]+)"/.exec(html);
  793. data.action = m ? RegExp.$1 : "";
  794. //inputs
  795. data.fields = {};
  796. var inputs = html.match(/<input\s*(.|\r|\n)*?>/gi);
  797. $.each(inputs, function () {
  798. if (!/name=['"]([^'"]+?)['"]/.exec(this)) return;
  799. var name = RegExp.$1;
  800. data.fields[RegExp.$1] = !/value=['"]([^'"]+?)['"]/.exec(this) ? "" : RegExp.$1;
  801. });
  802. //tourflag
  803. m = /submit_form_confirm\('confirmPassenger','([a-z]+)'\)/.exec(html);
  804. if (m) data.tourFlag = RegExp.$1;
  805. return data;
  806. },
  807. selectionArea: function (opt) {
  808. var self = this;
  809. this.options = $.extend({ onAdd: function () { }, onRemove: function () { }, onClear: function () { }, onRemoveConfirm: function () { return true; }, syncToStorageKey: "", defaultList: null, preloadList: null }, opt);
  810. this.append('<div style="padding: 5px; border: 1px dashed gray; background-color: rgb(238, 238, 238); width:120px;">(还没有添加任何项)</div>');
  811. this.datalist = [];
  812. this.add = function (data) {
  813. if ($.inArray(data, self.datalist) > -1) return;
  814. var text = typeof (data) == "string" ? data : data.text;
  815. var html = $('<input type="button" class="lineButton" value="' + text + '" title="点击删除" />');
  816. self.append(html);
  817. html.click(self.removeByButton);
  818. self.datalist.push(data);
  819. self.syncToStorage();
  820. self.checkEmpty();
  821. self.options.onAdd.call(self, data, html);
  822. };
  823. this.removeByButton = function () {
  824. var obj = $(this);
  825. var idx = obj.index() - 1;
  826. var value = self.datalist[idx];
  827. if (!self.options.onRemoveConfirm.call(self, value, obj, idx)) {
  828. return;
  829. }
  830. obj.remove();
  831. self.datalist.splice(idx, 1);
  832. self.syncToStorage();
  833. self.checkEmpty();
  834. self.options.onRemove.call(self, value, obj);
  835. };
  836. this.emptyList = function () {
  837. self.datalist = [];
  838. self.find("input").remove();
  839. self.syncToStorage();
  840. self.checkEmpty();
  841. self.options.onClear.call(self);
  842. };
  843. this.isInList = function (data) {
  844. /// <summary>判断指定的值是否在列表中</summary>
  845. return $.inArray($.inArray(data, self.datalist)) > -1;
  846. };
  847. this.isInRegList = function (data) {
  848. /// <summary>判断指定的值是否在列表中。这里假定是字符串,使用正则进行判断</summary>
  849. for (var i = 0; i < self.datalist.length; i++) {
  850. if (utility.getRegCache(self.datalist[i]).test(data)) return true;
  851. }
  852. return false;
  853. };
  854. this.syncToStorage = function () {
  855. if (!self.options.syncToStorageKey) return;
  856. window.localStorage.setItem(self.options.syncToStorageKey, self.datalist.join("\t"));
  857. };
  858. this.checkEmpty = function () {
  859. if (self.find("input").length) {
  860. self.find("div").hide();
  861. } else {
  862. self.find("div").show();
  863. }
  864. };
  865. if (self.options.syncToStorageKey) {
  866. var list = self.options.preloadList;
  867. if (!list) {
  868. var list = window.localStorage.getItem(this.options.syncToStorageKey);
  869. if (!list) list = this.options.defaultList;
  870. else list = list.split('\t');
  871. }
  872. if (list) {
  873. $.each(list, function () { self.add(this + ""); });
  874. }
  875. }
  876. return this;
  877. }
  878. }
  879. function unsafeInvoke(callback) {
  880. /// <summary>非沙箱模式下的回调</summary>
  881. var cb = document.createElement("script");
  882. cb.type = "text/javascript";
  883. cb.textContent = buildCallback(callback);
  884. document.head.appendChild(cb);
  885. }
  886. function buildCallback(callback) {
  887. var content = "";
  888. if (!utility_emabed) {
  889. content += "if(typeof(window.utility)!='undefined' && navigator.userAgent.indexOf('Maxthon')==-1){ alert('我勒个去! 检测到您似乎同时运行了两只助手! 请转到『附加组件管理『(Firefox)或『扩展管理』(Chrome)中卸载老版本的助手!');}; \r\nwindow.utility=" + buildObjectJavascriptCode(utility) + "; window.utility.init();window.helperVersion='" + version + "';\r\n";
  890. utility_emabed = true;
  891. }
  892. content += "window.__cb=" + buildObjectJavascriptCode(callback) + ";\r\n\
  893. if(typeof(jQuery)!='undefined')window.__cb();\r\n\
  894. else{\
  895. var script=document.createElement('script');\r\nscript.src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js';\r\n\
  896. script.type='text/javascript';\r\n\
  897. script.addEventListener('load', window.__cb);\r\n\
  898. document.head.appendChild(script);\r\n\
  899. }";
  900. return content;
  901. }
  902. function buildObjectJavascriptCode(object) {
  903. /// <summary>将指定的Javascript对象编译为脚本</summary>
  904. if (!object) return null;
  905. var t = typeof (object);
  906. if (t == "string") {
  907. return "\"" + object.replace(/(\r|\n|\\)/gi, function (a, b) {
  908. switch (b) {
  909. case "\r":
  910. return "\\r";
  911. case "\n":
  912. return "\\n";
  913. case "\\":
  914. return "\\\\";
  915. }
  916. }) + "\"";
  917. }
  918. if (t != "object") return object + "";
  919. var code = [];
  920. for (var i in object) {
  921. var obj = object[i];
  922. var objType = typeof (obj);
  923. if ((objType == "object" || objType == "string") && obj) {
  924. code.push(i + ":" + buildObjectJavascriptCode(obj));
  925. } else {
  926. code.push(i + ":" + obj);
  927. }
  928. }
  929. return "{" + code.join(",") + "}";
  930. }
  931. var isChrome = navigator.userAgent.indexOf("AppleWebKit") != -1;
  932. var isFirefox = navigator.userAgent.indexOf("Firefox") != -1;
  933. if (location.host == "dynamic.12306.cn" || (location.host == "www.12306.cn" && location.protocol == "https:")) {
  934. if (!isChrome && !isFirefox) {
  935. alert("很抱歉,未能识别您的浏览器,或您的浏览器尚不支持脚本运行,请使用Firefox或Chrome浏览器!\n如果您运行的是Maxthon3,请确认当前页面运行在高速模式而不是兼容模式下 :-)");
  936. } else if (isFirefox && typeof (GM_notification) == 'undefined') {
  937. alert("很抱歉,本脚本需要最新的Scriptish扩展、不支持GreaseMonkey,请禁用您的GreaseMonkey扩展并安装Scriptish!");
  938. window.open("https://addons.mozilla.org/zh-CN/firefox/addon/scriptish/");
  939. } else if (!window.localStorage) {
  940. alert("警告! localStorage 为 null, 助手无法运行. 请查看浏览器是否已经禁用 localStorage!\nFirefox请设置 about:config 中的 dom.storage.enabled 为 true .");
  941. } else {
  942. //记录更新
  943. utility.setPref("updates", updates.join("\t"));
  944. initUIDisplay();
  945. unsafeInvoke(injectDom);
  946. entryPoint();
  947. }
  948. }
  949. //#endregion
  950. //#region -----------------入口----------------------
  951. function entryPoint() {
  952. var location = window.location;
  953. var path = location.pathname;
  954. utility.regInfo = utility.verifySn(true);
  955. if (utility.regInfo.result != 0) {
  956. return;
  957. }
  958. //
  959. unsafeInvoke(autoReloadIfError);
  960. if ((path == "/otsweb/loginAction.do" && location.search != '?method=initForMy12306') || path == "/otsweb/login.jsp") {
  961. //登录页
  962. unsafeInvoke(initLogin);
  963. }
  964. if (utility.regInfo.bindAcc && localStorage.getItem("_sessionuser") && utility.regInfo.bindAcc.length > 0 && utility.regInfo.bindAcc[0] && utility.regInfo.bindAcc[0] != "*") {
  965. var user = localStorage.getItem("_sessionuser");
  966. var ok = false;
  967. for (var i = 0; i < utility.regInfo.bindAcc.length; i++) {
  968. if (utility.regInfo.bindAcc[i] == user) {
  969. ok = true;
  970. break;
  971. }
  972. }
  973. if (!ok) return;
  974. }
  975. if (path == "/otsweb/order/querySingleAction.do") {
  976. if (location.search == "?method=init" && document.getElementById("submitQuery")) {
  977. unsafeInvoke(initTicketQuery);
  978. unsafeInvoke(initDirectSubmitOrder);
  979. }
  980. if (location.search == "?method=submutOrderRequest") {
  981. unsafeInvoke(initSubmitOrderQuest);
  982. }
  983. }
  984. if (path == "/otsweb/order/orderAction.do") {
  985. if (location.search.indexOf("method=cancelMyOrderNotComplete") != -1 && document.getElementById("submitQuery")) {
  986. unsafeInvoke(initTicketQuery);
  987. unsafeInvoke(initDirectSubmitOrder);
  988. }
  989. }
  990. if (path == "/otsweb/order/payConfirmOnlineSingleAction.do") {
  991. if (location.search.indexOf("method=cancelOrder") != -1 && document.getElementById("submitQuery")) {
  992. unsafeInvoke(initTicketQuery);
  993. unsafeInvoke(initDirectSubmitOrder);
  994. }
  995. }
  996. if (path == "/otsweb/order/myOrderAction.do") {
  997. if (location.search.indexOf("method=resign") != -1 && document.getElementById("submitQuery")) {
  998. unsafeInvoke(initTicketQuery);
  999. unsafeInvoke(initDirectSubmitOrder);
  1000. }
  1001. }
  1002. if (path == "/otsweb/order/confirmPassengerAction.do") {
  1003. if (location.search == "?method=init") {
  1004. unsafeInvoke(initAutoCommitOrder);
  1005. unsafeInvoke(autoCommitOrderInSandbox);
  1006. }
  1007. if (location.search.indexOf("?method=payOrder") != -1) {
  1008. unsafeInvoke(initPagePayOrder);
  1009. //获取登录到IE的代码 Add By XPHelper
  1010. unsafeInvoke(utility.enableLoginIE);
  1011. }
  1012. }
  1013. if (path == "/otsweb/order/myOrderAction.do") {
  1014. if (location.search.indexOf("?method=laterEpay") != -1 || location.search.indexOf("?method=queryMyOrderNotComplete") != -1) {
  1015. unsafeInvoke(initNotCompleteOrderPage);
  1016. unsafeInvoke(initPayOrder);
  1017. //获取登录到IE的代码 Add By XPHelper
  1018. unsafeInvoke(utility.enableLoginIE);
  1019. }
  1020. }
  1021. if (path == "/otsweb/main.jsp" || path == "/otsweb/") {
  1022. //主框架
  1023. console.log("正在注入主框架脚本。");
  1024. //跨页面弹窗提示,防止因为页面跳转导致对话框不关闭
  1025. console.log("启动跨页面信息调用检查函数");
  1026. window.setInterval(function () {
  1027. var msg = window.localStorage["notify"];
  1028. if (typeof (msg != 'undefined') && msg) {
  1029. console.log("主窗口拦截提示请求: " + msg);
  1030. window.localStorage.removeItem("notify");
  1031. utility.notify(msg);
  1032. }
  1033. }, 100);
  1034. unsafeInvoke(injectMainPageFunction);
  1035. }
  1036. }
  1037. //#endregion
  1038. //#region 未完成订单查询页面
  1039. function initNotCompleteOrderPage() {
  1040. //处理显示时间的
  1041. (function () {
  1042. var tagInputs = $("input[name=cache_tour_flag]");
  1043. var flags = $.map(tagInputs, function (e, i) { return e.value; });
  1044. $.each(flags, function () { $("#showTime_" + this).hide().after("<span id='status_" + this + "'>正在查询...</span>"); });
  1045. function doCheck() {
  1046. var flag = flags.shift();
  1047. flags.push(flag);
  1048. utility.get("https://dynamic.12306.cn/otsweb/order/myOrderAction.do?method=getOrderWaitTime&tourFlag=" + flag, null, "json", function (data) {
  1049. var obj = $("#status_" + flag);
  1050. if (data.waitTime == 0 || data.waitTime == -1) {
  1051. obj.css({ "color": "green" }).html("订票成功!");
  1052. utility.notifyOnTop("订票成功!请尽快付款!");
  1053. parent.playAudio();
  1054. self.location.reload();
  1055. return;
  1056. }
  1057. if (data.waitTime == -2) {
  1058. utility.notifyOnTop("出票失败!请重新订票!" + data.msg);
  1059. parent.playFailAudio();
  1060. obj.css({ "color": "red" }).html("出票失败!" + data.msg);
  1061. return;
  1062. }
  1063. if (data.waitTime == -3) {
  1064. utility.notifyOnTop("订单已经被取消!");
  1065. parent.playFailAudio();
  1066. obj.css({ "color": "red" }).html("订单已经被取消!!");
  1067. return;
  1068. }
  1069. if (data.waitTime == -4) {
  1070. utility.notifyOnTop("正在处理中....");
  1071. obj.css({ "color": "blue" }).html("正在处理中....");
  1072. }
  1073. if (data.waitTime > 0) {
  1074. obj.css({ "color": "red" }).html("排队中<br />排队数【" + (data.waitCount || "未知") + "】<br />预计时间【" + utility.getSecondInfo(data.waitTime) + "】<br />不过这时间不<br />怎么靠谱 ╮(╯▽╰)╭");
  1075. } else {
  1076. obj.css({ "color": "red" }).html("奇怪的状态码 [" + data.waitTime + "]....");
  1077. }
  1078. setTimeout(doCheck, 2000);
  1079. }, function () {
  1080. utility.notifyOnTop("查询状态错误,正在刷新页面!");
  1081. self.location.reload();
  1082. });
  1083. }
  1084. if (flags.length > 0) doCheck();
  1085. })();
  1086. }
  1087. //#endregion
  1088. //#region 提交页面出错
  1089. function initSubmitOrderQuest() {
  1090. if ($("div.error_text").length > 0) {
  1091. parent.window.resubmitForm();
  1092. }
  1093. }
  1094. //#endregion
  1095. //#region 订票页面,声音提示
  1096. function initPagePayOrder() {
  1097. new Audio(utility.getAudioUrl()).play();
  1098. }
  1099. //#endregion
  1100. //#region -----------------出错自动刷新----------------------
  1101. function autoReloadIfError() {
  1102. if ($.trim($("h1:first").text()) == "错误") {
  1103. $("h1:first").css({ color: 'red', 'font-size': "18px" }).html(">_< 啊吖!,敢踹我出门啦。。。2秒后我一定会回来的 ╮(╯▽╰)╭");
  1104. setTimeout(function () {
  1105. self.location.reload();
  1106. }, 2000);
  1107. }
  1108. }
  1109. //#endregion
  1110. //#region -----------------主框架----------------------
  1111. function injectMainPageFunction() {
  1112. //资源
  1113. var main = $("#main")[0];
  1114. main.onload = function () {
  1115. var location = null;
  1116. try {
  1117. location = main.contentWindow.location + '';
  1118. } catch (e) {
  1119. //出错了,跨站
  1120. }
  1121. if (!location || location == "http://www.12306.cn/mormhweb/logFiles/error.html") {
  1122. resubmitForm();
  1123. }
  1124. }
  1125. if (window.webkitNotifications && window.webkitNotifications.checkPermission() != 0) {
  1126. if (confirm("喂!快戳『点击启用桌面通知』,不然提示会阻碍操作,导致运行变慢,然后就没票了!\n\n如果是第一次看到介句话,点击『取消』并按提示操作。如果反复邂逅这个对话框,就戳『确定』以打开助手主页的常见问题并查找解决办法。\n\n搜狗高速浏览器暂不支持保存此权限,每次访问时可能都会邂逅这个对话框……")) {
  1127. window.open("http://www.fishlee.net/soft/44/faq.html");
  1128. }
  1129. }
  1130. window.resubmitForm = function () {
  1131. var form = $("#orderForm");
  1132. if (form.length == 0 || form.attr("success") != "0") return;
  1133. utility.notify("页面出错了!正在重新预定!");
  1134. setTimeout(function () { document.getElementById("orderForm").submit(); }, 3000);
  1135. }
  1136. window.playAudio = function () {
  1137. new Audio(utility.getAudioUrl()).play();
  1138. };
  1139. window.playFailAudio = function () {
  1140. utility.playFailAudio();
  1141. };
  1142. }
  1143. //#endregion
  1144. //#region -----------------自动提交----------------------
  1145. function initAutoCommitOrder() {
  1146. var count = 0;
  1147. var breakFlag = 0;
  1148. var randCode = "";
  1149. var submitFlag = false;
  1150. var tourFlag = 'dc';
  1151. var randEl = $("#rand");
  1152. //启用日志
  1153. utility.enableLog();
  1154. //#region 如果系统出错,那么重新提交
  1155. if ($(".error_text").length > 0 && parent.$("#orderForm").length > 0) {
  1156. parent.resubmitForm();
  1157. return;
  1158. }
  1159. //#endregion
  1160. //获得tourflag
  1161. (function () {
  1162. /'(dc|fc|wc|gc)'/.exec($("div.tj_btn :button:eq(2)")[0].onclick + '');
  1163. tourFlag = RegExp.$1;
  1164. })();
  1165. function stop(msg) {
  1166. setCurOperationInfo(false, "错误 - " + msg);
  1167. setTipMessage(msg);
  1168. $("div.tj_btn button, div.tj_btn input").each(function () {
  1169. this.disabled = false;
  1170. $(this).removeClass().addClass("long_button_u");
  1171. });
  1172. $("#btnCancelAuto").hide();
  1173. }
  1174. var reloadCode = function () {
  1175. $("#img_rrand_code").click();
  1176. $("#rand").val("")[0].select();
  1177. };
  1178. var getSleepTime = function () {
  1179. return 1000 * Math.max(parseInt($("#pauseTime").val()), 1);
  1180. };
  1181. //订单等待时间过久的警告
  1182. var waitTimeTooLong_alert = false;
  1183. function submitForm() {
  1184. randEl[0].blur();
  1185. stopCheckCount();
  1186. if (!window.submit_form_check || !submit_form_check("confirmPassenger")) {
  1187. setCurOperationInfo(false, "您的表单没有填写完整!");
  1188. stop("请填写完整表单");
  1189. return;
  1190. }
  1191. count++;
  1192. setCurOperationInfo(true, "第 " + count + " 次提交");
  1193. if (breakFlag) {
  1194. stop("已取消自动提交");
  1195. breakFlag = 0;
  1196. return;
  1197. }
  1198. $("#btnCancelAuto").show().removeClass().addClass("long_button_u_down")[0].disabled = false; //阻止被禁用
  1199. breakFlag = 0;
  1200. waitTimeTooLong_alert = false;
  1201. $("#confirmPassenger").ajaxSubmit({
  1202. url: 'confirmPassengerAction.do?method=checkOrderInfo&rand=' + $("#rand").val(),
  1203. type: "POST",
  1204. data: { tFlag: tourFlag },
  1205. dataType: "json",
  1206. success: function (data) {
  1207. if ('Y' != data.errMsg || 'N' == data.checkHuimd || 'N' == data.check608) {
  1208. setCurOperationInfo(false, data.msg || data.errMsg);
  1209. stop(data.msg || data.errMsg);
  1210. reloadCode();
  1211. }
  1212. else {
  1213. queryQueueCount();
  1214. }
  1215. },
  1216. error: function (msg) {
  1217. setCurOperationInfo(false, "当前请求发生错误");
  1218. utility.delayInvoke(null, submitForm, 1000);
  1219. }
  1220. });
  1221. }
  1222. function queryQueueCount() {
  1223. var queryLeftData = {
  1224. train_date: $("#start_date").val(),
  1225. train_no: $("#train_no").val(),
  1226. station: $("#station_train_code").val(),
  1227. seat: $("#passenger_1_seat").val(),
  1228. from: $("#from_station_telecode").val(),
  1229. to: $("#to_station_telecode").val(),
  1230. ticket: $("#left_ticket").val()
  1231. };
  1232. utility.get("/otsweb/order/confirmPassengerAction.do?method=getQueueCount", queryLeftData, "json", function (data) {
  1233. console.log(data);
  1234. if (data.op_2) {
  1235. var errmsg = "排队人数过多,系统禁止排队,稍等自动重试 (排队人数=" + data.count + ")";
  1236. setCurOperationInfo(true, errmsg);
  1237. stop(errmsg);
  1238. utility.delayInvoke(null, queryQueueCount, 1000);
  1239. return;
  1240. }
  1241. submitConfirmOrder();
  1242. }, function () { utility.delayInvoke(null, queryLeftTickets, 2000); });
  1243. }
  1244. function submitConfirmOrder() {
  1245. jQuery.ajax({
  1246. url: '/otsweb/order/confirmPassengerAction.do?method=confirmSingleForQueueOrder',
  1247. data: $('#confirmPassenger').serialize(),
  1248. type: "POST",
  1249. timeout: 10000,
  1250. dataType: 'json',
  1251. success: function (msg) {
  1252. console.log(msg);
  1253. var errmsg = msg.errMsg;
  1254. if (errmsg != 'Y') {
  1255. if (errmsg.indexOf("包含未付款订单") != -1) {
  1256. alert("您有未支付订单! 等啥呢, 赶紧点确定支付去.");
  1257. window.location.replace("/otsweb/order/myOrderAction.do?method=queryMyOrderNotComplete&leftmenu=Y");
  1258. return;
  1259. }
  1260. if (errmsg.indexOf("重复提交") != -1) {
  1261. stop("重复提交错误,已刷新TOKEN,请重新输入验证码提交");
  1262. reloadToken();
  1263. reloadCode();
  1264. return;
  1265. }
  1266. if (errmsg.indexOf("后台处理异常") != -1 || errmsg.indexOf("非法请求") != -1) {
  1267. if (lastform) {
  1268. utility.notifyOnTop("后台处理异常,已自动重新提交表单,请填写验证码并提交!");
  1269. lastform.submit();
  1270. } else {
  1271. stop("后台处理异常,请返回查询页重新预定!");
  1272. }
  1273. return;
  1274. }
  1275. if (errmsg.indexOf("包含排队中") != -1) {
  1276. console.log("惊现排队中的订单, 进入轮询状态");
  1277. waitingForQueueComplete();
  1278. return;
  1279. }
  1280. setCurOperationInfo(false, errmsg);
  1281. stop(errmsg);
  1282. reloadCode();
  1283. } else {
  1284. utility.notifyOnTop("订单提交成功, 正在等待队列完成操作,请及时注意订单状态");
  1285. waitingForQueueComplete();
  1286. }
  1287. },
  1288. error: function (msg) {
  1289. setCurOperationInfo(false, "当前请求发生错误");
  1290. utility.delayInvoke(null, submitForm, 3000);
  1291. }
  1292. });
  1293. }
  1294. function reloadToken(submit) {
  1295. setCurOperationInfo(true, "正在刷新TOKEN....");
  1296. utility.post("/otsweb/order/confirmPassengerAction.do?method=init", null, "text", function (text) {
  1297. if (!/TOKEN"\s*value="([a-f\d]+)"/i.test(text)) {
  1298. setCurOperationInfo(false, "无法获得TOKEN,正在重试");
  1299. utility.delayInvoke("#countEle", reloadToken, 1000);
  1300. } else {
  1301. var token = RegExp.$1;
  1302. setCurOperationInfo(false, "已获得TOKEN - " + token);
  1303. console.log("已刷新TOKEN=" + token);
  1304. $("input[name=org.apache.struts.taglib.html.TOKEN]").val(token);
  1305. }
  1306. }, function () { utility.delayInvoke("#countEle", reloadToken, 1000); });
  1307. }
  1308. function waitingForQueueComplete() {
  1309. setCurOperationInfo(true, "订单提交成功, 正在等待队列完成操作....");
  1310. $.ajax({
  1311. url: '/otsweb/order/myOrderAction.do?method=getOrderWaitTime&tourFlag=' + tourFlag + '&' + Math.random(),
  1312. data: {},
  1313. type: 'GET',
  1314. timeout: 10000,
  1315. dataType: 'json',
  1316. success: function (json) {
  1317. console.log(json);
  1318. if (json.waitTime == -1 || json.waitTime == 0) {
  1319. utility.notifyOnTop("订票成功!");
  1320. if (json.orderId)
  1321. window.location.replace("/otsweb/order/confirmPassengerAction.do?method=payOrder&orderSequence_no=" + json.orderId);
  1322. else window.location.replace('/otsweb/order/myOrderAction.do?method=queryMyOrderNotComplete&leftmenu=Y');
  1323. } else if (json.waitTime == -3) {
  1324. var msg = "很抱歉, 铁道部无齿地撤销了您的订单, 赶紧重新下!";
  1325. utility.notify(msg);
  1326. setCurOperationInfo(false, msg);
  1327. stop(msg);
  1328. reloadCode();
  1329. } else if (json.waitTime == -2) {
  1330. var msg = "很抱歉, 铁道部说您占座失败 : " + json.msg + ', 赶紧重新来过!';
  1331. reloadToken();
  1332. utility.notify(msg);
  1333. setCurOperationInfo(false, msg);
  1334. stop(msg);
  1335. reloadCode();
  1336. }
  1337. else if (json.waitTime < 0) {
  1338. var msg = '很抱歉, 未知的状态信息 : waitTime=' + json.waitTime + ', 可能已成功,请验证未支付订单.';
  1339. setTipMessage(msg);
  1340. utility.notifyOnTop(msg);
  1341. location.href = '/otsweb/order/myOrderAction.do?method=queryMyOrderNotComplete&leftmenu=Y';
  1342. } else {
  1343. var msg = "订单需要 " + utility.getSecondInfo(json.waitTime) + " 处理完成, 请等待,不过你知道的,铁道部说的一直不怎么准。(排队人数=" + (json.waitCount || "未知") + ")";
  1344. if (json.waitTime > 1800) {
  1345. msg += "<span style='color:red; font-weight: bold;'>警告:排队时间大于30分钟,请不要放弃电话订票或用小号重新排队等其它方式继续订票!</span>";
  1346. }
  1347. setTipMessage(msg);
  1348. if (json.waitTime > 1800 && !waitTimeTooLong_alert) {
  1349. waitTimeTooLong_alert = true;
  1350. utility.notifyOnTop("警告!排队时间大于30分钟,成功率较低,请尽快电话订票或用小号重新排队!");
  1351. }
  1352. utility.delayInvoke("#countEle", waitingForQueueComplete, 1000);
  1353. }
  1354. },
  1355. error: function (json) {
  1356. utility.notifyOnTop("请求发生异常,可能是登录状态不对,请验证。如果没有问题,请手动进入未完成订单页面查询。");
  1357. self.location.reload();
  1358. }
  1359. });
  1360. }
  1361. $("div.tj_btn").append("<button class='long_button_u_down' type='button' id='btnAutoSubmit'>自动提交</button> <button class='long_button_u_down' type='button' id='btnCancelAuto' style='display:none;'>取消自动</button>");
  1362. $("#btnAutoSubmit").click(function () {
  1363. count = 0;
  1364. breakFlag = 0;
  1365. submitFlag = true;
  1366. submitForm();
  1367. });
  1368. $("#btnCancelAuto").click(function () {
  1369. $(this).hide();
  1370. breakFlag = 1;
  1371. submitFlag = false;
  1372. });
  1373. randEl.keyup(function (e) {
  1374. if (!submitFlag && !document.getElementById("autoStartCommit").checked) return;
  1375. if (e.charCode == 13 || randEl.val().length == 4) submitForm();
  1376. });
  1377. //清除上次保存的预定信息
  1378. var lastform = null;
  1379. if (parent) {
  1380. lastform = parent.$("#orderForm");
  1381. lastform.attr("success", "1");
  1382. }
  1383. //进度提示框
  1384. $("table.table_qr tr:last").before("<tr><td style='border-top:1px dotted #ccc;height:100px;' colspan='9' id='orderCountCell'></td></tr><tr><td style='border-top:1px dotted #ccc;' colspan='9'><ul id='tipScript'>" +
  1385. "<li class='fish_clock' id='countEle' style='font-weight:bold;'>等待操作</li>" +
  1386. "<li style='color:green;'><strong>操作信息</strong>:<span>休息中</span></li>" +
  1387. "<li style='color:green;'><strong>最后操作时间</strong>:<span>--</span></li></ul></td></tr>");
  1388. var tip = $("#tipScript li");
  1389. var errorCount = 0;
  1390. //以下是函数
  1391. function setCurOperationInfo(running, msg) {
  1392. var ele = $("#countEle");
  1393. ele.removeClass().addClass(running ? "fish_running" : "fish_clock").html(msg || (running ? "正在操作中……" : "等待中……"));
  1394. }
  1395. function setTipMessage(msg) {
  1396. tip.eq(2).find("span").html(utility.getTimeInfo());
  1397. tip.eq(1).find("span").html(msg);
  1398. }
  1399. //提交频率差别
  1400. $(".table_qr tr:last").before("<tr><td colspan='9'>自动提交失败时休息时间:<input type='text' size='4' class='input_20txt' style='text-align:center;' value='3' id='pauseTime' />秒 (不得低于1) <label><input type='checkbox' id='autoStartCommit' /> 输入验证码后立刻开始自动提交</label> <label><input type='checkbox' id='showHelp' /> 显示帮助</label></td></tr>");
  1401. document.getElementById("autoStartCommit").checked = typeof (window.localStorage["disableAutoStartCommit"]) == 'undefined';
  1402. document.getElementById("showHelp").checked = typeof (window.localStorage["showHelp"]) != 'undefined';
  1403. $("#autoStartCommit").change(function () {
  1404. if (this.checked) window.localStorage.removeItem("disableAutoStartCommit");
  1405. else window.localStorage.setItem("disableAutoStartCommit", "1");
  1406. });
  1407. $("#showHelp").change(function () {
  1408. if (this.checked) {
  1409. window.localStorage.setItem("showHelp", "1");
  1410. $("table.table_qr tr:last").show();
  1411. }
  1412. else {
  1413. window.localStorage.removeItem("showHelp");
  1414. $("table.table_qr tr:last").hide();
  1415. }
  1416. }).change();
  1417. //#region 自动刷新席位预定请求数
  1418. var stopCheckCount = null;
  1419. (function () {
  1420. var data = { train_date: $("#start_date").val(), station: $("#station_train_code").val(), seat: "", from: $("#from_station_telecode").val(), to: $("#to_station_telecode").val(), ticket: $("#left_ticket").val() };
  1421. var url = "confirmPassengerAction.do?method=getQueueCount";
  1422. var allSeats = $("#passenger_1_seat option");
  1423. var queue = [];
  1424. var checkCountStopped = false;
  1425. function beginCheck() {
  1426. if (checkCountStopped) return;
  1427. var html = [];
  1428. html.push("当前实时排队状态(每隔2秒轮询):");
  1429. allSeats.each(function () {
  1430. queue.push({ id: this.value, name: this.text });
  1431. html.push("席位【<span style='color:blue; font-weight: bold;'>" + this.text + "</span>】状态:<span id='queueStatus_" + this.value + "'>等待查询中....</span>");
  1432. });
  1433. $("#orderCountCell").html(html.join("<br />"));
  1434. if (queue.length > 0) executeQueue();
  1435. }
  1436. function checkTicketAvailable() {
  1437. var queryLeftData = {
  1438. 'orderRequest.train_date': $('#start_date').val(),
  1439. 'orderRequest.from_station_telecode': $('#from_station_telecode').val(),
  1440. 'orderRequest.to_station_telecode': $('#to_station_telecode').val(),
  1441. 'orderRequest.train_no': $('#train_no').val(),
  1442. 'trainPassType': 'QB',
  1443. 'trainClass': 'QB#D#Z#T#K#QT#',
  1444. 'includeStudent': 00,
  1445. 'seatTypeAndNum': '',
  1446. 'orderRequest.start_time_str': '00:00--24:00'
  1447. };
  1448. utility.get("/otsweb/order/querySingleAction.do?method=queryLeftTicket", queryLeftData, "text", function (text) {
  1449. window.ticketAvailable = '';
  1450. if (/(([\da-zA-Z]\*{5,5}\d{4,4})+)/gi.test(text)) {
  1451. window.ticketAvailable = RegExp.$1;
  1452. }
  1453. }, function () { });
  1454. }
  1455. function executeQueue() {
  1456. if (checkCountStopped) return;
  1457. var type = queue.shift();
  1458. queue.push(type);
  1459. data.seat = type.id;
  1460. var strLeftTicket = '';
  1461. checkTicketAvailable();
  1462. if (window.ticketAvailable) {
  1463. strLeftTicket = window.ticketAvailable;
  1464. }
  1465. utility.get(url, data, "json", function (data) {
  1466. var msg = "余票:<strong>" + getTicketCountDesc(strLeftTicket, type.id) + "</strong>";
  1467. msg += ",当前排队【<span style='color:blue; font-weight: bold;'>" + data.count + "</span>】,";
  1468. if (data.op_2) {
  1469. msg += "<span style='color:blue; font-weight: red;'>排队人数已经超过余票数,可能无法提交</span>。";
  1470. } else {
  1471. if (data.countT > 0) {
  1472. msg += "排队人数已超过系统参数,<span style='color:red; font-weight: bold;'>排队有危险</span>";
  1473. //} else if (data.op_1) {
  1474. // msg += "排队人数已超过系统参数,<span style='color:red; font-weight: bold;'>排队有危险</span>";
  1475. } else {
  1476. msg += "请尽快提交";
  1477. }
  1478. }
  1479. msg += "(" + utility.getTimeInfo() + ")";
  1480. $("#queueStatus_" + type.id).html(msg);
  1481. setTimeout(executeQueue, 2000);
  1482. }, function () {
  1483. setTimeout(executeQueue, 3000);
  1484. });
  1485. }
  1486. stopCheckCount = function () {
  1487. checkCountStopped = true;
  1488. }
  1489. beginCheck();
  1490. })();
  1491. //#endregion
  1492. //#region 自动选择联系人、自动选择上次选择的人
  1493. function autoSelectPassenger() {
  1494. var pp = localStorage.getItem("preSelectPassenger") || "";
  1495. var pseat = (localStorage.getItem("autoSelect_preSelectSeatType") || "").split('|')[0];
  1496. if (pp) {
  1497. pp = pp.split("|");
  1498. $.each(pp, function () {
  1499. if (!this) return true;
  1500. console.log("[INFO][自动选择乘客] 自动选定-" + this);
  1501. $("#" + this + "._checkbox_class").attr("checked", true).click().attr("checked", true); //为啥设置两次?我也不知道,反正一次不对。
  1502. return true;
  1503. });
  1504. if (pseat) {
  1505. $(".passenger_class").each(function () { $(this).find("select:eq(0)").val(pseat).change(); });
  1506. }
  1507. }
  1508. };
  1509. $(window).ajaxComplete(function (e, xhr, s) {
  1510. if (s.url.indexOf("getpassengerJson") != -1) {
  1511. console.log("[INFO][自动选择乘客] 系统联系人加载完成,正在检测预先选定");
  1512. autoSelectPassenger();
  1513. }
  1514. });
  1515. //如果已经加载完成,那么直接选定
  1516. if ($("#showPassengerFilter div").length) {
  1517. console.log("[INFO][自动选择乘客] OOPS,居然加载完成了?直接选定联系人");
  1518. autoSelectPassenger();
  1519. }
  1520. //#endregion
  1521. //#region 自动定位到随机码中
  1522. (function () {
  1523. var obj = document.getElementById("rand");
  1524. var oldOnload = window.onload;
  1525. window.onload = function () {
  1526. if (oldOnload) oldOnload();
  1527. obj.select();
  1528. };
  1529. obj.select();
  1530. })();
  1531. //#endregion
  1532. //#region 显示内部的选择上下铺
  1533. (function () {
  1534. //添加上下铺显示
  1535. $("tr.passenger_class").each(function () {
  1536. var tr = $(this);
  1537. var id = tr.attr("id");
  1538. tr.find("td:eq(2)").append("<select id='" + id + "_seat_detail' name='" + id + "_seat_detail'><option value='0'>随机</option><option value='2'>上铺</option><option value='2'>中铺</option><option value='1'>下铺</option></select>");
  1539. });
  1540. var seatSelector = $("select[name$=_seat]");
  1541. seatSelector.change(function () {
  1542. var self = $(this);
  1543. var val = self.val();
  1544. var l = self.next();
  1545. if (val == "2" || val == "3" || val == "4" || val == "6") {
  1546. l.show();
  1547. } else
  1548. l.hide();
  1549. var preseat = utility.getPref("preselectseatlevel");
  1550. if (preseat) {
  1551. l.val(preseat).change();
  1552. }
  1553. }).change();
  1554. })();
  1555. //#endregion
  1556. parent.$("#main").css("height", ($(document).height() + 300) + "px");
  1557. parent.window.setHeight(parent.window);
  1558. }
  1559. function autoCommitOrderInSandbox() {
  1560. //自动提示?
  1561. if (window.localStorage["bookTip"]) {
  1562. window.localStorage.removeItem("bookTip");
  1563. if (window.Audio) {
  1564. new window.Audio(utility.getAudioUrl()).play();
  1565. }
  1566. utility.notify("已经自动进入订票页面!请继续完成订单!");
  1567. }
  1568. }
  1569. //#endregion
  1570. //#region -----------------自动刷新----------------------
  1571. function initTicketQuery() {
  1572. //启用日志
  1573. utility.enableLog();
  1574. var initialized = false;
  1575. var seatLevelOrder = null;
  1576. var orderButtonClass = ".btn130_2"; //预定按钮的选择器
  1577. //#region 参数配置和常规工具界面
  1578. var queryCount = 0;
  1579. var timer = null;
  1580. var isTicketAvailable = false;
  1581. var audio = null; //通知声音
  1582. var timerCountDown = 0;
  1583. var timeCount = 0;
  1584. var autoBook = false;
  1585. //初始化表单
  1586. var form = $("form[name=querySingleForm] .cx_from:first");
  1587. form.find("tr:last").after("<tr class='append_row'><td colspan='9' id='queryFunctionRow'><label title='勾选此选项的话,每次你查询后,助手会帮你把始发站、到达站、日期等进行记录,下次进入查询页面后,将会帮您自动填写好'><input type='checkbox' id='keepinfo' checked='checked' />记住信息</label> <label title='勾选此选项后,假定查询的结果中没有符合你要求的车次,那么助手将会自动进行重新查询'><input checked='checked' type='checkbox' id='autoRequery' />自动重新查询</label>,每隔 <input style='width:50px;' type='number' min='5' value='5' size='4' id='refereshInterval' style='text-align:center;' />秒(最低5) " +
  1588. "<label title='勾选的话,当有票可定时,助手会放歌骚扰你'><input type='checkbox' checked='checked' id='chkAudioOn'>声音提示</label> <input type='button' id='chkSeatOnly' value='仅座票' class='lineButton' title='快速设置席别过滤按钮,点击后可快速勾选所有的座票,包括硬座软座一等座等等' /><input type='button' id='chkSleepOnly' value='仅卧铺' title='快速设置席别过滤按钮,点击后可快速勾选所有的卧铺,包括硬卧软卧什么的' class='lineButton' /><input type='button' id='chkAllSeat' value='全部席别' class='lineButton' title='快速勾选所有的席别' />" +
  1589. "<input type='button' id='enableNotify' οnclick='window.webkitNotifications.requestPermission();' value='点击启用桌面通知' style='line-height:25px;padding:5px;' /> <span id='refreshinfo'>已刷新 0 次,最后查询:--</span> <span id='refreshtimer'></span></td></tr>" +
  1590. "<tr class='append_row'><td colspan='9'><label title='设置有票时放的歌是不是放到天荒地老至死不渝'><input type='checkbox' checked='checked' id='chkAudioLoop'>声音循环</label>" +
  1591. "<span style='font-weight:bold;margin-left:10px;color:blue;' title='点击预定按钮时,有时候等待一会儿系统会提示服务器忙;勾选此选项后,如果出现这种情况,助手将会进行自动重新预定'><label><input type='checkbox' id='chkAutoResumitOrder' checked='checked' />预定失败时自动重试</label></span>" +
  1592. "<span style='font-weight:bold;margin-left:10px;color:blue;' title='有时候系统忙,查询会提示查询失败;勾选此选项后,如果出现这种情况,助手将会进行自动刷新查询'><label><input type='checkbox' id='chkAutoRequery' checked='checked' />查询失败时自动重试</label></span>" +
  1593. "<span style='font-weight:bold;margin-left:10px;color:pruple;' title='以服务器时间为准,未获得服务器时间之前,此选项不可用。启用智能加速模式时,在非正点附近时(大于0小于59分)按照正常速度刷新;当在正点附近时(大于等于59分时),暂停刷新并等到正点即刻刷新。'><label><input disabled='disabled' type='checkbox' id='chkSmartSpeed' />智能正点刷新模式</label></span>" +
  1594. "</td></tr>" +
  1595. "<tr class='append_row'><td id='filterFunctionRow' colspan='9'>" +
  1596. "<span style='font-weight:bold;color:red;'><label title='不可以预定的车次过滤掉的选项(隐藏起来不显示,无票的车次)'><input type='checkbox' id='chkFilterNonBookable' />过滤不可预订的车次</label></span>" +
  1597. "<span style='font-weight:bold;margin-left:10px;color:red;'><label title='有时候虽然整趟车可以预定,但是有票的席别都是你不要的,如果勾选此选项,也将会过滤掉'><input type='checkbox' id='chkFilterNonNeeded' />过滤不需要的席别</label></span>" +
  1598. "<span style='font-weight:bold;margin-left:10px;color:blue;display: none;'><label><input disabled='disabled' type='checkbox' id='chkFilterByTrain' />开启按车次过滤</label></span>" +
  1599. "</td></tr>" +
  1600. "<tr><td colspan='9' id='opFunctionRow'><input type='button' class='fish_button' disabled='disabled' value='停止声音' id='btnStopSound' /><input type='button' class='fish_button' disabled='disabled' value='停止刷新' id='btnStopRefresh' /><input type='button' class='fish_button' type='button' value='设置' id='configLink' /> <input type='button' class='fish_button' id='resetSettings' value='清空助手设置' /> <input type='button' class='fish_button configLink' value='IE登录' /> 【<a href='http://www.fishlee.net/soft/44/tour.html' style='color:purple;font-weight:bold;' target='_blank'>啊嘞……遇到不明白的啦?戳这里看教程呗</a>】<span style='margin-left:20px;color:purple;font-weight:bold;' id='serverMsg'></span></td> </tr>"
  1601. );
  1602. if (!window.Audio) {
  1603. $("#chkAudioOn, #chkAudioLoop, #btnStopSound").remove();
  1604. } else {
  1605. $("#btnStopSound").click(function () {
  1606. if (audio) {
  1607. audio.pause();
  1608. }
  1609. this.disabled = true;
  1610. });
  1611. }
  1612. $("#resetSettings").click(function () {
  1613. if (confirm("确定要清空助手的所有设置吗?")) {
  1614. window.localStorage.clear();
  1615. self.location.reload();
  1616. return false;
  1617. }
  1618. });
  1619. //操作控制
  1620. $("#btnStopRefresh").click(function () { resetTimer(); });
  1621. $("#chkSmartSpeed").change(function () {
  1622. });
  1623. //#endregion
  1624. //#region 显示座级选择UI
  1625. var ticketType = new Array();
  1626. var seatOptionTypeMap = {
  1627. "3": "9",
  1628. "4": "P",
  1629. "5": "M",
  1630. "6": "O",
  1631. "7": "6",
  1632. "8": "4",
  1633. "9": "3",
  1634. "10": "2",
  1635. "11": "1",
  1636. "12": "empty",
  1637. "13": "QT"
  1638. };
  1639. $(".hdr tr:eq(2) td").each(function (i, e) {
  1640. ticketType.push(false);
  1641. if (i < 3) return;
  1642. var obj = $(this);
  1643. ticketType[i] = (window.localStorage["typefilter_" + i] || "true") == "true";
  1644. //修改文字,避免换行
  1645. obj.attr("otext", obj.text());
  1646. var cap = $.trim(obj.text());
  1647. if (cap.length > 2) {
  1648. cap = cap.replace("座", "").replace("高级软卧", "高软");
  1649. obj.html(cap);
  1650. }
  1651. //加入复选框
  1652. var c = $("<input id='seatoption_" + seatOptionTypeMap[i] + "' type='checkbox' typecode='" + seatOptionTypeMap[i] + "' name='seatoption'/>").attr("checked", ticketType[i]);
  1653. c[0].ticketTypeId = i;
  1654. c.change(
  1655. function () {
  1656. ticketType[this.ticketTypeId] = this.checked;
  1657. window.localStorage["typefilter_" + this.ticketTypeId] = this.checked;
  1658. }).appendTo(obj);
  1659. });
  1660. //座级选择
  1661. $("#chkSeatOnly").click(function () {
  1662. $(".hdr tr:eq(2) td").each(function (i, e) {
  1663. var obj = $(this);
  1664. var txt = obj.attr("otext");
  1665. obj.find("input").attr("checked", typeof (txt) != 'undefined' && txt && txt.indexOf("座") != -1).change();
  1666. });
  1667. });
  1668. $("#chkSleepOnly").click(function () {
  1669. $(".hdr tr:eq(2) td").each(function (i, e) {
  1670. var obj = $(this);
  1671. var txt = obj.attr("otext");
  1672. obj.find("input").attr("checked", typeof (txt) != 'undefined' && txt && txt.indexOf("卧") != -1).change();
  1673. });
  1674. });
  1675. $("#chkAllSeat").click(function () {
  1676. $(":checkbox[name=seatoption]").attr("checked", true).change();
  1677. });
  1678. //#endregion
  1679. //#region 显示额外的功能区
  1680. var extrahtml = [];
  1681. extrahtml.push("<div class='outerbox' id='helperbox' style='width:auto;'><div class='box'><div class='title' style='position:relative;'>辅助工具 [<a href='#querySingleForm'>返回订票列表</a>] <div style='color:#066DFF;position:absolute;background-color: #eee;border: 1px solid purple;right:0px;top:0px;padding:2px;margin:2px;' title='时间依赖于本地时间保持在线刷新时间即时计算。受限于您的网速,并不十分准确(需要扣除网速的影响)' id='servertime'>服务器时间:<strong>----</strong>,本地时间:<strong>----</strong>,服务器比本地 <strong>----</strong></div></div>\
  1682. <table id='helpertooltable' style='width:100%;'><colgroup><col style='width:110px;' /><col style='width:370px;' /><col style='width:110px;' /><col style='width:auto;' /></colgroup>\
  1683. <tr class='fish_sep musicFunc' id='helperbox_bottom'><td class='name'>自定义音乐地址</td><td colspan='3'><input type='text' id='txtMusicUrl' value='" + utility.getAudioUrl() + "' οnfοcus='this.select();' style='width:50%;' /> <input type='button' οnclick='new Audio(document.getElementById(\"txtMusicUrl\").value).play();' value='测试'/><input type='button' οnclick='utility.resetAudioUrl(); document.getElementById(\"txtMusicUrl\").value=utility.getAudioUrl();' value='恢复默认'/> (地址第一次使用可能会需要等待一会儿)</td></tr>\
  1684. <tr class='fish_sep musicFunc'><td class='name'>可用音乐地址</td><td colspan='3'>");
  1685. var host1 = "http://resbak.fishlee.net/res/";
  1686. //var host2 = "https://github.com/iccfish/12306_ticket_helper/raw/master/res/";
  1687. var musics = [["music1.ogg", "超级玛丽"], ["music2.ogg", "蓝精灵"]];
  1688. $.each(musics, function () {
  1689. extrahtml.push("<a href='javascript:;' url='" + host1 + this[0] + "' class='murl'>" + this[1] + "</a>");
  1690. //extrahtml.push("<a href='javascript:;' url='" + host2 + this[0] + "' class='murl'>" + this[1] + "</a>(HTTPS)");
  1691. });
  1692. extrahtml.push("</td></tr><tr class='fish_sep'><td colspan='4'><input type='button' value='添加自定义车票时间段' id='btnDefineTimeRange' />\
  1693. <input type='button' value='清除自定义车票时间段' id='btnClearDefineTimeRange' /></td></tr>\
  1694. <tr class='fish_sep'><td style='text-align:center;' colspan='4'><a href='http://www.fishlee.net/soft/44/' target='_blank' style='color:purple;'>12306.CN 订票助手 by iFish(木鱼)</a> | <a href='http://t.qq.com/ccfish/' target='_blank' style='color:blue;'>腾讯微博</a> | <a href='http://www.fishlee.net/soft/44/announcement.html' style='color:blue;' target='_blank'>免责声明</a> | <a href='http://www.fishlee.net/Discussion/Index/44' target='_blank'>反馈BUG</a> | <a style='font-weight:bold;color:red;' href='http://www.fishlee.net/soft/44/donate.html' target='_blank'>捐助作者</a> | 版本 v" + window.helperVersion + ",许可于 <strong>" + utility.regInfo.name + ",类型 - " + utility.regInfo.typeDesc + "</strong> 【<a href='javascript:;' class='reSignHelper'>重新注册</a>】</td></tr>\
  1695. </table></div></div>");
  1696. $("body").append(extrahtml.join(""));
  1697. $("a.murl").live("click", function () {
  1698. $("#txtMusicUrl").val(this.getAttribute("url")).change();
  1699. });
  1700. $("#stopBut").before("<div class='jmp_cd' style='text-align:center;'><button class='fish_button' id='btnFilter'>加入黑名单</button><button class='fish_button' id='btnAutoBook'>自动预定本车次</button></div>");
  1701. $("#txtMusicUrl").change(function () { window.localStorage["audioUrl"] = this.value; });
  1702. $("form[name=querySingleForm]").attr("id", "querySingleForm");
  1703. //#endregion
  1704. //#region 添加自定义时间段
  1705. function addCustomTimeRange() {
  1706. var s = parseInt(prompt("请输入自定义时间段的起始时间(请填入小时,0-23)", "0"));
  1707. if (isNaN(s) || s < 0 || s > 23) {
  1708. alert("起始时间不正确 >_<"); return;
  1709. }
  1710. var e = parseInt(prompt("请输入自定义时间段的结束时间(请填入小时,1-24)", "24"));
  1711. if (isNaN(e) || e < 0 || e > 24) {
  1712. alert("结束时间不正确 >_<"); return;
  1713. }
  1714. var range = (s > 9 ? "" : "0") + s + ":00--" + (e > 9 ? "" : "0") + e + ":00";
  1715. if (confirm("您想要记住这个时间段吗?")) {
  1716. window.localStorage["customTimeRange"] = (window.localStorage["customTimeRange"] ? window.localStorage["customTimeRange"] + "|" : "") + range;
  1717. };
  1718. addCustomeTimeRangeToList(range);
  1719. }
  1720. function addCustomeTimeRangeToList(g) {
  1721. var obj = document.getElementById("startTime");
  1722. obj.options[obj.options.length] = new Option(g, g);
  1723. obj.selectedIndex = obj.options.length - 1;
  1724. }
  1725. if (window.localStorage["customTimeRange"]) {
  1726. var ctrs = window.localStorage["customTimeRange"].split("|");
  1727. $.each(ctrs, function () { addCustomeTimeRangeToList(this); });
  1728. }
  1729. $("#btnClearDefineTimeRange").click(function () {
  1730. if (!confirm("确定要清除自定义的时间段吗?清除后请刷新页面。")) return;
  1731. window.localStorage.removeItem("customTimeRange");
  1732. });
  1733. $("#btnDefineTimeRange").click(addCustomTimeRange);
  1734. //#endregion
  1735. //#region 过滤车次
  1736. var stopHover = window.onStopHover;
  1737. window.onStopHover = function (info) {
  1738. $("#stopDiv").attr("info", $.trim($("#id_" + info.split('#')[0]).text()));
  1739. stopHover.call(this, info);
  1740. $("#onStopHover").css("overflow", "hide");
  1741. };
  1742. $("#btnFilter").click(function () {
  1743. //加入黑名单
  1744. var trainNo = $("#stopDiv").attr("info").split('#')[0];
  1745. if (!trainNo || !confirm("确定要将车次【" + trainNo + "】加入黑名单?以后的查询将不再显示此车次。")) return;
  1746. list_blacklist.add(trainNo);
  1747. });
  1748. $("#btnAutoBook").click(function () {
  1749. //加入自动预定列表
  1750. var trainNo = $("#stopDiv").attr("info").split('#')[0];
  1751. if (isTrainInBlackList(trainNo)) {
  1752. alert("指定的车次在黑名单里呢……");
  1753. return;
  1754. }
  1755. if (!trainNo || !confirm("确定要将车次【" + trainNo + "】加入自动预定列表?如果下次查询有符合要求的席别将会自动进入预定页面。")) return;
  1756. list_autoorder.add(trainNo);
  1757. });
  1758. //清除进入指定页面后提示的标记位
  1759. if (window.localStorage["bookTip"]) window.localStorage.removeItem("bookTip");
  1760. //#endregion
  1761. //#region 自动重新查询
  1762. var clickButton = null;//点击的查询按钮
  1763. var filterNonBookable = $("#chkFilterNonBookable")[0]; //过滤不可定车次
  1764. var filterNonNeeded = $("#chkFilterNonNeeded")[0]; //过滤不需要车次
  1765. var onRequery = function () { }; //当重新查询时触发
  1766. var onNoTicket = function () { }; //当没有查到票时触发
  1767. $("#autoRequery").change(function () {
  1768. if (!this.checked)
  1769. resetTimer();
  1770. });
  1771. //刷新时间间隔
  1772. $("#refereshInterval").change(function () { timeCount = Math.max(5, parseInt($("#refereshInterval").val())); }).change();
  1773. //定时查询
  1774. var isSmartOn = false;
  1775. function resetTimer() {
  1776. queryCount = 0;
  1777. $("#btnStopRefresh")[0].disabled = true;
  1778. if (timer) {
  1779. clearInterval(timer);
  1780. timer = null;
  1781. }
  1782. $("#refreshtimer").html("");
  1783. }
  1784. function countDownTimer() {
  1785. timerCountDown -= 0.2;
  1786. var str = (Math.round(timerCountDown * 10) / 10) + "";
  1787. $("#refreshtimer").html("[" + (isSmartOn ? "等待正点," : "") + str + (str.indexOf('.') == -1 ? ".0" : "") + "秒后查询...]");
  1788. if (timerCountDown > 0) return;
  1789. clearInterval(timer);
  1790. timer = null;
  1791. onRequery();
  1792. doQuery();
  1793. }
  1794. function startTimer() {
  1795. if (timer) return;
  1796. var d = new Date().getMinutes();
  1797. isSmartOn = document.getElementById("chkSmartSpeed").checked && time_server && time_server.getMinutes() >= 59;
  1798. timerCountDown = isSmartOn ? 60 - time_server.getSeconds() + 2 : timeCount;
  1799. var str = (Math.round(timerCountDown * 10) / 10) + "";
  1800. $("#refreshtimer").html("[" + (isSmartOn ? "等待正点," : "") + timerCountDown + (str.indexOf('.') == -1 ? ".0" : "") + "秒后查询...]");
  1801. //没有定时器的时候,开启定时器准备刷新
  1802. $("#btnStopRefresh")[0].disabled = false;
  1803. timer = setInterval(countDownTimer, 200);
  1804. }
  1805. function displayQueryInfo() {
  1806. queryCount++;
  1807. $("#refreshinfo").html("已刷新 " + queryCount + " 次,最后查询:" + utility.getTimeInfo());
  1808. $("#refreshtimer").html("正在查询");
  1809. }
  1810. function doQuery() {
  1811. timer = null;
  1812. if (audio) audio.pause();
  1813. displayQueryInfo();
  1814. sendQueryFunc.call(clickBuyStudentTicket == "Y" ? document.getElementById("stu_submitQuery") : document.getElementById("submitQuery"));
  1815. }
  1816. //验证车票有开始
  1817. var onticketAvailable = function () {
  1818. resetTimer();
  1819. $("#refreshinfo").html("已经有票鸟!");
  1820. utility.notifyOnTop("可以订票了!");
  1821. if (window.Audio && $("#chkAudioOn")[0].checked) {
  1822. if (!audio) {
  1823. audio = new Audio($("#txtMusicUrl").val());
  1824. }
  1825. audio.loop = $("#chkAudioLoop")[0].checked;
  1826. $("#btnStopSound")[0].disabled = false;
  1827. audio.play();
  1828. }
  1829. }
  1830. //检查是否可以订票
  1831. var checkTicketsQueue = [];
  1832. var checkTicketCellsQueue = [];
  1833. function getTrainNo(row) {
  1834. /// <summary>获得行的车次号</summary>
  1835. return $.trim($("td:eq(0)", row).text());
  1836. }
  1837. //默认的单元格检测函数
  1838. checkTicketCellsQueue.push(function (i, e) {
  1839. if (!ticketType[i - 1]) return 0;
  1840. var el = $(e);
  1841. var info = $.trim(el.text()); //Firefox不支持 innerText
  1842. if (info == "*" || info == "--" || info == "无") {
  1843. return 0;
  1844. }
  1845. return 2;
  1846. });
  1847. //默认的行检测函数
  1848. checkTicketsQueue.push(function () {
  1849. var trainNo = getTrainNo(this);
  1850. var tr = this;
  1851. this.attr("tcode", trainNo);
  1852. //黑名单过滤
  1853. if (isTrainInBlackList(trainNo)) {
  1854. this.hide();
  1855. return 0;
  1856. }
  1857. var hasTicket = 1;
  1858. if ($("a.btn130", this).length > 0) return 0;
  1859. $("td", this).each(function (i, e) {
  1860. var cellResult = 0;
  1861. e = $(e);
  1862. var opt = { code: trainNo, tr: tr, index: e.index(), seatType: seatOptionTypeMap[e.index() - 1] };
  1863. e.attr("scode", opt.seatType);
  1864. $.each(checkTicketCellsQueue, function () {
  1865. cellResult = this(i, e, cellResult, opt) || cellResult;
  1866. return cellResult != 0;
  1867. });
  1868. e.attr("result", cellResult);
  1869. if (cellResult == 2) {
  1870. hasTicket = 2;
  1871. e.css("background-color", "#95AFFD");
  1872. }
  1873. });
  1874. tr.attr("result", hasTicket);
  1875. return hasTicket;
  1876. });
  1877. //检测是否有余票的函数
  1878. var checkTickets = function () {
  1879. var result = 0;
  1880. var row = this;
  1881. $.each(checkTicketsQueue, function () {
  1882. result = this.call(row, result);
  1883. return true;
  1884. });
  1885. return result;
  1886. }
  1887. //目标表格,当ajax完成时检测是否有票
  1888. $("body").ajaxComplete(function (e, r, s) {
  1889. //HACK-阻止重复调用
  1890. if (timer != null) return;
  1891. if (s.url.indexOf("queryLeftTicket") == -1)
  1892. return;
  1893. //验证有票
  1894. var rows = $("table.obj tr:gt(0)");
  1895. var ticketValid = false;
  1896. var validRows = {};
  1897. rows.each(function () {
  1898. var row = $(this);
  1899. var valid = checkTickets.call(row);
  1900. var code = getTrainNo(row);
  1901. row.attr("tcode", code);
  1902. row.find("td:eq(0)").click(putTrainCodeToList);
  1903. console.log("[INFO][车票可用性校验] " + code + " 校验结果=" + valid);
  1904. if (valid == 2) {
  1905. row.css("background-color", "#FD855C");
  1906. validRows[code] = row;
  1907. }
  1908. else {
  1909. if (valid == 1 && filterNonNeeded.checked) row.hide();
  1910. if (valid == 0 && filterNonBookable.checked) row.hide();
  1911. }
  1912. ticketValid = ticketValid || valid == 2;
  1913. });
  1914. //自动预定
  1915. if ($("#swAutoBook:checked").length > 0) {
  1916. if (!seatLevelOrder || !seatLevelOrder.length) {
  1917. //没有席别优先级,那选第一个
  1918. for (var idx in list_autoorder.datalist) {
  1919. var code = list_autoorder.datalist[idx];
  1920. var reg = utility.getRegCache(code);
  1921. var row = $.first(validRows, function (i, v) {
  1922. if (reg.test(i)) return v;
  1923. });
  1924. if (row) {
  1925. if (document.getElementById("autoBookTip").checked) {
  1926. window.localStorage["bookTip"] = 1;
  1927. }
  1928. row.find("a[name=btn130_2]").click();
  1929. return false;
  1930. }
  1931. };
  1932. } else {
  1933. console.log("按席别优先选择-车次过滤");
  1934. var trains = $.makeArray($("#gridbox tr[result=2]"));
  1935. var trainfiltered = [];
  1936. for (var idx in list_autoorder.datalist) {
  1937. //对车次进行过滤并按优先级排序
  1938. var rule = list_autoorder.datalist[idx];
  1939. var ruleTester = utility.getRegCache(rule);
  1940. for (var i = trains.length - 1; i >= 0; i--) {
  1941. var self = $(trains[i]);
  1942. var code = self.attr("tcode");
  1943. if (ruleTester.test(code)) {
  1944. trainfiltered.push(self);
  1945. trains.splice(i, 1);
  1946. }
  1947. }
  1948. }
  1949. if (document.getElementById("autoorder_method").selectedIndex == 0) {
  1950. $.each(seatLevelOrder, function () {
  1951. var scode = this;
  1952. for (var i in trainfiltered) {
  1953. var t = trainfiltered[i];
  1954. if (t.find("td[scode=" + this + "][result=2]").length) {
  1955. var tcode = scode == "empty" ? "1" : scode;
  1956. window.localStorage.setItem("autoSelect_preSelectSeatType", tcode);
  1957. $("#preSelectSeat").val(tcode)
  1958. if (document.getElementById("autoBookTip").checked) {
  1959. window.localStorage["bookTip"] = 1;
  1960. }
  1961. t.find(orderButtonClass).click();
  1962. return false;
  1963. }
  1964. }
  1965. return true;
  1966. });
  1967. } else {
  1968. //车次优先
  1969. $.each(trainfiltered, function () {
  1970. var t = this;
  1971. for (var i in seatLevelOrder) {
  1972. var scode = seatLevelOrder[i];
  1973. if (t.find("td[scode=" + scode + "][result=2]").length) {
  1974. var tcode = scode == "empty" ? "1" : scode;
  1975. window.localStorage.setItem("autoSelect_preSelectSeatType", tcode);
  1976. $("#preSelectSeat").val(tcode)
  1977. if (document.getElementById("autoBookTip").checked) {
  1978. window.localStorage["bookTip"] = 1;
  1979. }
  1980. t.find(orderButtonClass).click();
  1981. return false;
  1982. }
  1983. }
  1984. return true;
  1985. });
  1986. }
  1987. }
  1988. }
  1989. if (ticketValid) {
  1990. onticketAvailable();
  1991. } else if (document.getElementById("autoRequery").checked) {
  1992. onNoTicket();
  1993. startTimer();
  1994. }
  1995. });
  1996. //系统繁忙时自动重复查询 chkAutoResumitOrder
  1997. $("#orderForm").submit(function () {
  1998. if ($("#chkAutoResumitOrder")[0].checked) {
  1999. parent.$("#orderForm").remove();
  2000. parent.$("body").append($("#orderForm").clone(false).attr("target", "main").attr("success", "0"));
  2001. }
  2002. });
  2003. $("body").ajaxComplete(function (e, r, s) {
  2004. if (!$("#chkAutoRequery")[0].checked) return;
  2005. if (s.url.indexOf("/otsweb/order/querySingleAction.do") != -1 && r.responseText == "-1") {
  2006. //invalidQueryButton();
  2007. //delayButton();
  2008. //startTimer();
  2009. } else {
  2010. $("#serverMsg").html("");
  2011. }
  2012. });
  2013. $("body").ajaxError(function (e, r, s) {
  2014. if (s.url.indexOf("queryLeftTicket") == -1) return;
  2015. if (!$("#chkAutoRequery")[0].checked) return;
  2016. if (s.url.indexOf("/otsweb/order/querySingleAction.do") != -1) {
  2017. delayButton();
  2018. startTimer();
  2019. }
  2020. });
  2021. //Hack掉原来的系统函数。丫居然把所有的click事件全部处理了,鄙视
  2022. window.invalidQueryButton = function () {
  2023. var queryButton = $("#submitQuery");
  2024. queryButton.unbind("click", sendQueryFunc);
  2025. if (queryButton.attr("class") == "research_u") {
  2026. renameButton("research_x");
  2027. } else if (queryButton.attr("class") == "search_u") {
  2028. renameButton("search_x");
  2029. }
  2030. }
  2031. //#endregion
  2032. //#region 配置加载、保存、权限检测
  2033. //通知权限
  2034. if (!window.webkitNotifications || window.webkitNotifications.checkPermission() == 0) {
  2035. $("#enableNotify").remove();
  2036. }
  2037. //保存信息
  2038. function saveStateInfo() {
  2039. if (!$("#keepinfo")[0].checked || $("#fromStationText")[0].disabled) return;
  2040. utility.setPref("_from_station_text", $("#fromStationText").val());
  2041. utility.setPref("_from_station_telecode", $("#fromStation").val());
  2042. utility.setPref("_to_station_text", $("#toStationText").val());
  2043. utility.setPref("_to_station_telecode", $("#toStation").val());
  2044. utility.setPref("_depart_date", $("#startdatepicker").val());
  2045. utility.setPref("_depart_time", $("#startTime").val());
  2046. }
  2047. $("#submitQuery, #stu_submitQuery").click(saveStateInfo);
  2048. //回填信息
  2049. if (!$("#fromStationText")[0].disabled) {
  2050. var FROM_STATION_TEXT = utility.getPref('_from_station_text'); // 出发站名称
  2051. var FROM_STATION_TELECODE = utility.getPref('_from_station_telecode'); // 出发站电报码
  2052. var TO_STATION_TEXT = utility.getPref('_to_station_text'); // 到达站名称
  2053. var TO_STATION_TELECODE = utility.getPref('_to_station_telecode'); // 到达站电报码
  2054. var DEPART_DATE = utility.getPref('_depart_date'); // 出发日期
  2055. var DEPART_TIME = utility.getPref('_depart_time'); // 出发时间
  2056. if (FROM_STATION_TEXT) {
  2057. $("#fromStationText").val(FROM_STATION_TEXT);
  2058. $("#fromStation").val(FROM_STATION_TELECODE);
  2059. $("#toStationText").val(TO_STATION_TEXT);
  2060. $("#toStation").val(TO_STATION_TELECODE);
  2061. $("#startdatepicker").val(DEPART_DATE);
  2062. $("#startTime").val(DEPART_TIME);
  2063. }
  2064. }
  2065. //音乐
  2066. if (!window.Audio) {
  2067. $(".musicFunc").hide();
  2068. }
  2069. //#endregion
  2070. //#region 时间快捷修改
  2071. (function () {
  2072. var datebox = $("table.cx_from tr:eq(0) td:eq(5), table.cx_from tr:eq(1) td:eq(3)");
  2073. datebox.width("170px");
  2074. datebox.find("input").width("70px").before('<input type="button" class="date_prev lineButton" value="<">').after('<input type="button" class="date_next lineButton" value=">">');
  2075. datebox.find(".date_prev").click(function () { var dobj = $(this).next(); dobj.val(utility.formatDate(utility.addTimeSpan(utility.parseDate(dobj.val()), 0, 0, -1, 0, 0, 0))).change(); });
  2076. datebox.find(".date_next").click(function () { var dobj = $(this).prev(); dobj.val(utility.formatDate(utility.addTimeSpan(utility.parseDate(dobj.val()), 0, 0, 1, 0, 0, 0))).change(); });
  2077. })();
  2078. //#endregion
  2079. //#region 自动轮询,自动更改时间
  2080. (function () { //初始化UI
  2081. var html = "<tr class='fish_sep' id='autoChangeDateRow'><td class='name'>查询日期</td><td>\
  2082. <label><input type='checkbox' id='autoCorrentDate' checked='checked' /> 查询日期早于或等于今天时,自动修改为明天</label>\
  2083. </td><td class='name'>自动轮查</td><td><label><input type='checkbox' id='autoChangeDate' /> 无票时自动更改日期轮查</label>\
  2084. </td></tr><tr class='fish_sep' style='display:none;'><td class='name'>轮查日期设置</td><td colspan='3' id='autoChangeDateList'></td></tr>\
  2085. ";
  2086. $("#helperbox_bottom").before(html);
  2087. var autoChangeDateList = $("#autoChangeDateList");
  2088. var html = [];
  2089. var now = new Date();
  2090. for (var i = 0; i < 20; i++) {
  2091. now = utility.addTimeSpan(now, 0, 0, 1, 0, 0, 0);
  2092. html.push("<label style='margin-right:16px;'><input type='checkbox' value='" + utility.formatDate(now) + "' cindex='" + i + "' />" + utility.formatDateShort(now) + "</label>");
  2093. if ((i + 1) % 10 == 0)
  2094. html.push("<br />");
  2095. }
  2096. autoChangeDateList.html(html.join(""));
  2097. $("#autoChangeDate").change(function () {
  2098. var tr = $(this).closest("tr").next();
  2099. if (this.checked) tr.show();
  2100. else tr.hide();
  2101. });
  2102. //配置
  2103. utility.reloadPrefs($("#autoChangeDateRow"), "autoChangeDateRow");
  2104. //日期点选
  2105. var stKey = "autoChangeDateRow_dates";
  2106. var stValue = window.localStorage.getItem(stKey);
  2107. if (typeof (stValue) != 'undefined' && stValue) {
  2108. var array = stValue.split('|');
  2109. autoChangeDateList.find(":checkbox").each(function () {
  2110. this.checked = $.inArray(this.value, array) != -1;
  2111. });
  2112. }
  2113. autoChangeDateList.find(":checkbox").change(function () {
  2114. var value = $.map(autoChangeDateList.find(":checkbox:checked"), function (e, i) { return e.value; }).join("|")
  2115. window.localStorage.setItem(stKey, value);
  2116. });
  2117. })();
  2118. (function () {
  2119. //如果当前查询日期在当前日期或之前,那么自动修改日期
  2120. $("#startdatepicker, #roundTrainDate").change(function () {
  2121. if (!document.getElementById("autoCorrentDate").checked) return;
  2122. var obj = $(this);
  2123. var val = utility.parseDate(obj.val());
  2124. var tomorrow = utility.addTimeSpan(utility.getDate(new Date()), 0, 0, 1, 0, 0, 0);
  2125. if (!val || isNaN(val.getFullYear()) || tomorrow > val) {
  2126. console.log("自动修改日期为 " + utility.formatDate(tomorrow));
  2127. obj.val(utility.formatDate(tomorrow));
  2128. }
  2129. }).change();
  2130. })();
  2131. onNoTicket = (function (callback) {
  2132. return function () {
  2133. //Hook onNoTicket
  2134. callback();
  2135. if (!document.getElementById("autoChangeDate").checked) return;
  2136. console.log("自动轮询日期中。");
  2137. var index = parseInt($("#autoChangeDate").attr("cindex"));
  2138. if (isNaN(index)) index = -1;
  2139. var current = index == -1 ? [] : $("#autoChangeDateList :checkbox:eq(" + index + ")").parent().nextAll(":has(:checked):eq(0)").find("input");
  2140. if (current.length == 0) {
  2141. index = 0;
  2142. current = $("#autoChangeDateList :checkbox:checked:first");
  2143. if (current.length == 0) return; //没有选择任何
  2144. }
  2145. index = current.attr("cindex");
  2146. if (current.length > 0) {
  2147. $("#autoChangeDate").attr("cindex", index);
  2148. $("#startdatepicker").val(current.val());
  2149. //高亮
  2150. $("#cx_titleleft span").css({ color: 'red', 'font-weight': 'bold' });
  2151. }
  2152. };
  2153. }
  2154. )(onNoTicket);
  2155. //#endregion
  2156. //#region 拦截弹出的提示框,比如服务器忙
  2157. (function () {
  2158. var _bakAlert = window.alert;
  2159. window.alert = function (msg) {
  2160. if (msg.indexOf("服务器忙") != -1) {
  2161. $("#serverMsg").text(msg);
  2162. } else _bakAlert(msg);
  2163. }
  2164. })();
  2165. //#endregion
  2166. //#region 默认加入拦截Ajax缓存
  2167. (function () { $.ajaxSetup({ cache: false }); })();
  2168. //#endregion
  2169. //#region 显示所有的乘客
  2170. var list_autoorder = null;
  2171. var list_blacklist = null;
  2172. var list_whitelist = null;
  2173. function isTrainInBlackList(trainNo) {
  2174. /// <summary>返回指定的车次是否在黑名单中</summary>
  2175. return document.getElementById("swBlackList").checked && (list_blacklist.isInRegList(trainNo)) && !(document.getElementById("swWhiteList").checked && list_whitelist.isInRegList(trainNo));
  2176. }
  2177. function putTrainCodeToList() {
  2178. var code = $(this).closest("tr").attr("tcode");
  2179. if (confirm("是否要将【" + code + "】加入自动预定列表?如果不是,请点击取消并继续选择是否加入黑名单或白名单。")) {
  2180. list_autoorder.add(code);
  2181. } else if (confirm("是否要将【" + code + "】加入黑名单?如果不是,请点击取消并继续选择是否加入白名单。")) {
  2182. list_blacklist.add(code);
  2183. } else if (confirm("是否要将【" + code + "】加入白名单?")) {
  2184. list_whitelist.add(code);
  2185. };
  2186. }
  2187. (function () {
  2188. var html = "\
  2189. <tr class='fish_sep caption'><td><label><input type='checkbox' id='swWhiteList' checked='checked' /> 车次白名单</label></td><td style='font-weight:normal;' colspan='2'>加入白名单的车次,将不会被过滤(仅为搭配黑名单)</td><td style='text-align:rigth;'><button class='fish_button' id='btnAddWhite'>添加</button><button class='fish_button' id='btnClearWhite'>清空</button></td></tr>\
  2190. <tr class='fish_sep'><td colspan='4' id='whiteListTd'></td></tr>\
  2191. <tr class='fish_sep caption'><td><label><input type='checkbox' id='swBlackList' checked='checked' name='swBlackList' />车次黑名单</label></td><td style='font-weight:normal;' colspan='2'>加入黑名单的车次,除非在白名单中,否则会被直接过滤而不会显示</td><td style='text-align:rigth;'><button class='fish_button' id='btnAddBlack'>添加</button><button class='fish_button' id='btnClearBlack'>清空</button></td></tr>\
  2192. <tr class='fish_sep'><td colspan='4' id='blackListTd'></td></tr>\
  2193. <tr class='caption autoorder_steps fish_sep' id='selectPasRow'><td colspan='3'><span class='hide indicator'>① </span>自动添加乘客 (加入此列表的乘客将会自动在提交订单的页面中添加上,<strong>最多选五位</strong>)</td><td><input type='button' class='fish_button' οnclick=\"self.location='/otsweb/passengerAction.do?method=initAddPassenger&';\" value='添加联系人' /> (提示:新加的联系人五分钟之内无法订票)</td></tr>\
  2194. <tr class='fish_sep'><td class='name'>未选择</td><td id='passengerList' colspan='3'><span style='color:gray; font-style:italic;'>联系人列表正在加载中,请稍等...如果长时间无法加载成功,请尝试刷新页面 x_x</span></td></tr>\
  2195. <tr class='fish_sep'><td class='name'>已选择</td><td id='passengerList1' colspan='3'></td></tr>\
  2196. <tr class='fish_sep autoordertip' style='display:none;'><td class='name'>部分提交订单</td><td><label><input type='checkbox' id='autoorder_part' /> 当票数不足时,允许为部分的联系人先提交订单</label></td><td class='name'>提交为学生票</td><td><label><input type='checkbox' id='autoorder_stu' /> 即使是普通查询,也为学生联系人提交学生票</label></td></tr>\
  2197. <tr class='fish_sep autoorder_steps caption' id='seatLevelRow'><td><span class='hide indicator'>② </span>席别优先选择</td><td><input type='hidden' id='preSelectSeat' /><select id='preSelectSeatList'></select> (选中添加,点击按钮删除;<a href='http://www.fishlee.net/soft/44/tour.html' target='_blank'>更多帮助</a>)</td><td style='text-align:right;'>卧铺优选</td><td><select id='preselectseatlevel'></select>(不一定有用的啦……呵呵呵呵呵呵……)</td></tr>\
  2198. <tr class='fish_sep'><td colspan='4' id='preseatlist'><div id='preseatlist_empty' style='padding:5px; border: 1px dashed gray; background-color:#eee;width:200px;'>(尚未指定,请从上面的下拉框中选定)</div></td></tr>\
  2199. <tr class='fish_sep autoorder_steps caption'><td><label><input type='checkbox' id='swAutoBook' name='swAutoBook' checked='checked' /><span class='hide indicator'>③</span> 自动预定</label></td><td colspan='2' style='font-weight:normal;'><select id='autoorder_method'><option value='0'>席别优先</option><option value='1'>车次优先</option></select>如果启用,符合规则的车次的特定席别有效时,将会进入预定页面</td><td style='text-align:rigth;'><button id='btnAddAutoBook' class='fish_button'>添加</button><button id='btnClearAutoBook' class='fish_button'>清空</button></td></tr>\
  2200. <tr class='fish_sep'><td colspan='4' id='autobookListTd'></td></tr>\
  2201. <tr class='fish_sep'><td colspan='4'><label><input type='checkbox' id='autoBookTip' checked='checked' /> 如果自动预定成功,进入预定页面后播放提示音乐并弹窗提示</label></td></tr>\
  2202. <tr class='fish_sep autoordertip' style='display:none;'><td class='name'>自动回滚</td><td><label><input type='checkbox' id='autoorder_autocancel' /> 自动提交失败时,自动取消自动提交并再次预定</label></td></tr>\
  2203. <tr class='caption autoorder_steps fish_sep highlightrow'><td class='name autoordertd'><label style='display:none;color:red;'><input type='checkbox' id='autoorder'/>自动提交订单</label></td><td class='autoordertd' colspan='3'><p style='display:none;'><img id='randCode' src='/otsweb/passCodeAction.do?rand=randp' /> <input size='4' maxlength='4' type='text' id='randCodeTxt' /> (验证码可在放票前填写,临近放票时建议点击图片刷新并重新填写,以策安全。请务必控制好阁下的眼神……)</p></td></tr>\
  2204. <tr style='display:none;' class='autoordertip fish_sep'><td class='name' style='color:red;'>警告</td><td colspan='3' style='color:darkblue;'>\
  2205. <p style='font-weight:bold; color:purple;'>自动提交订单使用流程:勾选要订票的联系人 -> 设置需要的席别 -> 将你需要订票的车次按优先级别加入自动预定列表 -> 勾选自动提交订单 -> 输入验证码 -> 开始查票。信息填写不完整将会导致助手忽略自动提交订单,请务必注意。进入自动订票模式后,席别选择和自动预定都将被锁定而无法手动切换。如果查询的是学生票,那么提交的将会是学生票订单。<u style='color:red;'>一切都设置完成后,请点击查询开始查票。一旦有票将会自动提交。</u></p>\
  2206. <p>1. 自动提交订单使用的是自动预定的列表顺序,取第一个有效的车次自动提交订单!请确认设置正确!!</p>\
  2207. <p>2. 自动提交的席别和联系人请在上方选择,和预设的是一致的,暂不支持不同的联系人选择不同的席别;</p>\
  2208. <p>3. 作者无法保证自动提交是否会因为铁老大的修改失效,因此请务必同时使用<b>其它浏览器</b>手动提交订单!否则可能会造成您不必要的损失!</p>\
  2209. <p style='font-weight:bold;'>5. 当助手第一次因为功能性自动提交失败后(非网络错误和验证码错误,如余票不足、占座失败等),将会立刻禁用自动提交并回滚到普通提交,并再次提交订票请求,因此请时刻注意提交结果并及时填写内容,并强烈建议你另外打开单独的浏览器同时手动下订单!!</p>\
  2210. <p style='font-weight:bold;color:darkcylan;'>6. 为可靠起见,建议每隔一段时间刷新下验证码重新填写(点击验证码图片刷新)。由于不同的浏览器刷新的结果不一样,强烈建议多个浏览器或多台机子一起刷新!</p>\
  2211. <p style='font-size:16px; font-weight:bold;color:blue;'>一定要仔细看说明啊!切记多个浏览器准备不要老想着一棵树上吊死啊!千万不要因为自动提交订单导致你订不到票啊!!这样老衲会内疚的啊!!!!</p>\
  2212. </td></tr>";
  2213. $("#helpertooltable tr:first").addClass("fish_sep").before(html);
  2214. //优选逻辑
  2215. $("#autoorder_method").val(window.localStorage["autoorder_method"] || "0").change(function () { window.localStorage.setItem("autoorder_method", $(this).val()); });
  2216. $("#autoorder_autocancel").attr("checked", (window.localStorage["autoorder_autocancel"] || "1") == "1").change(function () { window.localStorage.setItem("autoorder_autocancel", this.checked ? "1" : "0"); });
  2217. //自动预定列表
  2218. list_autoorder = utility.selectionArea.call($("#autobookListTd"), { syncToStorageKey: "list_autoBookList", onAdd: onAutoOrderRowStyle, onRemove: onAutoOrderRowStyle, onClear: onAutoOrderRowStyle });
  2219. list_blacklist = utility.selectionArea.call($("#blackListTd"), { syncToStorageKey: "list_blackList" });
  2220. list_whitelist = utility.selectionArea.call($("#whiteListTd"), { syncToStorageKey: "list_whiteList" });
  2221. var autoBookHeader = $("#swAutoBook").closest("tr");
  2222. function onAutoOrderRowStyle() {
  2223. if (!document.getElementById("autoorder").checked) return;
  2224. autoBookHeader.removeClass("steps stepsok");
  2225. autoBookHeader.addClass(list_autoorder.datalist.length ? "stepsok" : "steps");
  2226. }
  2227. function appendTrainCodeToList(target) {
  2228. var code = prompt("请输入您要加入列表的车次。车次可以使用正则表达式(亲,不知道的话请直接填写车次编号喔),比如 【.*】(不包括【】号) 可以代表所有车次,【K.*】可以代表所有K字头的车次,【D.*】可以代表所有D字头车次等等");
  2229. if (!code) return;
  2230. //修正部分符号
  2231. code = code.replace(/(,|,|\/|\\|、|-)/g, "|");
  2232. try {
  2233. new RegExp(code);
  2234. } catch (e) {
  2235. alert("嗯……看起来同学您输入的不是正确的正则表达式哦。");
  2236. return;
  2237. }
  2238. target.add(code);
  2239. }
  2240. function emptyList(target) {
  2241. target.emptyList();
  2242. }
  2243. //绑定添加清空事件
  2244. $("#btnAddAutoBook").click(function () { appendTrainCodeToList(list_autoorder); });
  2245. $("#btnAddWhite").click(function () { appendTrainCodeToList(list_whitelist); });
  2246. $("#btnAddBlack").click(function () { appendTrainCodeToList(list_blacklist); });
  2247. $("#btnClearAutoBook").click(function () { emptyList(list_autoorder); });
  2248. $("#btnClearWhite").click(function () { emptyList(list_whitelist); });
  2249. $("#btnClearBlack").click(function () { emptyList(list_blacklist); });
  2250. $("#swBlackList, #swAutoBook").each(function () {
  2251. var obj = $(this);
  2252. var name = obj.attr("name");
  2253. var opt = localStorage.getItem(name);
  2254. if (opt != null) this.checked = opt == "1";
  2255. }).change(function () {
  2256. var obj = $(this);
  2257. var name = obj.attr("name");
  2258. localStorage.setItem(name, this.checked ? "1" : "0");
  2259. });
  2260. var seatlist = [
  2261. ["", "=请选择="],
  2262. ["9", "商务座"],
  2263. ["P", "特等座"],
  2264. ["6", "高级软卧"],
  2265. ["4", "软卧"],
  2266. ["3", "硬卧"],
  2267. ["2", "软座"],
  2268. ["1", "硬座"],
  2269. ["empty", "硬座(无座)"],
  2270. ["M", "一等座"],
  2271. ["O", "二等座"]
  2272. ];
  2273. var level = [[0, '随机'], [3, "上铺"], [2, '中铺'], [1, '下铺']];
  2274. var seatDom = document.getElementById("preSelectSeatList");
  2275. var seatLevelDom = document.getElementById("preselectseatlevel");
  2276. $.each(seatlist, function () {
  2277. seatDom.options[seatDom.options.length] = new Option(this[1], this[0]);
  2278. });
  2279. $.each(level, function () {
  2280. seatLevelDom.options[seatLevelDom.options.length] = new Option(this[1], this[0]);
  2281. });
  2282. //刷新优选列表
  2283. var seatLevelRow = $("#seatLevelRow");
  2284. function refreshSeatTypeOrder() {
  2285. var list = $("#preseatlist input");
  2286. if (initialized) $(":checkbox[name=seatoption]").attr("checked", false).change();
  2287. seatLevelOrder = [];
  2288. list.each(function () {
  2289. var code = $(this).attr("code");
  2290. seatLevelOrder.push(code);
  2291. if (initialized) $("#seatoption_" + code).attr("checked", true).change();
  2292. });
  2293. if (!list.length) {
  2294. $("#preseatlist_empty").show();
  2295. $(":checkbox[name=seatoption]").attr("checked", true).change();
  2296. window.localStorage.setItem("autoSelect_preSelectSeatType", "");
  2297. } else {
  2298. $("#preseatlist_empty").hide();
  2299. window.localStorage.setItem("autoSelect_preSelectSeatType", seatLevelOrder[0]);
  2300. }
  2301. if (initialized) utility.notifyOnTop("已经根据您选择的席别自动切换了席别过滤选项,请注意,并作出需要的调整。");
  2302. window.localStorage.setItem("preSelectSeatType", seatLevelOrder.join('|'));
  2303. if (document.getElementById("autoorder").checked) {
  2304. seatLevelRow.removeClass("stepsok steps");
  2305. seatLevelRow.addClass(seatLevelOrder.length ? "stepsok" : "steps");
  2306. }
  2307. }
  2308. //选中后添加到列表中
  2309. $("#preSelectSeatList").change(function () {
  2310. var index = seatDom.selectedIndex;
  2311. if (index == 0) return;
  2312. //添加
  2313. var opt = seatDom.options[index];
  2314. var html = "<input type='button' title='点击删除' class='seatTypeButton lineButton' value='" + opt.text + "' code='" + opt.value + "' />";
  2315. $("#preseatlist").append(html);
  2316. $("#preseatlist_empty").hide();
  2317. //当前选项移除
  2318. seatDom.options[index] = null;
  2319. seatDom.selectedIndex = 0;
  2320. refreshSeatTypeOrder();
  2321. });
  2322. //席别的按钮点击后自动删除
  2323. $("input.seatTypeButton").live("click", function () {
  2324. var btn = $(this);
  2325. btn.remove();
  2326. //加回列表
  2327. var code = btn.attr("code");
  2328. var name = btn.val();
  2329. seatDom.options[seatDom.options.length] = new Option(name, code);
  2330. //刷新列表
  2331. refreshSeatTypeOrder();
  2332. });
  2333. (function () {
  2334. var preseattype = window.localStorage.getItem("preSelectSeatType") || window.localStorage.getItem("autoSelect_preSelectSeatType");
  2335. if (!preseattype) return;
  2336. preseattype = preseattype.split('|');
  2337. var el = $(seatDom);
  2338. $.each(preseattype, function () { el.val(this + ""); el.change(); });
  2339. })();
  2340. $(seatLevelDom).val(window.localStorage.getItem("preselectseatlevel") || "").change(function () {
  2341. window.localStorage.setItem("preselectseatlevel", $(this).val());
  2342. });
  2343. var pre_autoorder_book_status;
  2344. $("#autoorder").click(function () {
  2345. if (this.checked) {
  2346. pre_autoorder_book_status = document.getElementById("swAutoBook").checked;
  2347. document.getElementById("swAutoBook").checked = true;
  2348. //alert("警告!选中将会启用自动下单功能,并取代自动预定功能,请输入验证码,当指定的车次中的指定席别可用时,助手将会为您全自动下单。\n\n请确认您设置了正确的车次和席别!\n\n但是,作者无法保证是否会因为铁道部的修改导致失效,请使用此功能的同时务必使用传统的手动下单以保证不会导致您的损失!");
  2349. }
  2350. document.getElementById("swAutoBook").disabled = this.checked;
  2351. if (this.checked) {
  2352. $(".autoordertip").show();
  2353. $(":checkbox[name=seatoption]").attr("disabled", true);
  2354. refreshSeatTypeOrder();
  2355. onAutoOrderRowStyle();
  2356. }
  2357. else {
  2358. $(".autoordertip").hide();
  2359. document.getElementById("swAutoBook").checked = pre_autoorder_book_status;
  2360. $(":checkbox[name=seatoption]").attr("disabled", false);
  2361. $("tr.autoorder_steps").removeClass("steps").removeClass("stepsok");
  2362. }
  2363. });
  2364. //禁用自动预定
  2365. //加载乘客
  2366. utility.getAllPassengers(function (list) {
  2367. var h = [];
  2368. var check = (localStorage.getItem("preSelectPassenger") || "").split('|');
  2369. var index = 0;
  2370. $.each(list, function () {
  2371. var value = this.passenger_name + this.passenger_id_type_code + this.passenger_id_no;
  2372. this.index = index++;
  2373. h.push("<label style='margin-right:10px;'><input type='checkbox' id='preSelectPassenger" + this.index + "' name='preSelectPassenger'" + ($.inArray(value, check) > -1 ? " checked='checked'" : "") + " value='" + value + "' />" + this.passenger_name + "</label>");
  2374. });
  2375. $("#passengerList").html(h.join("")).find("input").change(function () {
  2376. var self = $(this).closest("label");
  2377. if (this.checked) {
  2378. var selected = $("#passengerList1 :checkbox");
  2379. if (selected.length >= 5) {
  2380. alert("选择的乘客不能多于五位喔~~");
  2381. this.checked = false;
  2382. return;
  2383. }
  2384. $("#passengerList1").append(self);
  2385. } else {
  2386. $("#passengerList").append(self);
  2387. }
  2388. selected = $("#passengerList1 :checkbox");
  2389. var user = $.map(selected, function (e) { return e.value; });
  2390. $("#ticketLimition").val(selected.length);
  2391. localStorage.setItem("preSelectPassenger", user.join("|"));
  2392. refreshPasRowStyle(user);
  2393. });
  2394. $.each(check, function () {
  2395. $("#passengerList :checkbox[value=" + this + ']').change();
  2396. });
  2397. $.each(list, function () {
  2398. $("#preSelectPassenger" + this.index).data('pasinfo', this);
  2399. });
  2400. $("#ticketLimition").val($("#passengerList1 :checkbox").length);
  2401. function refreshPasRowStyle(selected) {
  2402. if (!document.getElementById("autoorder").checked) return;
  2403. var row = $("#selectPasRow");
  2404. row.removeClass("steps stepsok");
  2405. row.addClass(selected.length ? "stepsok" : "steps");
  2406. }
  2407. $("#autoorder").click(function () { refreshPasRowStyle($("#passengerList1 :checkbox")); });
  2408. });
  2409. })();
  2410. //#endregion
  2411. //#region 预定界面加载快速查询链接
  2412. (function () {
  2413. var html = [];
  2414. html.push("<tr class='caption fish_sep'><td colspan='4'>快速查询链接</strong></td></tr>");
  2415. html.push("<tr class='fish_sep'><td colspan='4'>");
  2416. var urls = [
  2417. ["各始发站放票时间查询", "http://www.12306.cn/mormhweb/zxdt/tlxw_tdbtz53.html"]
  2418. ];
  2419. $.each(urls, function () {
  2420. html.push("<div style='float:left;'><a href='" + this[1] + "' target='_blank'>" + this[0] + "</a></div>");
  2421. });
  2422. html.push("</td></tr>");
  2423. $("#helpertooltable tr:last").before(html.join(""));
  2424. })();
  2425. //#endregion
  2426. //#region 余票数限制
  2427. (function () {
  2428. var html = [];
  2429. html.push("<tr class='caption'><td colspan='4'>票数限制</strong></td></tr>");
  2430. html.push("<tr class='fish_sep'><td><strong>最小票数</strong><td colspan='3'><select id='ticketLimition'></select>");
  2431. html.push("介个就是说……如果票票数小于这里的数字的话……就无视的啦 =。=</td></tr>");
  2432. $("#helpertooltable tr:first").addClass("fish_sep").before(html.join(""));
  2433. var dom = $("#ticketLimition").val($("#passengerList1 :checkbox").length)[0];
  2434. for (var i = 0; i < 6; i++) {
  2435. dom.options[i] = new Option(i ? i : "(无限制)", i);
  2436. }
  2437. //注册检测函数
  2438. checkTicketCellsQueue.push(function (i, e, prevValue) {
  2439. var limit = parseInt(dom.value);
  2440. if (!prevValue || !(limit > 0) || $("#autoorder_part:visible:checked").length) return null;
  2441. var text = $.trim(e.text());
  2442. if (text == "有") return 2;
  2443. return parseInt(text) >= limit ? 2 : 1;
  2444. });
  2445. })();
  2446. //#endregion
  2447. //#region 保存查询车次类型配置
  2448. (function () {
  2449. var ccTypeCheck = $("input:checkbox[name=trainClassArr]");
  2450. var preccType = (utility.getPref("cctype") || "").split("|");
  2451. if (preccType[0]) {
  2452. ccTypeCheck.each(function () {
  2453. this.checked = $.inArray(this.value, preccType) != -1;
  2454. });
  2455. }
  2456. ccTypeCheck.click(function () {
  2457. utility.setPref("cctype", $.map(ccTypeCheck.filter(":checked"), function (v, i) {
  2458. return v.value;
  2459. }).join("|"));
  2460. });
  2461. })();
  2462. //#endregion
  2463. //#region 增加互换目标的功能
  2464. (function () {
  2465. var fromCode = $("#fromStation");
  2466. var from = $("#fromStationText");
  2467. var toCode = $("#toStation");
  2468. var to = $("#toStationText");
  2469. from.css("width", "50px").after("<input type='button' value='<->' class='lineButton' title='交换出发地和目的地' id='btnExchangeStation' />");
  2470. $("#btnExchangeStation").click(function () {
  2471. var f1 = fromCode.val();
  2472. var f2 = from.val();
  2473. fromCode.val(toCode.val());
  2474. from.val(to.val());
  2475. toCode.val(f1);
  2476. to.val(f2);
  2477. });
  2478. })();
  2479. //#endregion
  2480. //#region 要求发到站和终点站完全匹配
  2481. (function () {
  2482. var fromText = $("#fromStationText");
  2483. var toText = $("#toStationText");
  2484. $("#filterFunctionRow").append("<label style='font-weight:bold;color:red;margin-left:10px;'><input type='checkbox' id='closeFuseSearch'>过滤发站不完全匹配的车次</label><label style='font-weight:bold;color:red;margin-left:10px;'><input type='checkbox' id='closeFuseSearch1'>过滤到站不完全匹配的车次</label>");
  2485. $("#closeFuseSearch, #closeFuseSearch1").parent().attr("title", '默认情况下,例如查找‘杭州’时,会包括‘杭州南’这个车站。勾选此选项,将会在搜索‘杭州’的时候,过滤那些不完全一致的车站,如‘杭州南’。');
  2486. function getStationName() {
  2487. var txt = $.trim(this.text()).split(/\s/);
  2488. return txt[0];
  2489. }
  2490. checkTicketsQueue.push(function (result) {
  2491. if (document.getElementById("closeFuseSearch").checked) {
  2492. var fs = getStationName.call(this.find("td:eq(1)"));
  2493. if (fs != fromText.val()) {
  2494. this.hide();
  2495. return 0;
  2496. }
  2497. }
  2498. if (document.getElementById("closeFuseSearch1").checked) {
  2499. var fs = getStationName.call(this.find("td:eq(2)"));
  2500. if (fs != toText.val()) {
  2501. this.hide();
  2502. return 0;
  2503. }
  2504. }
  2505. return result;
  2506. });
  2507. })();
  2508. //#endregion
  2509. //#region 保持在线
  2510. var time_offset = null;
  2511. var time_server = null;
  2512. (function () {
  2513. $("#helpertooltable tr:last").before("<tr class='fish_sep'><td class='name'>保持在线</td><td colspan='3'>助手每隔十分钟会帮你刷新存在感防止挂机而掉线的啦。。。。。最后刷新时间:<strong id='lastonlinetime'>无</strong></td></tr>");
  2514. var label = $("#lastonlinetime");
  2515. function online() {
  2516. var serverTime = null;
  2517. utility.post("/otsweb/main.jsp", null, "text", function (data, status, xhr) {
  2518. serverTime = new Date(xhr.getResponseHeader("Date"));
  2519. time_offset = new Date() - serverTime;
  2520. label.html(utility.formatTime(serverTime));
  2521. });
  2522. }
  2523. online();
  2524. setInterval(online, 600 * 1000);
  2525. })();
  2526. //显示本地时间和服务器时间
  2527. (function () {
  2528. var dom = $("#servertime strong");
  2529. function display() {
  2530. if (time_offset === null) return;
  2531. var now = new Date();
  2532. time_server = new Date();
  2533. time_server.setTime(now.getTime() - time_offset);
  2534. document.getElementById("chkSmartSpeed").disabled = time_server.getFullYear() < 2000;
  2535. dom.eq(0).html(utility.formatTime(time_server));
  2536. dom.eq(1).html(utility.formatTime(now));
  2537. dom.eq(2).html((time_offset < 0 ? "快" : "慢") + (Math.abs(time_offset) / 1000) + "秒");
  2538. }
  2539. setInterval(display, 1000);
  2540. display();
  2541. })();
  2542. //#endregion
  2543. //#region 车票模式配置
  2544. (function () {
  2545. $("#helpertooltable tr:first").before("<tr class='fish_sep caption'><td class='name' colspan='4'>出行模式</td></tr>\
  2546. <tr class='fish_sep'><td colspan='2'><select id='profilelist'><option value=''>===选择一个出行模式===</option></select><button id='profile_save' class='fish_button'>保存</button><button id='profile_add' class='fish_button'>另存</button><button id='profile_delete' class='fish_button'>删除</button><button id='profile_reset' class='fish_button'>重置所有选项</button></td><td colspan='2'>出行模式可以帮你快速的保存一系列设置,如联系人、车次、席别、黑名单和白名单</td>\
  2547. </tr>\
  2548. ");
  2549. var list = (window.localStorage["profilelist"] || "").split("\t");
  2550. var listDom = $("#profilelist");
  2551. var listEle = listDom[0];
  2552. if (list[0] == "") list.splice(0, 1);
  2553. $.each(list, function () {
  2554. listEle.options[listEle.options.length] = new Option(this + '', this + '');
  2555. });
  2556. listDom.change(function () {
  2557. var value = listDom.val();
  2558. if (!value) return;
  2559. applyProfile(loadProfile(value));
  2560. });
  2561. $("#profile_save").click(function () {
  2562. if (!listDom.val()) $("#profile_add").click();
  2563. else {
  2564. saveProfile(listDom.val(), generateProfile());
  2565. alert("存档已经更新~");
  2566. }
  2567. });
  2568. $("#profile_add").click(function () {
  2569. var data = generateProfile();
  2570. var name = prompt("请输入出行模式的名称,如『出去鬼混』神马的……", "嗷嗷回家~");
  2571. if (!name) return;
  2572. name = name.replace(/\s+/g, "");
  2573. if (window.localStorage.getItem("profile_" + name)) {
  2574. alert("啊嘞?这个名字的已经有了喔,重试呗~");
  2575. } else {
  2576. saveProfile(name, data);
  2577. list.push(name);
  2578. listEle.options[listEle.options.length] = new Option(name, name);
  2579. window.localStorage.setItem("profilelist", list.join("\t"));
  2580. alert("已保存唷。");
  2581. }
  2582. });
  2583. $("#profile_delete").click(function () {
  2584. var idx = listEle.selectedIndex;
  2585. if (!idx || !confirm("亲,确定要下此狠手咩?")) return;
  2586. listEle.options[idx] = null;
  2587. window.localStorage.removeItem("profile_" + list[idx - 1]);
  2588. list.splice(idx - 1, 1);
  2589. window.localStorage.setItem("profilelist", list.join("\t"));
  2590. alert("乃伊佐特~");
  2591. });
  2592. $("#profile_reset").click(function () {
  2593. listDom.val("");
  2594. applyProfile({ "blackListEnabled": true, "whiteListEnabled": true, "autoBookListEnabled": true, "seatOrder": [], "prePassenger": [], "whiteList": [], "blackList": [], "autoBookList": [], "autoBookMethod": "1" });
  2595. });
  2596. function loadProfile(name) {
  2597. return $.parseJSON(window.localStorage.getItem("profile_" + name));
  2598. }
  2599. function saveProfile(name, profile) {
  2600. if (!profile) window.localStorage.removeItem(name);
  2601. else window.localStorage.setItem("profile_" + name, $.toJSON(profile));
  2602. }
  2603. function generateProfile() {
  2604. var pro = {};
  2605. pro.blackListEnabled = document.getElementById("swBlackList").checked;
  2606. pro.whiteListEnabled = document.getElementById("swWhiteList").checked;
  2607. pro.autoBookListEnabled = document.getElementById("swAutoBook").checked;
  2608. pro.seatOrder = seatLevelOrder;
  2609. pro.prePassenger = $.map($("#passengerList1 :checkbox"), function (e) {
  2610. var data = $(e).data("pasinfo");
  2611. return { type: data.passenger_type, idtype: data.passenger_id_type_code, id: data.passenger_id_no };
  2612. });;
  2613. pro.whiteList = list_whitelist.datalist;
  2614. pro.blackList = list_blacklist.datalist;
  2615. pro.autoBookList = list_autoorder.datalist;
  2616. pro.autoBookMethod = $("#autoorder_method").val();
  2617. pro.queryInfo = $("#querySingleForm").serializeArray();
  2618. return pro;
  2619. }
  2620. function applyProfile(pro) {
  2621. $("#swBlackList").attr("checked", pro.blackListEnabled).change();
  2622. $("#swWhiteList").attr("checked", pro.whiteListEnabled).change();
  2623. $("#swAutoBook").attr("checked", pro.autoBookListEnabled).change();
  2624. //清除席别优选
  2625. $("#preseatlist input").click();
  2626. var seatList = $("#preSelectSeatList");
  2627. $.each(pro.seatOrder, function () {
  2628. seatList.val(this + '').change();
  2629. });
  2630. //黑名单白名单神马的。
  2631. list_whitelist.emptyList();
  2632. $.each(pro.whiteList, function () { list_whitelist.add(this + ''); });
  2633. list_blacklist.emptyList();
  2634. $.each(pro.blackList, function () { list_blacklist.add(this + ''); });
  2635. list_autoorder.emptyList();
  2636. $.each(pro.autoBookList, function () { list_autoorder.add(this + ''); });
  2637. //联系人
  2638. var plist = $("input:checkbox[name=preSelectPassenger]");
  2639. plist.attr("checked", false);
  2640. plist.change();
  2641. $.each(pro.prePassenger, function () {
  2642. var p = this;
  2643. plist.each(function () {
  2644. var data = $(this).data("pasinfo");
  2645. if (data.passenger_type == p.type && data.passenger_id_type_code == p.idtype && data.passenger_id_no == p.id) {
  2646. this.checked = true;
  2647. $(this).change();
  2648. return false;
  2649. }
  2650. return true;
  2651. });
  2652. });
  2653. //优选方式
  2654. $("#autoorder_method").val(pro.autoBookMethod).change();
  2655. //查询方式
  2656. if (pro.queryInfo) {
  2657. $.each(pro.queryInfo, function () {
  2658. if (this.name.indexOf("orderRequest.") == -1) return;
  2659. $("input[name=" + this.name + "]").val(this.value).change();
  2660. });
  2661. }
  2662. utility.notifyOnTop("已加载出行模式");
  2663. }
  2664. })();
  2665. //#endregion
  2666. utility.reloadPrefs($("tr.append_row"), "ticket_query");
  2667. //完成初始化
  2668. initialized = true;
  2669. parent.$("#main").css("height", ($(document).height() + 300) + "px");
  2670. parent.window.setHeight(parent.window);
  2671. }
  2672. //#endregion
  2673. //#region 自动提交订单
  2674. function initDirectSubmitOrder() {
  2675. //if (Math.random() > 0.10) return;
  2676. console.log("[INFO] initialize direct submit order.");
  2677. var html = "<div id='fishSubmitFormStatus' class='outerBox' style='position:fixed;left:0px;bottom:-100px;'><div class='box'><div class='title'>自动提交订单中</div>\
  2678. <div class='content' style='width:150px;'><ul id='tipScript'>\
  2679. <li class='fish_clock' id='countEle' style='font-weight:bold;'>等待操作</li>\
  2680. <li style='color:green;'><strong>操作信息</strong>:<span>休息中</span></li>\
  2681. <li style='color:green;'><strong>最后操作时间</strong>:<span>--</span></li></div>\
  2682. </div></div>";
  2683. parent.window.$("#fishSubmitFormStatus").remove();
  2684. parent.window.$("body").append(html);
  2685. var tip = parent.window.$("#tipScript li");
  2686. var counter = parent.window.$("#countEle");
  2687. var status = parent.window.$("#fishSubmitFormStatus");
  2688. var formData = null;
  2689. var tourFlag;
  2690. var data = null;
  2691. $("#autoorder")[0].disabled = false;
  2692. function setCurOperationInfo(running, msg) {
  2693. counter.removeClass().addClass(running ? "fish_running" : "fish_clock").html(msg || (running ? "正在操作中……" : "等待中……"));
  2694. }
  2695. function setTipMessage(msg) {
  2696. tip.eq(2).find("span").html(utility.getTimeInfo());
  2697. tip.eq(1).find("span").html(msg);
  2698. }
  2699. //窗口状态
  2700. var statusShown = false;
  2701. function showStatus() {
  2702. if (statusShown) return;
  2703. statusShown = true;
  2704. status.animate({ bottom: "0px" });
  2705. }
  2706. function hideStatus() {
  2707. if (!statusShown) return;
  2708. statusShown = false;
  2709. status.animate({ bottom: "-100px" });
  2710. }
  2711. //验证码事件
  2712. var randRow = $("#randCodeTxt").closest("tr");
  2713. function refreshRandRowStyle() {
  2714. randRow.removeClass("steps stepsok");
  2715. randRow.addClass(getVcCode().length == 4 ? "stepsok" : "steps");
  2716. }
  2717. $("#randCodeTxt").keyup(function () {
  2718. refreshRandRowStyle();
  2719. if (statusShown && document.getElementById("randCodeTxt").value.length == 4) checkOrderInfo();
  2720. });
  2721. $("#autoorder").change(refreshRandRowStyle);
  2722. //刷新验证码
  2723. function reloadCode() {
  2724. $("#randCode").attr("src", "/otsweb/passCodeAction.do?rand=randp&" + Math.random());
  2725. var vcdom = document.getElementById("randCodeTxt");
  2726. vcdom.focus();
  2727. vcdom.select();
  2728. }
  2729. $("#randCode").click(reloadCode);
  2730. function getVcCode() {
  2731. return document.getElementById("randCodeTxt").value;
  2732. }
  2733. function isCanAutoSubmitOrder() {
  2734. if (!document.getElementById("autoorder").checked) return [];
  2735. var result = [];
  2736. if (!$("#passengerList1 :checkbox").length) result.push("选择乘客");
  2737. if (!$("#preseatlist input").length) result.push("设置优选席别");
  2738. if (getVcCode().length != 4) result.push("填写验证码");
  2739. if (!$("#autobookListTd input").length) result.push("设置自动预定车次");
  2740. return result;
  2741. }
  2742. function redirectToNotCompleteQuery() {
  2743. window.location.replace("/otsweb/order/myOrderAction.do?method=queryMyOrderNotComplete&leftmenu=Y");
  2744. }
  2745. $("#orderForm").submit(function () {
  2746. if (!document.getElementById("autoorder").checked || isCanAutoSubmitOrder().length || !($("#preSelectSeat").val())) return true;
  2747. showStatus();
  2748. utility.notifyOnTop("开始自动提交预定订单!");
  2749. setCurOperationInfo(true, "正在自动提交订单");
  2750. //确定乘客
  2751. var tcode = $("#station_train_code").val();
  2752. var seatCode = $("#preSelectSeat").val();
  2753. var count = parseInt($.trim($("#gridbox tr[tcode=" + tcode + "] td[scode=" + seatCode + "]").text())) || 0;
  2754. if (seatCode == "1" && $("#preseatlist input[code=empty]").length) {
  2755. //允许了无座,那就加上无座的票数
  2756. count = parseInt($.trim($("#gridbox tr[tcode=" + tcode + "] td[scode=empty]").text())) || 0;
  2757. }
  2758. var pases = $("#passengerList1 :checkbox");
  2759. console.log("欲购票数=" + pases.length + ",实际票数=" + count + " (isNaN 为很多 =。=)");
  2760. if (!isNaN(count) && count > 0 && count < pases.length) {
  2761. $("#passengerList1 :checkbox:gt(" + (count - 1) + ")").attr("checked", false).change();
  2762. }
  2763. var form = $(this);
  2764. utility.post(form.attr("action"), form.serialize(), "text", function (html) {
  2765. if (html.indexOf("您还有未处理") != -1) {
  2766. hideStatus();
  2767. utility.notifyOnTop("您还有未处理订单!");
  2768. redirectToNotCompleteQuery();
  2769. return;
  2770. }
  2771. setTipMessage("正在分析内容");
  2772. getOrderFormInfo(html);
  2773. }, function () {
  2774. utility.notifyOnTop("提交预定请求发生错误,稍等重试!");
  2775. utility.delayInvoke(counter, function () { $("#orderForm").submit(); }, 2000);
  2776. });
  2777. return false;
  2778. });
  2779. function getOrderFormInfo(html) {
  2780. if (typeof (html) != 'undefined' && html) {
  2781. data = utility.analyzeForm(html);
  2782. data.fields["orderRequest.reserve_flag"] = "A"; //网上支付
  2783. tourFlag = data.tourFlag;
  2784. //组装请求
  2785. formData = [];
  2786. $.each(data.fields, function (i) {
  2787. if (i.indexOf("orderRequest") != -1 || i.indexOf("org.") == 0 || i == "leftTicketStr") formData.push(i + "=" + encodeURIComponent(this));
  2788. });
  2789. formData.push("tFlag=" + data.tourFlag);
  2790. //添加乘客
  2791. var pas = $("#passengerList1 :checkbox");
  2792. var seat = $("#preSelectSeat").val();
  2793. var seatType = $("#preselectseatlevel").val();
  2794. for (var i = 0; i < 5; i++) {
  2795. if (i >= pas.length) {
  2796. formData.push("oldPassengers=");
  2797. formData.push("checkbox9=");
  2798. continue;
  2799. }
  2800. var p = pas.eq(i).data("pasinfo");
  2801. var ptype = p.passenger_type;
  2802. var idtype = p.passenger_id_type_code;
  2803. var idno = p.passenger_id_no;
  2804. var name = p.passenger_name;
  2805. //学生票?
  2806. if (clickBuyStudentTicket != "Y" && ptype == "3" && !document.getElementById("autoorder_stu").checked) ptype = 1;
  2807. formData.push("passengerTickets=" + seat + "," + seatType + "," + ptype + "," + encodeURIComponent(name) + "," + idtype + "," + encodeURIComponent(idno) + "," + p.mobile_no + ",Y");
  2808. formData.push("oldPassengers=" + encodeURIComponent(name) + "," + idtype + "," + encodeURIComponent(idno));
  2809. formData.push("passenger_" + (i + 1) + "_seat=" + seat);
  2810. formData.push("passenger_" + (i + 1) + "_seat_detail=" + seatType);
  2811. formData.push("passenger_" + (i + 1) + "_ticket=" + ptype);
  2812. formData.push("passenger_" + (i + 1) + "_name=" + encodeURIComponent(name));
  2813. formData.push("passenger_" + (i + 1) + "_cardtype=" + idtype);
  2814. formData.push("passenger_" + (i + 1) + "_cardno=" + idno);
  2815. formData.push("passenger_" + (i + 1) + "_mobileno=" + p.mobile_no);
  2816. formData.push("checkbox9=Y");
  2817. }
  2818. }
  2819. checkOrderInfo();
  2820. }
  2821. function checkOrderInfo() {
  2822. setCurOperationInfo(true, "正在检测订单状态....");
  2823. utility.notifyOnTop("开始自动提交订单!");
  2824. console.log(data);
  2825. utility.post("confirmPassengerAction.do?method=checkOrderInfo&rand=" + getVcCode(), formData.join("&") + "&randCode=" + getVcCode(), "json", function (data) {
  2826. console.log(data);
  2827. if ('Y' != data.errMsg || 'N' == data.checkHuimd || 'N' == data.check608) {
  2828. if (data.errMsg && data.errMsg.indexOf("验证码") != -1) {
  2829. utility.notifyOnTop("验证码不正确。请输入验证码!");
  2830. setTipMessage("请重新输入验证码。");
  2831. reloadCode();
  2832. } else {
  2833. setCurOperationInfo(false, data.msg || data.errMsg);
  2834. document.getElementById("autoorder").checked = false;
  2835. $("#orderForm").submit();
  2836. }
  2837. return;
  2838. }
  2839. queryQueueInfo();
  2840. }, function () {
  2841. setCurOperationInfo(false, "网络出现错误,稍等重试");
  2842. utility.delayInvoke(counter, checkOrderInfo, 500);
  2843. });
  2844. }
  2845. function queryQueueInfo() {
  2846. if (!document.getElementById("autoorder").checked) {
  2847. hideStatus();
  2848. return;
  2849. }
  2850. setCurOperationInfo(true, "正在提交订单");
  2851. setTipMessage("正在检查队列。");
  2852. var queryLeftData = {
  2853. train_date: data.fields["orderRequest.train_date"],
  2854. station: data.fields["orderRequest.station_train_code"],
  2855. train_no: data.fields["orderRequest.train_no"],
  2856. seat: $("#preSelectSeat").val(),
  2857. from: data.fields["orderRequest.from_station_telecode"],
  2858. to: data.fields["orderRequest.to_station_telecode"],
  2859. ticket: data.fields["leftTicketStr"]
  2860. };
  2861. utility.get("/otsweb/order/confirmPassengerAction.do?method=getQueueCount", queryLeftData, "json", function (data) {
  2862. if (data.op_2) {
  2863. //utility.notifyOnTop("排队人数过多,系统禁止排队,稍等重试。要重新查询,请刷新页面!");
  2864. setTipMessage("排队人数过多 (人数=" + data.count + ")");
  2865. setCurOperationInfo(true, "排队人数过多");
  2866. utility.delayInvoke(counter, queryQueueInfo, 500);
  2867. } else {
  2868. submitOrder();
  2869. }
  2870. }, function () { utility.delayInvoke(counter, queryQueueInfo, 500); });
  2871. }
  2872. function submitOrder() {
  2873. if (!document.getElementById("autoorder").checked) {
  2874. hideStatus();
  2875. return;
  2876. }
  2877. setCurOperationInfo(true, "正在提交订单");
  2878. setTipMessage("已检测状态。");
  2879. var order_type = 'confirmSingleForQueueOrder'; //'dc' 单程
  2880. if (tourFlag == 'wc') {
  2881. // 异步下单-往程
  2882. order_type = 'confirmPassengerInfoGoForQueue';
  2883. } else if (tourFlag == 'fc') {
  2884. // 异步下单-返程
  2885. order_type = 'confirmPassengerInfoBackForQueue';
  2886. } else if (tourFlag == 'gc') {
  2887. // 异步下单-改签
  2888. order_type = 'confirmPassengerInfoResignForQueue';
  2889. }
  2890. utility.post('/otsweb/order/confirmPassengerAction.do?method=' + order_type,
  2891. formData.join("&") + "&randCode=" + getVcCode(), "json", function (data) {
  2892. var msg = data.errMsg;
  2893. if (msg == "Y") {
  2894. setTipMessage("订单提交成功");
  2895. setCurOperationInfo(false, "订单提交成功,请等待排队完成。");
  2896. utility.notifyOnTop("订单提交成功,请等待排队完成。");
  2897. redirectToNotCompleteQuery();
  2898. } else {
  2899. if (msg.indexOf("包含未付款订单") != -1) {
  2900. hideStatus();
  2901. alert("您有未支付订单! 等啥呢, 赶紧点确定支付去.");
  2902. redirectToNotCompleteQuery();
  2903. return;
  2904. }
  2905. if (msg.indexOf("重复提交") != -1) {
  2906. setTipMessage("TOKEN失效,刷新Token中....");
  2907. $("#orderForm").submit();
  2908. return;
  2909. }
  2910. if (msg.indexOf("包含排队中") != -1) {
  2911. hideStatus();
  2912. alert("您有排队中订单! 点确定转到排队页面");
  2913. redirectToNotCompleteQuery();
  2914. return;
  2915. }
  2916. if (msg.indexOf("排队人数现已超过余票数") != -1) {
  2917. //排队人数超过余票数,那么必须重新提交
  2918. document.getElementById("autoorder").checked = false;
  2919. setTipMessage(msg);
  2920. reloadCode();
  2921. setCurOperationInfo(false, "警告:" + msg + ",自动回滚为手动提交,请切换车次或席别,请尽快重试!");
  2922. sendQueryFunc.call(clickBuyStudentTicket == "Y" ? document.getElementById("stu_submitQuery") : document.getElementById("submitQuery"));
  2923. return;
  2924. }
  2925. setTipMessage(msg);
  2926. setCurOperationInfo(false, "未知错误:" + msg + ",请告知作者。");
  2927. utility.notifyOnTop("未知错误:" + msg + ",请告知作者。");
  2928. if (document.getElementById("autoorder_autocancel").checked) {
  2929. document.getElementById("autoorder").checked = false;
  2930. $("#autoorder").change();
  2931. $("#orderForm").submit();
  2932. }
  2933. }
  2934. }, function () {
  2935. setCurOperationInfo(false, "网络出现错误,稍等重试");
  2936. utility.delayInvoke(counter, submitOrder, 2000);
  2937. });
  2938. }
  2939. //周期性检测状态,已确认可以自动提交
  2940. setInterval(function () {
  2941. if (document.getElementById("autoorder").checked) {
  2942. var r = isCanAutoSubmitOrder();
  2943. if (r.length) {
  2944. utility.notifyOnTop("您选择了自动提交订单,但是信息没有设置完整!请" + r.join("、") + "!");
  2945. }
  2946. }
  2947. }, 30 * 1000);
  2948. //最后显示界面,防止初始化失败却显示了界面
  2949. $("tr.autoordertd, td.autoordertd *").show();
  2950. }
  2951. //#endregion
  2952. //#region -----------------自动登录----------------------
  2953. function initLogin() {
  2954. //启用日志
  2955. utility.enableLog();
  2956. //如果已经登录,则自动跳转
  2957. utility.unsafeCallback(function () {
  2958. if (parent && parent.$) {
  2959. var str = parent.$("#username_ a").attr("href");
  2960. if (str && str.indexOf("sysuser/user_info") != -1) {
  2961. window.location.href = "https://dynamic.12306.cn/otsweb/order/querySingleAction.do?method=init";
  2962. }
  2963. return;
  2964. }
  2965. });
  2966. //检测主框架是否是顶级窗口
  2967. var isTop = false;
  2968. try {
  2969. isTop = (top.location + '').indexOf("dynamic.12306.cn") != -1;
  2970. } catch (e) {
  2971. }
  2972. if (!isTop) {
  2973. $("#loginForm table tr:first td:last").append("<a href='https://dynamic.12306.cn/otsweb/' target='_blank' style='font-weight:bold;color:red;'>点击全屏订票</a>");
  2974. if (!utility.getPref("login.fullscreenAlert")) {
  2975. utility.setPref("login.fullscreenAlert", 1);
  2976. utility.notifyOnTop("强烈建议你点击界面中的『点击全屏订票』来全屏购票,否则助手有些提示消息您将无法看到!");
  2977. }
  2978. }
  2979. //Hack当前UI显示
  2980. $(".enter_right").empty().append("<div class='enter_enw'>" +
  2981. "<div class='enter_rtitle' style='padding: 40px 0px 10px 0px; font-size: 20px;'>脚本提示信息</div>" +
  2982. "<div class='enter_rfont'>" +
  2983. "<ul id='tipScript'>" +
  2984. "<li class='fish_clock' id='countEle' style='font-weight:bold;'>等待操作</li>" +
  2985. "<li style='color:green;'><strong>操作信息</strong>:<span>休息中</span></li>" +
  2986. "<li style='color:green;'><strong>最后操作时间</strong>:<span>--</span></li>" +
  2987. "<li> <a href='javascript:;' class='configLink' tab='tabLogin'>登录设置</a> | <a href='http://t.qq.com/ccfish/' target='_blank' style='color:blue;'>腾讯微博</a> | <a href='http://www.fishlee.net/soft/44/' style='color:blue;' target='_blank'>助手主页</a></li><li><a href='http://www.fishlee.net/soft/44/announcement.html' style='color:blue;' target='_blank'>免责声明</a> | <a href='http://www.fishlee.net/Discussion/Index/44' target='_blank'>反馈BUG</a> | <a style='font-weight:bold;color:red;' href='http://www.fishlee.net/honor/index.html' target='_blank'>捐助作者</a></li>" +
  2988. '<li id="enableNotification"><input type="button" id="enableNotify" οnclick="$(this).parent().hide();window.webkitNotifications.requestPermission();" value="点击启用桌面通知" style="line-height:25px;padding:5px;" /></li><li style="padding-top:10px;line-height:normal;color:gray;">请<strong style="color: red;">最后输验证码</strong>,输入完成后系统将自动帮你提交。登录过程中,请勿离开当前页。如系统繁忙,会自动重新刷新验证码,请直接输入验证码,输入完成后助手将自动帮你提交。</li>' +
  2989. "</ul>" +
  2990. "</div>" +
  2991. "</div>");
  2992. var html = [];
  2993. html.push("<div class='outerbox' style='margin:15px;'><div class='box'><div class='title'>小提示</div><div style='padding:10px;'>");
  2994. html.push("<table><tr><td style='width:33%;font-weight:bold;background-color:#f5f5f5;'><strong>您还可以通过以下网址访问订票网站:</strong></td><td style='width:33%;font-weight:bold;background-color:#f5f5f5;'>助手运行常见问题</td><td style='font-weight:bold;background-color:#f5f5f5;'>版本信息</td></tr>");
  2995. html.push("<tr><td><ul><li style='list-style:disc inside;'><a href='https://www.12306.cn/otsweb/' target='blank'>https://www.12306.cn/otsweb/</a></li>");
  2996. html.push("<li style='list-style:disc inside;'><a href='https://dynamic.12306.cn/otsweb/' target='blank'>https://dynamic.12306.cn/otsweb/</a></li><li style='list-style:disc inside;'><a href='http://dynamic.12306.cn/otsweb/' target='blank'>http://dynamic.12306.cn/otsweb/</a></li>");
  2997. html.push("</ul></td><td><ol>");
  2998. $.each([
  2999. ["http://www.fishlee.net/soft/44/tour.html", "订票助手使用指南", "font-weight:bold;color:red;"],
  3000. ["http://www.fishlee.net/soft/44/12306faq.html", "订票的常见问题&指南", ""],
  3001. ["http://www.fishlee.net/soft/44/faq.html", "助手运行的常见问题", ]
  3002. ], function (i, n) {
  3003. html.push("<li style='list-style:disc inside;'><a style='" + n[2] + "' href='" + n[0] + "' target='blank'>" + (n[1] || n[0]) + "</a></li>");
  3004. });
  3005. html.push("</ol></td><td><ul>");
  3006. var info = [];
  3007. info.push("已许可于:" + utility.regInfo.name);
  3008. if (utility.regInfo.bindAcc) {
  3009. if (!utility.regInfo.bindAcc[0] || utility.regInfo.bindAcc[0] == "*") info.push("许可12306帐户:<em>无限</em>");
  3010. else info.push("许可12306帐户:" + utility.regInfo.bindAcc);
  3011. }
  3012. info.push(utility.regInfo.typeDesc);
  3013. info.push("版本:<strong>" + window.helperVersion + "</strong>");
  3014. $.each(info, function (i, n) { html.push("<li style='list-style:disc inside;'>" + n + "</li>"); });
  3015. html.push("<li style='list-style:disc inside;'>【<a href='javascript:;' class='reSignHelper'>重新注册</a>】</li>");
  3016. html.push("</ul></td></tr></table>");
  3017. html.push("</div></div></div>");
  3018. $("div.enter_help").before(html.join(""));
  3019. //插入登录标记
  3020. var form = $("#loginForm");
  3021. var trs = form.find("tr");
  3022. trs.eq(1).find("td:last").html('<label><input type="checkbox" id="keepInfo" /> 记录密码</label>');
  3023. $("#loginForm td:last").html('<label><input type="checkbox" checked="checked" id="autoLogin" name="autoLogin" /> 自动登录</label>');
  3024. utility.reloadPrefs($("#loginForm td:last"));
  3025. $("#keepInfo").change(function () {
  3026. if (!this.checked) {
  3027. if (localStorage.getItem("__un") != null) {
  3028. localStorage.removeItem("__un");
  3029. localStorage.removeItem("__up");
  3030. alert("保存的密码已经删除!");
  3031. }
  3032. }
  3033. });
  3034. //注册判断
  3035. form.submit(function () {
  3036. utility.setPref("_sessionuser", $("#UserName").val());
  3037. });
  3038. if (!window.webkitNotifications || window.webkitNotifications.checkPermission() == 0) {
  3039. $("#enableNotification").remove();
  3040. }
  3041. var tip = $("#tipScript li");
  3042. var count = 1;
  3043. var errorCount = 0;
  3044. var inRunning = false;
  3045. //以下是函数
  3046. function setCurOperationInfo(running, msg) {
  3047. var ele = $("#countEle");
  3048. ele.removeClass().addClass(running ? "fish_running" : "fish_clock").html(msg || (running ? "正在操作中……" : "等待中……"));
  3049. }
  3050. function setTipMessage(msg) {
  3051. tip.eq(2).find("span").html(utility.getTimeInfo());
  3052. tip.eq(1).find("span").html(msg);
  3053. }
  3054. function getLoginRandCode() {
  3055. setCurOperationInfo(true, "正在获得登录随机码");
  3056. $.ajax({
  3057. url: "/otsweb/loginAction.do?method=loginAysnSuggest",
  3058. method: "POST",
  3059. dataType: "json",
  3060. cache: false,
  3061. success: function (json, code, jqXhr) {
  3062. //{"loginRand":"211","randError":"Y"}
  3063. if (json.randError != 'Y') {
  3064. setTipMessage("错误:" + json.randError);
  3065. utility.delayInvoke("#countEle", getLoginRandCode, utility.getLoginRetryTime());
  3066. } else {
  3067. setTipMessage("登录随机码 -> " + json.loginRand);
  3068. $("#loginRand").val(json.loginRand);
  3069. submitForm();
  3070. }
  3071. },
  3072. error: function (xhr) {
  3073. errorCount++;
  3074. if (xhr.status == 403) {
  3075. setTipMessage("[" + errorCount + "] 警告! 403错误, IP已被封!")
  3076. utility.delayInvoke("#countEle", getLoginRandCode, 10 * 1000);
  3077. } else {
  3078. setTipMessage("[" + errorCount + "] 网络请求错误,重试")
  3079. utility.delayInvoke("#countEle", getLoginRandCode, utility.getLoginRetryTime());
  3080. }
  3081. }
  3082. });
  3083. }
  3084. function submitForm() {
  3085. var data = {};
  3086. $.each($("#loginForm").serializeArray(), function () {
  3087. if (this.name == "refundFlag" && !document.getElementById("refundFlag").checked) return;
  3088. data[this.name] = this.value;
  3089. });
  3090. if (!data["loginUser.user_name"] || !data["user.password"] || !data.randCode || data.randCode.length != 4/* || (utility.regInfo.bindAcc && utility.regInfo.bindAcc != data["loginUser.user_name"])*/)
  3091. return;
  3092. if ($("#keepInfo")[0].checked) {
  3093. utility.setPref("__un", data["loginUser.user_name"]);
  3094. utility.setPref("__up", data["user.password"])
  3095. }
  3096. setCurOperationInfo(true, "正在登录中……");
  3097. $.ajax({
  3098. type: "POST",
  3099. url: "/otsweb/loginAction.do?method=login",
  3100. data: data,
  3101. timeout: 10000,
  3102. dataType: "text",
  3103. success: function (html) {
  3104. msg = utility.getErrorMsg(html);
  3105. if (html.indexOf('请输入正确的验证码') > -1) {
  3106. setTipMessage("验证码不正确");
  3107. setCurOperationInfo(false, "请重新输入验证码。");
  3108. stopLogin();
  3109. } else if (msg.indexOf('密码') > -1) {
  3110. setTipMessage(msg);
  3111. setCurOperationInfo(false, "请重新输入。");
  3112. stopLogin();
  3113. } else if (msg.indexOf('锁定') > -1) {
  3114. setTipMessage(msg);
  3115. setCurOperationInfo(false, "请重新输入。");
  3116. stopLogin();
  3117. } else if (html.indexOf("欢迎您登录") != -1) {
  3118. utility.notifyOnTop('登录成功,开始查询车票吧!');
  3119. window.location.href = "https://dynamic.12306.cn/otsweb/order/querySingleAction.do?method=init";
  3120. } else {
  3121. setTipMessage(msg);
  3122. utility.delayInvoke("#countEle", getLoginRandCode, utility.getLoginRetryTime());
  3123. }
  3124. },
  3125. error: function (msg) {
  3126. errorCount++;
  3127. if (xhr.status == 403) {
  3128. setTipMessage("[" + errorCount + "] 警告! 403错误, IP已被封!")
  3129. utility.delayInvoke("#countEle", getLoginRandCode, 10 * 1000);
  3130. } else {
  3131. setTipMessage("[" + errorCount + "] 网络请求错误,重试")
  3132. utility.delayInvoke("#countEle", getLoginRandCode, utility.getLoginRetryTime());
  3133. }
  3134. }
  3135. });
  3136. }
  3137. function relogin() {
  3138. if (inRunning) return;
  3139. var user = $("#UserName").val();
  3140. if (!user) return;
  3141. if (utility.regInfo.bindAcc && utility.regInfo.bindAcc.length && utility.regInfo.bindAcc[0] && $.inArray(user, utility.regInfo.bindAcc) == -1 && utility.regInfo.bindAcc[0] != "*") {
  3142. alert("很抱歉,12306订票助手的授权许可已绑定至【" + utility.regInfo.bindAcc.join() + "】,未授权用户,助手停止运行,请手动操作。\n您可以在登录页面下方的帮助区点击【重新注册】来修改绑定。");
  3143. return;
  3144. }
  3145. count++;
  3146. utility.setPref("_sessionuser", $("#UserName").val());
  3147. inRunning = true;
  3148. getLoginRandCode();
  3149. }
  3150. function stopLogin() {
  3151. //等待重试时,刷新验证码
  3152. $("#img_rrand_code").click();
  3153. $("#randCode").val("")[0].select();
  3154. inRunning = false;
  3155. }
  3156. //初始化
  3157. function executeLogin() {
  3158. count = 1;
  3159. utility.notify("自动登录中:(1) 次登录中...");
  3160. setTipMessage("开始登录中....");
  3161. getLoginRandCode();
  3162. return false;
  3163. }
  3164. var kun = utility.getPref("__un");
  3165. var kup = utility.getPref("__up");
  3166. if (kun && kup) {
  3167. $("#UserName").val(kun);
  3168. $("#password").val(kup);
  3169. $("#randCode")[0].focus();
  3170. }
  3171. $("#randCode").keyup(function (e) {
  3172. if (!$("#autoLogin")[0].checked) return;
  3173. e = e || event;
  3174. if (e.charCode == 13 || $("#randCode").val().length == 4) relogin();
  3175. });
  3176. //#region 起售时间提示和查询
  3177. function addDays(count) {
  3178. return new Date(this.getFullYear(), this.getMonth(), this.getDate() + count);
  3179. }
  3180. var curDate = new Date();
  3181. var html = ["<li style='font-weight:bold; color:blue;'><u>助手提示</u>:网上和电话订票提前20天,本日起售【<u>"];
  3182. html.push(utility.formatDate(addDays.call(curDate, 19)));
  3183. html.push("</u>】日车票;代售点和车站提前18天,本日起售【<u>");
  3184. html.push(utility.formatDate(addDays.call(curDate, 17)));
  3185. html.push("</u>】日车票。<br />【<a href='javascript:;' id='querySaleDate'>根据乘车日期推算起售日期</a>】【<a href='http://www.12306.cn/mormhweb/zxdt/tlxw_tdbtz53.html' target='_blank'>以相关公告、车站公告为准</a>】");
  3186. $("div.enter_from ul").append(html.join(""));
  3187. $("#querySaleDate").click(function () {
  3188. var date = prompt("请输入您要乘车的日期,如:2013-02-01");
  3189. if (!date) return;
  3190. if (!/(\d{4})[-/]0?(\d{1,2})[-/]0?(\d{1,2})/.exec(date)) {
  3191. alert("很抱歉未能识别日期");
  3192. }
  3193. date = new Date(parseInt(RegExp.$1), parseInt(RegExp.$2) - 1, parseInt(RegExp.$3));
  3194. alert("您查询的乘车日期是:" + utility.formatDate(date) + "\n\n互联网、电话起售日期是:" + utility.formatDate(addDays.call(date, -19)) + "\n车站、代售点起售日期是:" + utility.formatDate(addDays.call(date, -17)) + "\n\n以上结果仅供参考。");
  3195. });
  3196. //#endregion
  3197. }
  3198. //#endregion
  3199. //#region 自动重新支付
  3200. function initPayOrder() {
  3201. //如果出错,自动刷新
  3202. if ($("div.error_text").length > 0) {
  3203. utility.notifyOnTop("页面出错,稍后自动刷新!");
  3204. setTimeout(function () { self.location.reload(); }, 3000);
  3205. }
  3206. return;
  3207. // undone
  3208. window.payOrder = this;
  3209. //epayOrder
  3210. var oldCall = window.epayOrder;
  3211. var formUrl, formData;
  3212. $("#myOrderForm").submit(function () {
  3213. var form = $(this);
  3214. var action = form.attr("action");
  3215. if (acton && action.index("laterEpay") != -1) {
  3216. return false;
  3217. }
  3218. });
  3219. window.epayOrder = function () {
  3220. oldCall.apply(arguments);
  3221. var form = $("#myOrderForm");
  3222. var formData = utility.serializeForm(form);
  3223. var formUrl = form.attr("action");
  3224. };
  3225. function getsubmitForm() {
  3226. utility.post(formUrl, formData, "text", function (html) {
  3227. }, function () {
  3228. });
  3229. }
  3230. }
  3231. //#endregion
  3232. //#region 更新专用检测代码
  3233. if (location.pathname == "/otsweb/" || location.pathname == "/otsweb/main.jsp") {
  3234. if (isFirefox) {
  3235. //firefox 专用检测代码
  3236. GM_xmlhttpRequest({
  3237. method: "GET",
  3238. url: "http://www.fishlee.net/service/update/44/version.js",
  3239. onload: function (o) {
  3240. eval(o.responseText);
  3241. if (typeof (fishlee12306_msgid) != 'undefined') {
  3242. if (utility.getPref("helperlastmsgid") != fishlee12306_msgid) {
  3243. utility.setPref("helperlastmsgid", fishlee12306_msgid);
  3244. if (!fishlee12306_msgver || compareVersion(version, fishlee12306_msgver) < 0) {
  3245. if (fishlee12306_msg) alert(fishlee12306_msg);
  3246. }
  3247. }
  3248. }
  3249. console.log("[INFO] 更新检查:当前助手版本=" + version + ",新版本=" + version_12306_helper);
  3250. if (compareVersion(version, version_12306_helper) < 0 && confirm("订票助手已发布新版 【" + version_12306_helper + "】,为了您的正常使用,请及时更新!是否立刻更新?\n\n本次更新内容如下:\n" + version_updater.join("\n"))) {
  3251. GM_openInTab("http://www.fishlee.net/Service/Download.ashx/44/47/12306_ticket_helper.user.js", true, true);
  3252. }
  3253. }
  3254. });
  3255. } else {
  3256. unsafeInvoke(function () {
  3257. $("body").append('<iframe id="checkVersion" width="0" height="0" style="visibility:hidden;" src="http://static.fishlee.net/content/scriptProxy.html?script=http://static.fishlee.net/content/images/apps/cn12306/checkVersion.js&v=' + window.helperVersion + '"></iframe>');
  3258. });
  3259. }
  3260. }
  3261. function compareVersion(v1, v2) {
  3262. var vv1 = v1.split('.');
  3263. var vv2 = v2.split('.');
  3264. var length = Math.min(vv1.length, vv2.length);
  3265. for (var i = 0; i < length; i++) {
  3266. var s1 = parseInt(vv1[i]);
  3267. var s2 = parseInt(vv2[i]);
  3268. if (s1 < s2) return -1;
  3269. if (s1 > s2) return 1;
  3270. }
  3271. return vv1.length > vv2.length ? 1 : vv1.length < vv2.length ? -1 : 0;
  3272. }
  3273. //#endregion

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/632028
推荐阅读
相关标签
  

闽ICP备14008679号