// ==UserScript== // @name 12306.CN 訂票助手 For Firefox&Chrome // @namespace http://www.u-tide.com/fish/ // @author [email protected] <[email protected]> http://www.fishlle.net/ // @developer iFish // @contributor // @description 幫你訂票的小助手 :-) // @match http://dynamic.12306.cn/otsweb/* // @match https://dynamic.12306.cn/otsweb/* // @match https://www.12306.cn/otsweb/* // @require http://lib.sinaapp.com/js/jquery/1.8.3/jquery.min.js // @icon http://www.12306.cn/mormhweb/images/favicon.ico // @run-at document-idle // @version 4.2.4 // @updateURL http://www.fishlee.net/Service/Download.ashx/44/47/12306_ticket_helper.user.js // @supportURL http://www.fishlee.net/soft/44/ // @homepage http://www.fishlee.net/soft/44/ // @contributionURL https://me.alipay.com/imfish // @contributionAmount ¥5.00 // ==/UserScript== //=======START======= var version = "4.2.4"; var updates = [ "修改自動預定和自動送出邏輯,提示排隊人數過多時自動重試 (不過此類情況成功率不高,建議多做打算)", "修改自動送出的重試過程可以通過取消勾選『自動送出』來取消", "修正改簽的自動送出會生成一個新的訂單", "修正自動送出在出現網絡錯誤時,可能會卡住的BUG" ]; var faqUrl = "http://www.fishlee.net/soft/44/faq.html"; //标記 var utility_emabed = false; //#region -----------------UI界面-------------------------- function initUIDisplay() { injectStyle(); } /** * 将使用的樣式加入到目前頁面中 */ function injectStyle() { var s = document.createElement("style"); s.id = "12306_ticket_helper"; s.type = "text/css"; s.textContent = ".fish_running, .fish_clock, .fish_error, .fish_ok {\ line-height:20px;\ text-indent:18px;\ background-repeat:no-repeat;\ background-position:2px 50%;\ font-size:12px;\ }\ .fish_running{background-image:url(data:image/gif;base64,R0lGODlhEAAQALMPAHp6evf394qKiry8vJOTk83NzYKCgubm5t7e3qysrMXFxe7u7pubm7S0tKOjo////yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCAAPACwAAAAAEAAQAAAETPDJSau9NRDAgWxDYGmdZADCkQnlU7CCOA3oNgXsQG2FRhUAAoWDIU6MGeSDR0m4ghRa7JjIUXCogqQzpRxYhi2HILsOGuJxGcNuTyIAIfkECQgADwAsAAAAABAAEAAABGLwSXmMmjhLAQjSWDAYQHmAz8GVQPIESxZwggIYS0AIATYAvAdh8OIQJwRAQbJkdjAlUCA6KfU0VEmyGWgWnpNfcEAoAo6SmWtBUtCuk9gjwQKeQAeWYQAHIZICKBoKBncTEQAh+QQJCAAPACwAAAAAEAAQAAAEWvDJORejGCtQsgwDAQAGGWSHMK7jgAWq0CGj0VEDIJxPnvAU0a13eAQKrsnI81gqAZ6AUzIonA7JRwFAyAQSgCQsjCmUAIhjDEhlrQTFV+lMGLApWwUzw1jsIwAh+QQJCAAPACwAAAAAEAAQAAAETvDJSau9L4QaBgEAMWgEQh0CqALCZ0pBKhRSkYLvM7Ab/OGThoE2+QExyAdiuexhVglKwdCgqKKTGGBgBc00Np7VcVsJDpVo5ydyJt/wCAAh+QQJCAAPACwAAAAAEAAQAAAEWvDJSau9OAwCABnBtQhdCQjHlQhFWJBCOKWPLAXk8KQIkCwWBcAgMDw4Q5CkgOwohCVCYTIwdAgPolVhWSQAiN1jcLLVQrQbrBV4EcySA8l0Alo0yA8cw+9TIgAh+QQFCAAPACwAAAAAEAAQAAAEWvDJSau9WA4AyAhWMChPwXHCQRUGYARgKQBCzJxAQgXzIC2KFkc1MREoHMTAhwQ0Y5oBgkMhAAqUw8mgWGho0EcCx5DwaAUQrGXATg6zE7bwCQ2sAGZmz7dEAAA7); color: green;}\ .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;}\ .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;}\ .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;}\ .outerbox{border:5px solid #EAE3F7;}\ .box{border:1px solid #6E41C2;color:#444;margin:auto;}\ .box .title{padding:5px;line-height:20px;background-color:#B59DE2;color:#fff;}\ .box .title a {color:white;}\ .box .content{padding:5px;background-color:#fff;}\ .box table{border-collapse:collapse; width:98%;}\ .box table td{padding:5px;}\ .box input[type=button],.fish_button {padding:5px;}\ .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;}\ .fish_sep td {border-top:1px solid #A688DD;}\ .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;}\ .lineButton:hover { color: white; background-color: green;-webkit-transition:all linear 0.1s;-moz-transition:all linear 0.1s; }\ .fishTab {border: 5px solid #E5D9EC;font-size: 12px;}\ .fishTab .innerTab {border-width: 1px;border-style: solid;border-color: #C7AED5;background-color: #fff;}\ .fishTab .tabNav {font-weight:bold;color:#F5F1F8;background-color: #C7AED5;line-height:25px;overflow:hidden;margin:0px;padding:0px;}\ .fishTab .tabNav li {float:left;list-style:none;cursor:pointer;padding-left: 20px;padding-right: 20px;}\ .fishTab .tabNav li:hover {background-color:#DACAE3;}\ .fishTab .tabNav li.current {background-color:#fff;color: #000;}\ .fishTab .tabContent {padding:5px;display:none;}\ .fishTab .tabContent p{margin:10px 0px 10px 0px;}\ .fishTab div.current {display:block;}\ .fishTab div.control {text-align:center;line-height:25px;background-color:#F0EAF4;}\ .fishTab input[type=button] { padding: 5px; }\ .hide {display:none;}\ .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;}\ .fish_button:hover{background:#fff;color:#7077DA;-webkit-transition:all linear 0.1s;-moz-transition:all linear 0.1s;cursor:pointer;}\ tr.steps td{background-color:#E8B7C2!important;-webkit-transition:all linear 0.1s;-moz-transition:all linear 0.1s;}\ tr.stepsok td{background-color:#BDE5BD!important;-webkit-transition:all linear 0.1s;-moz-transition:all linear 0.1s;}\ tr.steps span.indicator {display:inline-block!important;}\ tr.stepsok span.indicator {display:inline-block!important;}\ .highlightrow td { background-color:#D0C0ED!important; color:red; }\ #randCodeTxt{ font-weight: bold; font-size: 18px; text-align: center; padding: 3px 10px 3px 10px; font-family: verdana!important; text-transform: uppercase; }"; document.head.appendChild(s); } function injectDom() { var html = []; html.push('<div id="fishOption" style="width: 600px; display:none; box-shadow: 7px 7px 10px #A67EBC;">'); html.push('<div class="innerTab">'); html.push('<ul class="tabNav" default="tabVersion">'); html.push('<li tab="tabLogin">正常設定</li>'); html.push('<li tab="tabReg">注冊</li>'); html.push('<li tab="tabFaq">常見問題</li>'); html.push('<li tab="tabVersion">版本資訊</li>'); html.push('<li tab="tabLog">運作日志</li>'); html.push('<li tab="tabLoginIE">登入到IE</li>');//擷取登入到IE的代碼 Add By XPHelper html.push('</ul>'); html.push('<div class="tabContent tabLogin">'); html.push('<table>'); html.push('<tr>'); html.push('<td>重試時間 '); html.push('<td>'); html.push('<td><input type="text" name="login.retryLimit" size="6" value="2000" />'); html.push('(ms)</td>'); html.push('<td>'); html.push('</td>'); html.push('<td></td>'); html.push('</tr>'); html.push('</table>'); html.push('</div>'); html.push('<div class="tabContent tabReg" style="text-indent: 20px">'); html.push('<p>為了阻止地球人他喵地拿作者無償奉獻的助手去賣錢錢,請注冊唷。<strong>完全免費申請</strong>。</p>'); html.push('<p style="color: red;"> <strong style="font-size:16px;">啊嘞……看這裡!本助手完全免費啊諸位大人!</strong>任何在第三方網站上出售的軟體全他喵的是侵權出售啊!!看到的時候請親務必記得退款退貨打差評向青天大老爺舉報啊!!</p>'); html.push('<p style="color:purple;"> 回家是一個單純而簡單的心願,希望我們不會變得太複雜……</p>'); html.push('<p>任何版本之間,功能上沒有任何差別,So……不要問作者萬一資助的話會有神馬新功能,木有的說…… (= ̄ω ̄=) </p>'); html.push('<p class="registered" style="display:none;">很高興認識你,,<strong>[email protected]</strong>,謝謝你的出現~~~~已注冊版本:<strong>正式版</strong>【<a href="javascript:;" id="unReg">重新注冊</a>】</p>'); html.push('<table class="regTable" style="display:none;width:98%;">'); html.push('<tr>'); 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>'); html.push('</tr><tr>'); html.push('<td style="text-align:center;"><textarea id="regContent" style="width:98%; height:50px;"></textarea></td>'); html.push('</tr><tr>'); html.push('<td><input type="button" id="regButton" value="注冊" /></td>'); html.push('</tr>'); html.push('</table>'); html.push('</div>'); html.push('<div class="tabContent tabVersion" style="text-indent: 20px">'); 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>'); html.push('<p> 12306 訂票助手是一款用于訂票的助手軟體,嗯……看到這裡相信你已經知道它支援神馬浏覽器了 =。=<strong>完全免費,無需付費使用,僅接受捐助。</strong> </p>'); html.push('<p style="color: red;"> <strong style="font-size:16px;">啊嘞……看這裡!本助手完全免費啊諸位大人!</strong>任何在第三方網站上出售的軟體全他喵的是侵權出售啊!!看到的時候請親務必記得退款退貨打差評向青天大老爺舉報啊!!</p>'); html.push('<p style="color:purple;"> 回家是一個單純而簡單的心願,希望我們不會變得太複雜……</p>'); html.push('<p> 有很多朋友資助作者,正在木有暖氣的南方飽受煎熬的作者感激涕零 ≥ω≤。<a href="http://www.fishlee.net/soft/44/donate.html" target="_blank">戳這裡了解捐助詳情</a>。 </p>'); html.push('<p style="color: blue;"> <strong style="font-size:16px;">那個,諸位票販子們,放過本助手吧!!不要害作者啊!!!你們都去用什麼自動識别驗證碼的好啦!離貧道遠點!!</strong> ╮(╯▽╰)╭ </p>'); html.push('<p style="font-weight:bold;">目前版本更新内容</p>'); html.push('<ol>'); $.each(utility.getPref("updates").split('\t'), function (i, n) { html.push("<li style='padding-left:20px;list-style:disc inside;'>" + n + "</li>"); }); html.push('</ol>'); html.push('</div>'); html.push('<div class="tabContent tabFaq">'); html.push('<table>'); html.push('<tr>'); html.push('<td colspan="4"> 你在訂票過程中可能……會遇到各種問題,由于介個12306網站本身呢……木有沒有任何介紹 ╮(╯▽╰)╭ ,是以老衲整理了相關問題,供客官參考。如果還有不明白的問題,加群讨論呗 (= ̄ω ̄=) 。 <br /><br />'); html.push('1.放票非正點也,So在将近放票的時候,務必保持重新整理狀态哈,而且……當整點沒有放票時,不要放棄繼續重新整理喔;<br />\ 2.動車都是11點放票撒,切記切記;<br />\ 3.第一波放票悲催地木有訂到時,請耐心等待,因為現在放票有N多節點,随時會有票出來,晚很久才放票也正常,鐵老大經常秀下限嘀;<br />\ 4.如果您的車票很難買,請盡量發動你的七大姑八大姨神馬的一堆朋友過來集體幫忙,同時建議用多個浏覽器刷票,因為緩存的關系不同的浏覽器出現票的時間可能不同;<br />\ 5.最新版3.9.0中的預先選擇鋪位功能有點淡化了……要用的話,使用優選席别,第一個優選的将會被自動選中 ^_^<br />\ <br />\ 好了,廢話說完鳥,祝大家買票順利,貧僧隻希望不會幫倒忙就好了 ╮(╯▽╰)╭<br />\ 如果您還有問題的話,<a href="http://www.fishlee.net/soft/44/tour.html" target="_blank">建議點選這裡檢視教程~~~~</a>\ '); html.push('</td></tr>'); html.push('<tr style="display:none;">'); html.push('<td><a href="http://www.fishlee.net/soft/44/12306faq.html" target="_blank">訂票常見問題</a></td>'); html.push('<td><a href="http://www.fishlee.net/soft/44/faq.html" target="_blank">助手運作常見問題</a></td>'); html.push('</tr>'); html.push('</table>'); html.push('</div><div class="tabLog tabContent"><div>下面是目前頁面的記錄。如果您的助手遇到功能上的問題,請全部複制後發成郵件給作者:[email protected] 以便于老衲解決問題。<span style="color:red;font-weight:bold;">請在發送前務必剔除記錄中包含的個人隐私如密碼等資訊。</span></div><textarea id="runningLog" style="width:100%;height:200px;"></textarea></div>'); //擷取登入到IE的代碼 Add By XPHelper 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>'); html.push('<div class="control">'); html.push('<input type="button" class="close_button" value="關閉" />'); html.push('</div>'); html.push('</div>'); html.push('</div>'); $("body").append(html.join("")); var opt = $("#fishOption"); $("#regButton").click(function () { var sn = $.trim($("#regContent").val()); var rt = utility.verifySn(false, "", sn); if (rt.result != 0) { alert("很抱歉, 注冊失敗. 代碼 " + rt.result + ", " + rt.msg); } else { utility.setSnInfo("", sn); alert("注冊成功, 請重新整理浏覽器。\n注冊給 - " + rt.name + " , 注冊類型 - " + rt.typeDesc.replace(/<[^>]*>/gi, "")); try { utility.getTopWindow().location.reload(); } catch (e) { alert("權限不足無法重新整理頁面, 請手動重新整理目前頁!"); } } }); $("#unReg, a.reSignHelper").live("click", function () { if (!confirm("确定要重新注冊嗎?")) return; utility.setSnInfo("", ""); utility.getTopWindow().location.reload(); }); //初始化設定 utility.configTab = utility.fishTab(opt); opt.find("input[name]").each(function () { var el = $(this); var key = el.attr("name"); var value = window.localStorage.getItem(key); if (!value) return; if (el.attr("type") == "checkbox") { el.attr("checked", value == "1"); } else { el.val(value); } }).change(function () { var el = $(this); var key = el.attr("name"); if (el.attr("type") == "checkbox") { window.localStorage.setItem(key, el[0].checked ? 1 : 0); } else { window.localStorage.setItem(key, el.val()); } }); $("#configLink, .configLink").live("click", function () { var el = $(this); var dp = el.attr("tab"); utility.getTopWindow().utility.showLoginIE(); utility.getTopWindow().utility.showOptionDialog(dp || ""); }); //新版本更新顯示提示 if (utility.getPref("helperVersion") != window.helperVersion) { //檢測老版本設定 if (utility.getAudioUrl().indexOf("github") != -1 || utility.getAudioUrl().indexOf("https://") != -1) { utility.resetAudioUrl(); } utility.setPref("helperVersion", window.helperVersion); //僅頂層頁面顯示 try { if (parent == self) utility.showOptionDialog("tabVersion"); } catch (ex) { //跨域了,也是頂級 utility.showOptionDialog("tabVersion"); } } //注冊 var result = utility.verifySn(true); if (result.result == 0) { var info = opt.find(".registered").show().find("strong"); info.eq(0).html(result.name); info.eq(1).html(result.typeDesc); } else { opt.find(".regTable").show(); if (location.pathname == "/otsweb/" || location.pathname == "/otsweb/main.jsp") { alert("為了阻止地球人趁火打劫然後拿着老衲免費奉獻的東東去賣錢,貧僧鬥膽麻煩客官……啊不,施主注冊下下,一下子就好了啦!"); window.open("http://www.fishlee.net/Apps/Cn12306/GetNormalRegKey"); utility.showOptionDialog("tabReg"); } } utility.regInfo = result; } //#endregion //#region -----------------執行環境相容---------------------- var utility = { configTab: null, icon: "http://www.12306.cn/mormhweb/images/favicon.ico", notifyObj: null, timerObj: null, regInfo: null, isWebKit: function () { return navigator.userAgent.indexOf("WebKit") != -1; }, trim: function (data) { if (typeof ($) != 'undefined') return $.trim(data); return data.replace(/(^\s+|\s+$)/g, ""); }, getTopWindow: function () { try { if (parent == self) return self; else return parent.window.utility.getTopWindow(); } catch (e) { //跨域的話,也是頂層 return self; } }, init: function () { $.extend({ any: function (array, callback) { var flag = false; $.each(array, function (i, v) { flag = callback.call(this, i, v); if (flag) return false; }); return flag; }, first: function (array, callback) { var result = null; $.each(array, function (i, v) { result = callback.call(this, i, v); if (result) return false; }); return result; } }); (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) }, runningQueue: null, appendLog: function (settings) { /// <summary>記錄日志</summary> if (!utility.runningQueue) utility.runningQueue = []; var log = { url: settings.url, data: settings.data, response: null, success: null }; if (log.url.indexOf("Passenger") != -1) return; //不記錄對乘客的請求 utility.runningQueue.push(log); settings.log = log; }, showLog: function () { if (!utility.runningQueue) { alert("目前頁面尚未産生日志記錄。"); return; } var log = []; $.each(utility.runningQueue, function () { log.push("成功:" + (this.success ? "是" : "否") + "\r\n位址:" + this.url + "\r\n送出資料:" + utility.formatData(this.data) + "\r\n傳回資料:" + utility.formatData(this.response)); }); $("#runningLog").val(log.join("\r\n----------------------------------\r\n")); utility.showOptionDialog("tabLog"); }, //擷取登入到IE的代碼 Add By XPHelper showLoginIE: function () { var strCookie = document.cookie; var arrCookie = strCookie.split("; "); var IECode = "javascript:"; var cookie = []; for (var i = 0; i < arrCookie.length; i++) { var arr = arrCookie[i].split("="); if (arr.length < 2 || arr[0].indexOf("helper.") != -1) continue; cookie.push("document.cookie=\"" + arr[0] + "=" + arr[1] + "\";"); } IECode += cookie.join(""); IECode += "self.location.reload();"; $("#LoginIECode").val(IECode); }, formatData: function (data) { if (!data) return "(null)"; if (typeof (data) == "string") return data; var html = []; for (var i in data) { html.push('"' + i + '":\"' + (this[i] + "").replace(/(\r|\n|")/g, function (a) { "\\" + a; }) + '\"'); } return "{" + html.join(",") + "}"; }, notify: function (msg, timeout) { console.log("資訊提示: " + msg); if (window.webkitNotifications) { if (window.webkitNotifications.checkPermission() == 0) { utility.closeNotify(); if (utility.notifyObj == null) utility.notifyObj = webkitNotifications.createNotification(utility.icon, '訂票', msg); utility.notifyObj.show(); if (!timeout || timeout != 0) utility.timerObj = setTimeout(utility.closeNotify, timeout || 5000); } else { alert("【啊喂!!桌面通知還木有開啟!請戳界面中的『點選啟用桌面通知』按鈕來開啟!】\n\n" + msg); } } else { if (typeof (GM_notification) != 'undefined') { GM_notification(msg); } else { console.log("首頁面中腳本資訊, 無法提示, 寫入通知區域."); utility.notifyOnTop(msg); } } }, notifyOnTop: function (msg) { window.localStorage.setItem("notify", msg); }, closeNotify: function () { if (!utility.notifyObj) return; utility.notifyObj.cancel(); if (utility.timerObj) { clearTimeout(utility.timerObj); } utility.timerObj = null; utility.notifyObj = null; }, setPref: function (name, value) { window.localStorage.setItem(name, value); }, getPref: function (name) { return window.localStorage.getItem(name); }, unsafeCallback: function (callback) { if (typeof (unsafeInvoke) == "undefined") callback(); else unsafeInvoke(callback); }, getTimeInfo: function () { var d = new Date(); return d.getHours() + ":" + (d.getMinutes() < 10 ? "0" : "") + d.getMinutes() + ":" + (d.getSeconds() < 10 ? "0" : "") + d.getSeconds(); }, savePrefs: function (obj, prefix) { var objs = obj.find("input"); objs.change(function () { var type = this.getAttribute("type"); if (type == "text") utility.setPref(prefix + "_" + this.getAttribute("id"), $(this).val()); else if (type == "checkbox") utility.setPref(prefix + "_" + this.getAttribute("id"), this.checked ? 1 : 0); }) }, reloadPrefs: function (obj, prefix) { var objs = obj.find("input"); prefix = prefix || ""; objs.each(function () { var e = $(this); var type = e.attr("type"); var id = e.attr("id"); var value = utility.getPref(prefix + "_" + id); if (typeof (value) == "undefined" || value == null) return; if (type == "text") e.val(value); else if (type == "checkbox") this.checked = value == "1"; e.change(); }); utility.savePrefs(obj, prefix); }, getErrorMsg: function (msg) { /// <summary>獲得給定資訊中的錯誤資訊</summary> var m = msg.match(/var\s+message\s*=\s*"([^"]*)/); return m && m[1] ? m[1] : "<未知資訊>"; }, delayInvoke: function (target, callback, timeout) { target = target || "#countEle"; var e = typeof (target) == "string" ? $(target) : target; if (timeout <= 0) { e.html("正在執行").removeClass("fish_clock").addClass("fish_running"); callback(); } else { var str = (Math.floor(timeout / 100) / 10) + ''; if (str.indexOf(".") == -1) str += ".0"; e.html(str + " 秒後再來!...").removeClass("fish_running").addClass("fish_clock"); setTimeout(function () { utility.delayInvoke(target, callback, timeout - 500); }, 500); } }, saveList: function (name) { /// <summary>将指定清單的值儲存到配置中</summary> var dom = document.getElementById(name); window.localStorage["list_" + name] = utility.getOptionArray(dom).join("\t"); }, loadList: function (name) { /// <summary>将指定的清單的值從配置中加載</summary> var dom = document.getElementById(name); var data = window.localStorage["list_" + name]; if (!data) return; if (data.indexOf("\t") != -1) data = data.split('\t'); else data = data.split('|'); $.each(data, function () { dom.options[dom.options.length] = new Option(this, this); }); }, addOption: function (dom, text, value) { /// <summary>在指定的清單中加入新的選項</summary> dom.options[dom.options.length] = new Option(text, value); }, getOptionArray: function (dom) { /// <summary>獲得選項的數組格式</summary> return $.map(dom.options, function (o) { return o.value; }); }, inOptionList: function (dom, value) { /// <summary>判斷指定的值是否在清單中</summary> for (var i = 0; i < dom.options.length; i++) { if (dom.options[i].value == value) return true; } return false; }, getAudioUrl: function () { /// <summary>獲得音樂位址</summary> 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"); }, getFailAudioUrl: function () { return (utility.isWebKit() ? "http://resbak.fishlee.net/res/" : "http://resbak.fishlee.net/res/") + "music3.ogg"; }, playFailAudio: function () { if (!window.Audio) return; new Audio(utility.getFailAudioUrl()).play() }, resetAudioUrl: function () { /// <summary>恢複音樂位址為預設</summary> window.localStorage.removeItem("audioUrl"); }, parseDate: function (s) { /(\d{4})[-/](\d{1,2})[-/](\d{1,2})/.exec(s); return new Date(RegExp.$1, RegExp.$2 - 1, RegExp.$3); }, getDate: function (s) { /// <summary>獲得指定日期的天機關</summary> return new Date(s.getFullYear(), s.getMonth(), s.getDate()); }, formatDate: function (d) { /// <summary>格式化日期</summary> var y = d.getFullYear(); return y + "-" + utility.formatDateShort(d); }, formatDateShort: function (d) { /// <summary>格式化日期</summary> var mm = d.getMonth() + 1; var d = d.getDate(); return (mm > 9 ? mm : "0" + mm) + "-" + (d > 9 ? d : "0" + d); }, formatTime: function (d) { function padTo2Digit(digit) { return digit < 10 ? '0' + digit : digit; } return utility.formatDate(d) + " " + padTo2Digit(d.getHours()) + ":" + padTo2Digit(d.getMinutes()) + ":" + padTo2Digit(d.getSeconds()); }, addTimeSpan: function (date, y, mm, d, h, m, s) { /// <summary>對指定的日期進行偏移</summary> return new Date(date.getFullYear() + y, date.getMonth() + mm, date.getDate() + d, date.getHours() + h, date.getMinutes() + m, date.getSeconds() + s); }, serializeForm: function (form) { /// <summary>序列化表單為對象</summary> var v = {}; var o = form.serializeArray(); for (var i in o) { if (typeof (v[o[i].name]) == 'undefined') v[o[i].name] = o[i].value; else v[o[i].name] += "," + o[i].value; } return v; }, getSecondInfo: function (second) { var show_time = ""; var hour = parseInt(second / 3600); //時 if (hour > 0) { show_time = hour + "小時"; second = second % 3600; } var minute = parseInt(second / 60); //分 if (minute >= 1) { show_time = show_time + minute + "分"; second = second % 60; } else if (hour >= 1 && second > 0) { show_time = show_time + "0分"; } if (second > 0) { show_time = show_time + second + "秒"; } return show_time; }, post: function (url, data, dataType, succCallback, errorCallback) { $.ajax({ url: url, data: data, timeout: 10000, type: "POST", success: succCallback, error: errorCallback, dataType: dataType }); }, get: function (url, data, dataType, succCallback, errorCallback) { $.ajax({ url: url, data: data, timeout: 10000, type: "GET", success: succCallback, error: errorCallback, dataType: dataType }); }, showDialog: function (object, optx) { /// <summary>顯示對話框。其中帶有 close_button 樣式的控件會自動作為關閉按鈕</summary> return (function (opt) { var dataKey = "fs_dlg_opt"; if (this.data(dataKey)) { //this.data(dataKey).closeDialog(); return; } 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); this.data("fs_dlg_opt", opt); var top = "0px"; var left = "50%"; this.css({ "position": opt.parent ? "absolute" : "fixed", "left": left, "top": top, "margin-left": "-" + (this.width() / 2) + "px", "margin-top": "0px", "z-index": "9999" }); var obj = this; this.changeLoadingIcon = function (icon) { /// <summary>更改加載對話框的圖示</summary> obj.removeClass().addClass("loadingDialog loadicon_" + (icon || "tip")); return obj; }; this.autoCloseDialog = function (timeout) { /// <summary>設定目前對話框在指定時間後自動關閉</summary> setTimeout(function () { obj.closeDialog(); }, timeout || 2500); return obj; }; this.setLoadingMessage = function (msgHtml) { obj.find("div").html(msgHtml); return obj; }; this.closeDialog = function () { /// <summary>關閉對話框</summary> obj.removeData(dataKey); obj.animate({ "marginTop": "+=" + opt.animationMove + "px", "opacity": "hide" }, opt.speed, opt.fx, function () { if (opt.bindControl) opt.bindControl.enable(); if (opt.onClose) opt.onClose.call(obj); if (opt.removeDialog) obj.remove(); }) return obj; }; $('.close_button', this).unbind("click").click(obj.closeDialog); //auto close if (opt.timeOut > 0) { var handler = opt.onShow; opt.onShow = function () { setTimeout(function () { $(obj).closeDialog(); }, opt.timeOut); if (handler != null) handler.call(this); }; } //show it if (opt.bindControl) opt.bindControl.disable(); this.animate({ "marginTop": "+=" + opt.animationMove + "px", "opacity": "show" }, opt.speed, opt.fx, function () { opt.onShow && opt.onShow.call(obj); }) this.data(dataKey, this); return this; }).call(object, optx); }, fishTab: function (obj, opt) { return (function (opt) { var self = this; opt = $.extend({ switchOnHover: false, switchOnClick: true }, opt); this.addClass("fishTab"); this.showTab = function (tabid) { self.find(".current").removeClass("current"); self.find("ul.tabNav li[tab=" + tabid + "], div." + tabid).addClass("current"); }; self.find(".tabNav li").hover(function () { if (!opt.switchOnHover) return; self.showTab($(this).attr("tab")); }).click(function () { if (!opt.switchOnClick) return; self.showTab($(this).attr("tab")); }); this.showTab(self.find(".tabNav").attr("default") || self.find(".tabNav li:eq(0)").attr("tab")); return this; }).call(obj, opt); }, getLoginRetryTime: function () { return parseInt(window.localStorage.getItem("login.retryLimit")) || 2000; }, showOptionDialog: function (tab) { if (tab) utility.configTab.showTab(tab); utility.showDialog($("#fishOption")); }, addCookie: function (name, value, expDays) { var cook = name + "=" + value + "; path=/; domain=.12306.cn"; if (expDays > 0) { cook += "; expires=" + new Date(new Date().getTime() + expDays * 3600 * 1000 * 24).toGMTString(); } document.cookie = cook; }, getCookie: function (name) { var cook = document.cookie; var arr = cook.split("; "); for (var i = 0; i < arr.length; i++) { var arg = arr[i].split('='); if (arg[0] == name) return arg[1]; } }, setSnInfo: function (name, sn) { utility.setPref("helper.regUser", name); utility.setPref("helper.regSn", sn); utility.addCookie("helper.regUser", name, 999); utility.addCookie("helper.regSn", sn, 999); }, verifySn: function (skipTimeVerify, name, sn) { name = name || utility.getPref("helper.regUser") || utility.getCookie("helper.regUser"); sn = sn || utility.getPref("helper.regSn") || utility.getCookie("helper.regSn"); if (!name && sn) return utility.verifySn2(skipTimeVerify, sn); if (!name || !sn) return { result: -4, msg: "未注冊" }; utility.setSnInfo(name, sn); var args = sn.split(','); if (!skipTimeVerify) { if ((new Date() - args[0]) / 60000 > 5) { return { result: -1, msg: "序列号注冊已失效" }; } } var dec = []; var encKey = args[0] + args[1]; var j = 0; for (var i = 0; i < args[2].length; i += 4) { dec.push(String.fromCharCode(parseInt(args[2].substr(i, 4), 16) ^ encKey.charCodeAt(j))); j++; if (j >= encKey.length) j = 0; } var data = dec.join(""); data = { result: null, type: data.substring(0, 4), name: data.substring(4) }; data.result = data.name == name ? 0 : -3; data.msg = data.result == 0 ? "成功驗證" : "注冊無效" data.typeDesc = data.type == "NRML" ? "正式版" : (data.type == "GROP" ? "内部版, <span style='color:blue;'>感謝您參與我們之中</span>!" : "<span style='color:red;'>捐助版, 非常感謝您的支援</span>!"); return data; }, verifySn2: function (skipTimeVerify, data) { data = utility.trim(data); try { var nameLen = parseInt(data.substr(0, 2), 16); var name = data.substr(2, nameLen); data = data.substring(2 + nameLen); var arr = []; for (var i = 0; i < data.length; i++) { var c = data.charCodeAt(i); if (c >= 97) arr.push(String.fromCharCode(c - 49)); else arr.push(data.charAt(i)); } data = arr.join(""); var ticket = parseInt(data.substr(0, 14), 16); var key = parseInt(data.substr(14, 1), 16); var encKey = ticket.toString(16).toUpperCase() + key.toString().toUpperCase(); data = data.substring(15); var dec = []; var j = 0; for (var i = 0; i < data.length; i += 4) { dec.push(String.fromCharCode(parseInt(data.substr(i, 4), 16) ^ encKey.charCodeAt(j))); j++; if (j >= encKey.length) j = 0; } dec = dec.join("").split('|'); var regVersion = dec[0].substr(0, 4); var regName = dec[0].substring(4); var bindAcc = dec.slice(1, dec.length); if (!bindAcc && !skipTimeVerify && (new Date() - ticket) / 60000 > 5) { return { result: -1, msg: "注冊碼已失效, 請重新申請" }; } if (regName != name) { return { result: -3, msg: "注冊失敗,使用者名不比對" }; } var data = { name: name, type: regVersion, bindAcc: bindAcc, ticket: ticket, result: 0, msg: "成功注冊" }; switch (data.type) { case "NRML": data.typeDesc = "正式版"; break; case "GROP": data.typeDesc = "内部版, <span style='color:blue;'>感謝您參與我們之中</span>!"; break; case "DONT": data.typeDesc = "<span style='color:red;'>捐助版, 非常感謝您的支援</span>!"; break; case "PART": data.typeDesc = "合作版,歡迎您的使用"; } data.regTime = new Date(ticket); data.regVersion = 2; return data; } catch (e) { return { result: -4, msg: "資料錯誤" }; } }, allPassengers: null, getAllPassengers: function (callback) { if (utility.allPassengers) { callback(utility.allPassengers); } //開始加載所有乘客 utility.allPassengers = []; var pageIndex = 0; function loadPage() { utility.post("/otsweb/passengerAction.do?method=getPagePassenger", { pageSize: 10, pageIndex: pageIndex }, "json", function (json) { $.each(json.rows, function () { utility.allPassengers.push(this); }); if (utility.allPassengers.length >= json.recordCount) { callback(utility.allPassengers); } else { pageIndex++; setTimeout(loadPage, 1000); } }, function () { setTimeout(loadPage, 3000); }); } loadPage(); }, regCache: {}, getRegCache: function (value) { return utility.regCache[value] || (utility.regCache[value] = new RegExp("^(" + value + ")$", "i")); }, preCompileReg: function (optionList) { var data = $.map(optionList, function (e) { return e.value; }); return new RegExp("^(" + data.join("|") + ")$", "i"); }, enableLog: function () { $("body").append('<button style="width:100px;position:fixed;right:0px;top:0px;height:35px;" onclick="utility.showLog();">顯示運作日志</button>'); $(document).ajaxSuccess(function (a, b, c) { if (!c.log) return; c.log.response = b.responseText; c.log.success = true; }).ajaxSend(function (a, b, c) { utility.appendLog(c); }).ajaxError(function (a, b, c) { if (!c.log) return; c.log.response = b.responseText; }); }, //擷取登入到IE的代碼 Add By XPHelper enableLoginIE: function () { $("body").append('<button style="width:150px;position:fixed;right:0px;top:0px;height:35px;" class="configLink" tab="tabLoginIE">擷取登入到IE的代碼</button>'); }, analyzeForm: function (html) { var data = {}; //action var m = /<form.*?action="([^"]+)"/.exec(html); data.action = m ? RegExp.$1 : ""; //inputs data.fields = {}; var inputs = html.match(/<input\s*(.|\r|\n)*?>/gi); $.each(inputs, function () { if (!/name=['"]([^'"]+?)['"]/.exec(this)) return; var name = RegExp.$1; data.fields[RegExp.$1] = !/value=['"]([^'"]+?)['"]/.exec(this) ? "" : RegExp.$1; }); //tourflag m = /submit_form_confirm\('confirmPassenger','([a-z]+)'\)/.exec(html); if (m) data.tourFlag = RegExp.$1; return data; }, selectionArea: function (opt) { var self = this; this.options = $.extend({ onAdd: function () { }, onRemove: function () { }, onClear: function () { }, onRemoveConfirm: function () { return true; }, syncToStorageKey: "", defaultList: null, preloadList: null }, opt); this.append('<div style="padding: 5px; border: 1px dashed gray; background-color: rgb(238, 238, 238); width:120px;">(還沒有添加任何項)</div>'); this.datalist = []; this.add = function (data) { if ($.inArray(data, self.datalist) > -1) return; var text = typeof (data) == "string" ? data : data.text; var html = $('<input type="button" class="lineButton" value="' + text + '" title="點選删除" />'); self.append(html); html.click(self.removeByButton); self.datalist.push(data); self.syncToStorage(); self.checkEmpty(); self.options.onAdd.call(self, data, html); }; this.removeByButton = function () { var obj = $(this); var idx = obj.index() - 1; var value = self.datalist[idx]; if (!self.options.onRemoveConfirm.call(self, value, obj, idx)) { return; } obj.remove(); self.datalist.splice(idx, 1); self.syncToStorage(); self.checkEmpty(); self.options.onRemove.call(self, value, obj); }; this.emptyList = function () { self.datalist = []; self.find("input").remove(); self.syncToStorage(); self.checkEmpty(); self.options.onClear.call(self); }; this.isInList = function (data) { /// <summary>判斷指定的值是否在清單中</summary> return $.inArray($.inArray(data, self.datalist)) > -1; }; this.isInRegList = function (data) { /// <summary>判斷指定的值是否在清單中。這裡假定是字元串,使用正則進行判斷</summary> for (var i = 0; i < self.datalist.length; i++) { if (utility.getRegCache(self.datalist[i]).test(data)) return true; } return false; }; this.syncToStorage = function () { if (!self.options.syncToStorageKey) return; window.localStorage.setItem(self.options.syncToStorageKey, self.datalist.join("\t")); }; this.checkEmpty = function () { if (self.find("input").length) { self.find("div").hide(); } else { self.find("div").show(); } }; if (self.options.syncToStorageKey) { var list = self.options.preloadList; if (!list) { var list = window.localStorage.getItem(this.options.syncToStorageKey); if (!list) list = this.options.defaultList; else list = list.split('\t'); } if (list) { $.each(list, function () { self.add(this + ""); }); } } return this; } } function unsafeInvoke(callback) { /// <summary>非沙箱模式下的回調</summary> var cb = document.createElement("script"); cb.type = "text/javascript"; cb.textContent = buildCallback(callback); document.head.appendChild(cb); } function buildCallback(callback) { var content = ""; if (!utility_emabed) { 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"; utility_emabed = true; } content += "window.__cb=" + buildObjectJavascriptCode(callback) + ";\r\n\ if(typeof(jQuery)!='undefined')window.__cb();\r\n\ else{\ var script=document.createElement('script');\r\nscript.src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js';\r\n\ script.type='text/javascript';\r\n\ script.addEventListener('load', window.__cb);\r\n\ document.head.appendChild(script);\r\n\ }"; return content; } function buildObjectJavascriptCode(object) { /// <summary>将指定的Javascript對象編譯為腳本</summary> if (!object) return null; var t = typeof (object); if (t == "string") { return "\"" + object.replace(/(\r|\n|\\)/gi, function (a, b) { switch (b) { case "\r": return "\\r"; case "\n": return "\\n"; case "\\": return "\\\\"; } }) + "\""; } if (t != "object") return object + ""; var code = []; for (var i in object) { var obj = object[i]; var objType = typeof (obj); if ((objType == "object" || objType == "string") && obj) { code.push(i + ":" + buildObjectJavascriptCode(obj)); } else { code.push(i + ":" + obj); } } return "{" + code.join(",") + "}"; } var isChrome = navigator.userAgent.indexOf("AppleWebKit") != -1; var isFirefox = navigator.userAgent.indexOf("Firefox") != -1; if (location.host == "dynamic.12306.cn" || (location.host == "www.12306.cn" && location.protocol == "https:")) { if (!isChrome && !isFirefox) { alert("很抱歉,未能識别您的浏覽器,或您的浏覽器尚不支援腳本運作,請使用Firefox或Chrome浏覽器!\n如果您運作的是Maxthon3,請确認目前頁面運作在高速模式而不是相容模式下 :-)"); } else if (isFirefox && typeof (GM_notification) == 'undefined') { alert("很抱歉,本腳本需要最新的Scriptish擴充、不支援GreaseMonkey,請禁用您的GreaseMonkey擴充并安裝Scriptish!"); window.open("https://addons.mozilla.org/zh-CN/firefox/addon/scriptish/"); } else if (!window.localStorage) { alert("警告! localStorage 為 null, 助手無法運作. 請檢視浏覽器是否已經禁用 localStorage!\nFirefox請設定 about:config 中的 dom.storage.enabled 為 true ."); } else { //記錄更新 utility.setPref("updates", updates.join("\t")); initUIDisplay(); unsafeInvoke(injectDom); entryPoint(); } } //#endregion //#region -----------------入口---------------------- function entryPoint() { var location = window.location; var path = location.pathname; utility.regInfo = utility.verifySn(true); if (utility.regInfo.result != 0) { return; } // unsafeInvoke(autoReloadIfError); if ((path == "/otsweb/loginAction.do" && location.search != '?method=initForMy12306') || path == "/otsweb/login.jsp") { //登入頁 unsafeInvoke(initLogin); } if (utility.regInfo.bindAcc && localStorage.getItem("_sessionuser") && utility.regInfo.bindAcc.length > 0 && utility.regInfo.bindAcc[0] && utility.regInfo.bindAcc[0] != "*") { var user = localStorage.getItem("_sessionuser"); var ok = false; for (var i = 0; i < utility.regInfo.bindAcc.length; i++) { if (utility.regInfo.bindAcc[i] == user) { ok = true; break; } } if (!ok) return; } if (path == "/otsweb/order/querySingleAction.do") { if (location.search == "?method=init" && document.getElementById("submitQuery")) { unsafeInvoke(initTicketQuery); unsafeInvoke(initDirectSubmitOrder); } if (location.search == "?method=submutOrderRequest") { unsafeInvoke(initSubmitOrderQuest); } } if (path == "/otsweb/order/orderAction.do") { if (location.search.indexOf("method=cancelMyOrderNotComplete") != -1 && document.getElementById("submitQuery")) { unsafeInvoke(initTicketQuery); unsafeInvoke(initDirectSubmitOrder); } } if (path == "/otsweb/order/payConfirmOnlineSingleAction.do") { if (location.search.indexOf("method=cancelOrder") != -1 && document.getElementById("submitQuery")) { unsafeInvoke(initTicketQuery); unsafeInvoke(initDirectSubmitOrder); } } if (path == "/otsweb/order/myOrderAction.do") { if (location.search.indexOf("method=resign") != -1 && document.getElementById("submitQuery")) { unsafeInvoke(initTicketQuery); unsafeInvoke(initDirectSubmitOrder); } } if (path == "/otsweb/order/confirmPassengerAction.do") { if (location.search == "?method=init") { unsafeInvoke(initAutoCommitOrder); unsafeInvoke(autoCommitOrderInSandbox); } if (location.search.indexOf("?method=payOrder") != -1) { unsafeInvoke(initPagePayOrder); //擷取登入到IE的代碼 Add By XPHelper unsafeInvoke(utility.enableLoginIE); } } if (path == "/otsweb/order/myOrderAction.do") { if (location.search.indexOf("?method=laterEpay") != -1 || location.search.indexOf("?method=queryMyOrderNotComplete") != -1) { unsafeInvoke(initNotCompleteOrderPage); unsafeInvoke(initPayOrder); //擷取登入到IE的代碼 Add By XPHelper unsafeInvoke(utility.enableLoginIE); } } if (path == "/otsweb/main.jsp" || path == "/otsweb/") { //主架構 console.log("正在注入主架構腳本。"); //跨頁面彈窗提示,防止因為頁面跳轉導緻對話框不關閉 console.log("啟動跨頁面資訊調用檢查函數"); window.setInterval(function () { var msg = window.localStorage["notify"]; if (typeof (msg != 'undefined') && msg) { console.log("主視窗攔截提示請求: " + msg); window.localStorage.removeItem("notify"); utility.notify(msg); } }, 100); unsafeInvoke(injectMainPageFunction); } } //#endregion //#region 未完成訂單查詢頁面 function initNotCompleteOrderPage() { //處理顯示時間的 (function () { var tagInputs = $("input[name=cache_tour_flag]"); var flags = $.map(tagInputs, function (e, i) { return e.value; }); $.each(flags, function () { $("#showTime_" + this).hide().after("<span id='status_" + this + "'>正在查詢...</span>"); }); function doCheck() { var flag = flags.shift(); flags.push(flag); utility.get("https://dynamic.12306.cn/otsweb/order/myOrderAction.do?method=getOrderWaitTime&tourFlag=" + flag, null, "json", function (data) { var obj = $("#status_" + flag); if (data.waitTime == 0 || data.waitTime == -1) { obj.css({ "color": "green" }).html("訂票成功!"); utility.notifyOnTop("訂票成功!請盡快付款!"); parent.playAudio(); self.location.reload(); return; } if (data.waitTime == -2) { utility.notifyOnTop("出票失敗!請重新訂票!" + data.msg); parent.playFailAudio(); obj.css({ "color": "red" }).html("出票失敗!" + data.msg); return; } if (data.waitTime == -3) { utility.notifyOnTop("訂單已經被取消!"); parent.playFailAudio(); obj.css({ "color": "red" }).html("訂單已經被取消!!"); return; } if (data.waitTime == -4) { utility.notifyOnTop("正在進行中...."); obj.css({ "color": "blue" }).html("正在進行中...."); } if (data.waitTime > 0) { obj.css({ "color": "red" }).html("排隊中<br />排隊數【" + (data.waitCount || "未知") + "】<br />預計時間【" + utility.getSecondInfo(data.waitTime) + "】<br />不過這時間不<br />怎麼靠譜 ╮(╯▽╰)╭"); } else { obj.css({ "color": "red" }).html("奇怪的狀态碼 [" + data.waitTime + "]...."); } setTimeout(doCheck, 2000); }, function () { utility.notifyOnTop("查詢狀态錯誤,正在重新整理頁面!"); self.location.reload(); }); } if (flags.length > 0) doCheck(); })(); } //#endregion //#region 送出頁面出錯 function initSubmitOrderQuest() { if ($("div.error_text").length > 0) { parent.window.resubmitForm(); } } //#endregion //#region 訂票頁面,聲音提示 function initPagePayOrder() { new Audio(utility.getAudioUrl()).play(); } //#endregion //#region -----------------出錯自動重新整理---------------------- function autoReloadIfError() { if ($.trim($("h1:first").text()) == "錯誤") { $("h1:first").css({ color: 'red', 'font-size': "18px" }).html(">_< 啊吖!,敢踹我出門啦。。。2秒後我一定會回來的 ╮(╯▽╰)╭"); setTimeout(function () { self.location.reload(); }, 2000); } } //#endregion //#region -----------------主架構---------------------- function injectMainPageFunction() { //資源 var main = $("#main")[0]; main.onload = function () { var location = null; try { location = main.contentWindow.location + ''; } catch (e) { //出錯了,跨站 } if (!location || location == "http://www.12306.cn/mormhweb/logFiles/error.html") { resubmitForm(); } } if (window.webkitNotifications && window.webkitNotifications.checkPermission() != 0) { if (confirm("喂!快戳『點選啟用桌面通知』,不然提示會阻礙操作,導緻運作變慢,然後就沒票了!\n\n如果是第一次看到介句話,點選『取消』并按提示操作。如果反複邂逅這個對話框,就戳『确定』以打開助手首頁的常見問題并查找解決辦法。\n\n搜狗高速浏覽器暫不支援儲存此權限,每次通路時可能都會邂逅這個對話框……")) { window.open("http://www.fishlee.net/soft/44/faq.html"); } } window.resubmitForm = function () { var form = $("#orderForm"); if (form.length == 0 || form.attr("success") != "0") return; utility.notify("頁面出錯了!正在重新預定!"); setTimeout(function () { document.getElementById("orderForm").submit(); }, 3000); } window.playAudio = function () { new Audio(utility.getAudioUrl()).play(); }; window.playFailAudio = function () { utility.playFailAudio(); }; } //#endregion //#region -----------------自動送出---------------------- function initAutoCommitOrder() { var count = 0; var breakFlag = 0; var randCode = ""; var submitFlag = false; var tourFlag = 'dc'; var randEl = $("#rand"); //啟用日志 utility.enableLog(); //#region 如果系統出錯,那麼重新送出 if ($(".error_text").length > 0 && parent.$("#orderForm").length > 0) { parent.resubmitForm(); return; } //#endregion //獲得tourflag (function () { /'(dc|fc|wc|gc)'/.exec($("div.tj_btn :button:eq(2)")[0].onclick + ''); tourFlag = RegExp.$1; })(); function stop(msg) { setCurOperationInfo(false, "錯誤 - " + msg); setTipMessage(msg); $("div.tj_btn button, div.tj_btn input").each(function () { this.disabled = false; $(this).removeClass().addClass("long_button_u"); }); $("#btnCancelAuto").hide(); } var reloadCode = function () { $("#img_rrand_code").click(); $("#rand").val("")[0].select(); }; var getSleepTime = function () { return 1000 * Math.max(parseInt($("#pauseTime").val()), 1); }; //訂單等待時間過久的警告 var waitTimeTooLong_alert = false; function submitForm() { randEl[0].blur(); stopCheckCount(); if (!window.submit_form_check || !submit_form_check("confirmPassenger")) { setCurOperationInfo(false, "您的表單沒有填寫完整!"); stop("請填寫完整表單"); return; } count++; setCurOperationInfo(true, "第 " + count + " 次送出"); if (breakFlag) { stop("已取消自動送出"); breakFlag = 0; return; } $("#btnCancelAuto").show().removeClass().addClass("long_button_u_down")[0].disabled = false; //阻止被禁用 breakFlag = 0; waitTimeTooLong_alert = false; $("#confirmPassenger").ajaxSubmit({ url: 'confirmPassengerAction.do?method=checkOrderInfo&rand=' + $("#rand").val(), type: "POST", data: { tFlag: tourFlag }, dataType: "json", success: function (data) { if ('Y' != data.errMsg || 'N' == data.checkHuimd || 'N' == data.check608) { setCurOperationInfo(false, data.msg || data.errMsg); stop(data.msg || data.errMsg); reloadCode(); } else { queryQueueCount(); } }, error: function (msg) { setCurOperationInfo(false, "目前請求發生錯誤"); utility.delayInvoke(null, submitForm, 1000); } }); } function queryQueueCount() { var queryLeftData = { train_date: $("#start_date").val(), train_no: $("#train_no").val(), station: $("#station_train_code").val(), seat: $("#passenger_1_seat").val(), from: $("#from_station_telecode").val(), to: $("#to_station_telecode").val(), ticket: $("#left_ticket").val() }; utility.get("/otsweb/order/confirmPassengerAction.do?method=getQueueCount", queryLeftData, "json", function (data) { console.log(data); if (data.op_2) { var errmsg = "排隊人數過多,系統禁止排隊,稍等自動重試 (排隊人數=" + data.count + ")"; setCurOperationInfo(true, errmsg); stop(errmsg); utility.delayInvoke(null, queryQueueCount, 1000); return; } submitConfirmOrder(); }, function () { utility.delayInvoke(null, queryLeftTickets, 2000); }); } function submitConfirmOrder() { jQuery.ajax({ url: '/otsweb/order/confirmPassengerAction.do?method=confirmSingleForQueueOrder', data: $('#confirmPassenger').serialize(), type: "POST", timeout: 10000, dataType: 'json', success: function (msg) { console.log(msg); var errmsg = msg.errMsg; if (errmsg != 'Y') { if (errmsg.indexOf("包含未付款訂單") != -1) { alert("您有未支付訂單! 等啥呢, 趕緊點确定支付去."); window.location.replace("/otsweb/order/myOrderAction.do?method=queryMyOrderNotComplete&leftmenu=Y"); return; } if (errmsg.indexOf("重複送出") != -1) { stop("重複送出錯誤,已重新整理TOKEN,請重新輸入驗證碼送出"); reloadToken(); reloadCode(); return; } if (errmsg.indexOf("背景處理異常") != -1 || errmsg.indexOf("非法請求") != -1) { if (lastform) { utility.notifyOnTop("背景處理異常,已自動重新送出表單,請填寫驗證碼并送出!"); lastform.submit(); } else { stop("背景處理異常,請傳回查詢頁重新預定!"); } return; } if (errmsg.indexOf("包含排隊中") != -1) { console.log("驚現排隊中的訂單, 進入輪詢狀态"); waitingForQueueComplete(); return; } setCurOperationInfo(false, errmsg); stop(errmsg); reloadCode(); } else { utility.notifyOnTop("訂單送出成功, 正在等待隊列完成操作,請及時注意訂單狀态"); waitingForQueueComplete(); } }, error: function (msg) { setCurOperationInfo(false, "目前請求發生錯誤"); utility.delayInvoke(null, submitForm, 3000); } }); } function reloadToken(submit) { setCurOperationInfo(true, "正在重新整理TOKEN...."); utility.post("/otsweb/order/confirmPassengerAction.do?method=init", null, "text", function (text) { if (!/TOKEN"\s*value="([a-f\d]+)"/i.test(text)) { setCurOperationInfo(false, "無法獲得TOKEN,正在重試"); utility.delayInvoke("#countEle", reloadToken, 1000); } else { var token = RegExp.$1; setCurOperationInfo(false, "已獲得TOKEN - " + token); console.log("已重新整理TOKEN=" + token); $("input[name=org.apache.struts.taglib.html.TOKEN]").val(token); } }, function () { utility.delayInvoke("#countEle", reloadToken, 1000); }); } function waitingForQueueComplete() { setCurOperationInfo(true, "訂單送出成功, 正在等待隊列完成操作...."); $.ajax({ url: '/otsweb/order/myOrderAction.do?method=getOrderWaitTime&tourFlag=' + tourFlag + '&' + Math.random(), data: {}, type: 'GET', timeout: 10000, dataType: 'json', success: function (json) { console.log(json); if (json.waitTime == -1 || json.waitTime == 0) { utility.notifyOnTop("訂票成功!"); if (json.orderId) window.location.replace("/otsweb/order/confirmPassengerAction.do?method=payOrder&orderSequence_no=" + json.orderId); else window.location.replace('/otsweb/order/myOrderAction.do?method=queryMyOrderNotComplete&leftmenu=Y'); } else if (json.waitTime == -3) { var msg = "很抱歉, 鐵道部無齒地撤銷了您的訂單, 趕緊重新下!"; utility.notify(msg); setCurOperationInfo(false, msg); stop(msg); reloadCode(); } else if (json.waitTime == -2) { var msg = "很抱歉, 鐵道部說您占座失敗 : " + json.msg + ', 趕緊重新來過!'; reloadToken(); utility.notify(msg); setCurOperationInfo(false, msg); stop(msg); reloadCode(); } else if (json.waitTime < 0) { var msg = '很抱歉, 未知的狀态資訊 : waitTime=' + json.waitTime + ', 可能已成功,請驗證未支付訂單.'; setTipMessage(msg); utility.notifyOnTop(msg); location.href = '/otsweb/order/myOrderAction.do?method=queryMyOrderNotComplete&leftmenu=Y'; } else { var msg = "訂單需要 " + utility.getSecondInfo(json.waitTime) + " 處理完成, 請等待,不過你知道的,鐵道部說的一直不怎麼準。(排隊人數=" + (json.waitCount || "未知") + ")"; if (json.waitTime > 1800) { msg += "<span style='color:red; font-weight: bold;'>警告:排隊時間大于30分鐘,請不要放棄電話訂票或用小号重新排隊等其它方式繼續訂票!</span>"; } setTipMessage(msg); if (json.waitTime > 1800 && !waitTimeTooLong_alert) { waitTimeTooLong_alert = true; utility.notifyOnTop("警告!排隊時間大于30分鐘,成功率較低,請盡快電話訂票或用小号重新排隊!"); } utility.delayInvoke("#countEle", waitingForQueueComplete, 1000); } }, error: function (json) { utility.notifyOnTop("請求發生異常,可能是登入狀态不對,請驗證。如果沒有問題,請手動進入未完成訂單頁面查詢。"); self.location.reload(); } }); } $("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>"); $("#btnAutoSubmit").click(function () { count = 0; breakFlag = 0; submitFlag = true; submitForm(); }); $("#btnCancelAuto").click(function () { $(this).hide(); breakFlag = 1; submitFlag = false; }); randEl.keyup(function (e) { if (!submitFlag && !document.getElementById("autoStartCommit").checked) return; if (e.charCode == 13 || randEl.val().length == 4) submitForm(); }); //清除上次儲存的預定資訊 var lastform = null; if (parent) { lastform = parent.$("#orderForm"); lastform.attr("success", "1"); } //進度提示框 $("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'>" + "<li class='fish_clock' id='countEle' style='font-weight:bold;'>等待操作</li>" + "<li style='color:green;'><strong>操作資訊</strong>:<span>休息中</span></li>" + "<li style='color:green;'><strong>最後操作時間</strong>:<span>--</span></li></ul></td></tr>"); var tip = $("#tipScript li"); var errorCount = 0; //以下是函數 function setCurOperationInfo(running, msg) { var ele = $("#countEle"); ele.removeClass().addClass(running ? "fish_running" : "fish_clock").html(msg || (running ? "正在操作中……" : "等待中……")); } function setTipMessage(msg) { tip.eq(2).find("span").html(utility.getTimeInfo()); tip.eq(1).find("span").html(msg); } //送出頻率差别 $(".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>"); document.getElementById("autoStartCommit").checked = typeof (window.localStorage["disableAutoStartCommit"]) == 'undefined'; document.getElementById("showHelp").checked = typeof (window.localStorage["showHelp"]) != 'undefined'; $("#autoStartCommit").change(function () { if (this.checked) window.localStorage.removeItem("disableAutoStartCommit"); else window.localStorage.setItem("disableAutoStartCommit", "1"); }); $("#showHelp").change(function () { if (this.checked) { window.localStorage.setItem("showHelp", "1"); $("table.table_qr tr:last").show(); } else { window.localStorage.removeItem("showHelp"); $("table.table_qr tr:last").hide(); } }).change(); //#region 自動重新整理席位預定請求數 var stopCheckCount = null; (function () { 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() }; var url = "confirmPassengerAction.do?method=getQueueCount"; var allSeats = $("#passenger_1_seat option"); var queue = []; var checkCountStopped = false; function beginCheck() { if (checkCountStopped) return; var html = []; html.push("目前實時排隊狀态(每隔2秒輪詢):"); allSeats.each(function () { queue.push({ id: this.value, name: this.text }); html.push("席位【<span style='color:blue; font-weight: bold;'>" + this.text + "</span>】狀态:<span id='queueStatus_" + this.value + "'>等待查詢中....</span>"); }); $("#orderCountCell").html(html.join("<br />")); if (queue.length > 0) executeQueue(); } function checkTicketAvailable() { var queryLeftData = { 'orderRequest.train_date': $('#start_date').val(), 'orderRequest.from_station_telecode': $('#from_station_telecode').val(), 'orderRequest.to_station_telecode': $('#to_station_telecode').val(), 'orderRequest.train_no': $('#train_no').val(), 'trainPassType': 'QB', 'trainClass': 'QB#D#Z#T#K#QT#', 'includeStudent': 00, 'seatTypeAndNum': '', 'orderRequest.start_time_str': '00:00--24:00' }; utility.get("/otsweb/order/querySingleAction.do?method=queryLeftTicket", queryLeftData, "text", function (text) { window.ticketAvailable = ''; if (/(([\da-zA-Z]\*{5,5}\d{4,4})+)/gi.test(text)) { window.ticketAvailable = RegExp.$1; } }, function () { }); } function executeQueue() { if (checkCountStopped) return; var type = queue.shift(); queue.push(type); data.seat = type.id; var strLeftTicket = ''; checkTicketAvailable(); if (window.ticketAvailable) { strLeftTicket = window.ticketAvailable; } utility.get(url, data, "json", function (data) { var msg = "餘票:<strong>" + getTicketCountDesc(strLeftTicket, type.id) + "</strong>"; msg += ",目前排隊【<span style='color:blue; font-weight: bold;'>" + data.count + "</span>】,"; if (data.op_2) { msg += "<span style='color:blue; font-weight: red;'>排隊人數已經超過餘票數,可能無法送出</span>。"; } else { if (data.countT > 0) { msg += "排隊人數已超過系統參數,<span style='color:red; font-weight: bold;'>排隊有危險</span>"; //} else if (data.op_1) { // msg += "排隊人數已超過系統參數,<span style='color:red; font-weight: bold;'>排隊有危險</span>"; } else { msg += "請盡快送出"; } } msg += " (" + utility.getTimeInfo() + ")"; $("#queueStatus_" + type.id).html(msg); setTimeout(executeQueue, 2000); }, function () { setTimeout(executeQueue, 3000); }); } stopCheckCount = function () { checkCountStopped = true; } beginCheck(); })(); //#endregion //#region 自動選擇聯系人、自動選擇上次選擇的人 function autoSelectPassenger() { var pp = localStorage.getItem("preSelectPassenger") || ""; var pseat = (localStorage.getItem("autoSelect_preSelectSeatType") || "").split('|')[0]; if (pp) { pp = pp.split("|"); $.each(pp, function () { if (!this) return true; console.log("[INFO][自動選擇乘客] 自動標明-" + this); $("#" + this + "._checkbox_class").attr("checked", true).click().attr("checked", true); //為啥設定兩次?我也不知道,反正一次不對。 return true; }); if (pseat) { $(".passenger_class").each(function () { $(this).find("select:eq(0)").val(pseat).change(); }); } } }; $(window).ajaxComplete(function (e, xhr, s) { if (s.url.indexOf("getpassengerJson") != -1) { console.log("[INFO][自動選擇乘客] 系統聯系人加載完成,正在檢測預先標明"); autoSelectPassenger(); } }); //如果已經加載完成,那麼直接標明 if ($("#showPassengerFilter div").length) { console.log("[INFO][自動選擇乘客] OOPS,居然加載完成了?直接標明聯系人"); autoSelectPassenger(); } //#endregion //#region 自動定位到随機碼中 (function () { var obj = document.getElementById("rand"); var oldOnload = window. window.onload = function () { if (oldOnload) oldOnload(); obj.select(); }; obj.select(); })(); //#endregion //#region 顯示内部的選擇上下鋪 (function () { //添加上下鋪顯示 $("tr.passenger_class").each(function () { var tr = $(this); var id = tr.attr("id"); 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>"); }); var seatSelector = $("select[name$=_seat]"); seatSelector.change(function () { var self = $(this); var val = self.val(); var l = self.next(); if (val == "2" || val == "3" || val == "4" || val == "6") { l.show(); } else l.hide(); var preseat = utility.getPref("preselectseatlevel"); if (preseat) { l.val(preseat).change(); } }).change(); })(); //#endregion parent.$("#main").css("height", ($(document).height() + 300) + "px"); parent.window.setHeight(parent.window); } function autoCommitOrderInSandbox() { //自動提示? if (window.localStorage["bookTip"]) { window.localStorage.removeItem("bookTip"); if (window.Audio) { new window.Audio(utility.getAudioUrl()).play(); } utility.notify("已經自動進入訂票頁面!請繼續完成訂單!"); } } //#endregion //#region -----------------自動重新整理---------------------- function initTicketQuery() { //啟用日志 utility.enableLog(); var initialized = false; var seatLevelOrder = null; var orderButtonClass = ".btn130_2"; //預定按鈕的選擇器 //#region 參數配置和正常工具界面 var queryCount = 0; var timer = null; var isTicketAvailable = false; var audio = null; //通知聲音 var timerCountDown = 0; var timeCount = 0; var autoBook = false; //初始化表單 var form = $("form[name=querySingleForm] .cx_from:first"); 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) " + "<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='快速勾選所有的席别' />" + "<input type='button' id='enableNotify' onclick='window.webkitNotifications.requestPermission();' value='點選啟用桌面通知' style='line-height:25px;padding:5px;' /> <span id='refreshinfo'>已重新整理 0 次,最後查詢:--</span> <span id='refreshtimer'></span></td></tr>" + "<tr class='append_row'><td colspan='9'><label title='設定有票時放的歌是不是放到天荒地老至死不渝'><input type='checkbox' checked='checked' id='chkAudioLoop'>聲音循環</label>" + "<span style='font-weight:bold;margin-left:10px;color:blue;' title='點選預定按鈕時,有時候等待一會兒系統會提示伺服器忙;勾選此選項後,如果出現這種情況,助手将會進行自動重新預定'><label><input type='checkbox' id='chkAutoResumitOrder' checked='checked' />預定失敗時自動重試</label></span>" + "<span style='font-weight:bold;margin-left:10px;color:blue;' title='有時候系統忙,查詢會提示查詢失敗;勾選此選項後,如果出現這種情況,助手将會進行自動重新整理查詢'><label><input type='checkbox' id='chkAutoRequery' checked='checked' />查詢失敗時自動重試</label></span>" + "<span style='font-weight:bold;margin-left:10px;color:pruple;' title='以伺服器時間為準,未獲得伺服器時間之前,此選項不可用。啟用智能加速模式時,在非正點附近時(大于0小于59分)按照正常速度重新整理;當在正點附近時(大于等于59分時),暫停重新整理并等到正點即刻重新整理。'><label><input disabled='disabled' type='checkbox' id='chkSmartSpeed' />智能正點重新整理模式</label></span>" + "</td></tr>" + "<tr class='append_row'><td id='filterFunctionRow' colspan='9'>" + "<span style='font-weight:bold;color:red;'><label title='不可以預定的車次過濾掉的選項(隐藏起來不顯示,無票的車次)'><input type='checkbox' id='chkFilterNonBookable' />過濾不可預訂的車次</label></span>" + "<span style='font-weight:bold;margin-left:10px;color:red;'><label title='有時候雖然整趟車可以預定,但是有票的席别都是你不要的,如果勾選此選項,也将會過濾掉'><input type='checkbox' id='chkFilterNonNeeded' />過濾不需要的席别</label></span>" + "<span style='font-weight:bold;margin-left:10px;color:blue;display: none;'><label><input disabled='disabled' type='checkbox' id='chkFilterByTrain' />開啟按車次過濾</label></span>" + "</td></tr>" + "<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>" ); if (!window.Audio) { $("#chkAudioOn, #chkAudioLoop, #btnStopSound").remove(); } else { $("#btnStopSound").click(function () { if (audio) { audio.pause(); } this.disabled = true; }); } $("#resetSettings").click(function () { if (confirm("确定要清空助手的所有設定嗎?")) { window.localStorage.clear(); self.location.reload(); return false; } }); //操作控制 $("#btnStopRefresh").click(function () { resetTimer(); }); $("#chkSmartSpeed").change(function () { }); //#endregion //#region 顯示座級選擇UI var ticketType = new Array(); var seatOptionTypeMap = { "3": "9", "4": "P", "5": "M", "6": "O", "7": "6", "8": "4", "9": "3", "10": "2", "11": "1", "12": "empty", "13": "QT" }; $(".hdr tr:eq(2) td").each(function (i, e) { ticketType.push(false); if (i < 3) return; var obj = $(this); ticketType[i] = (window.localStorage["typefilter_" + i] || "true") == "true"; //修改文字,避免換行 obj.attr("otext", obj.text()); var cap = $.trim(obj.text()); if (cap.length > 2) { cap = cap.replace("座", "").replace("進階軟卧", "高軟"); obj.html(cap); } //加入複選框 var c = $("<input id='seatoption_" + seatOptionTypeMap[i] + "' type='checkbox' typecode='" + seatOptionTypeMap[i] + "' name='seatoption'/>").attr("checked", ticketType[i]); c[0].ticketTypeId = i; c.change( function () { ticketType[this.ticketTypeId] = this.checked; window.localStorage["typefilter_" + this.ticketTypeId] = this.checked; }).appendTo(obj); }); //座級選擇 $("#chkSeatOnly").click(function () { $(".hdr tr:eq(2) td").each(function (i, e) { var obj = $(this); var txt = obj.attr("otext"); obj.find("input").attr("checked", typeof (txt) != 'undefined' && txt && txt.indexOf("座") != -1).change(); }); }); $("#chkSleepOnly").click(function () { $(".hdr tr:eq(2) td").each(function (i, e) { var obj = $(this); var txt = obj.attr("otext"); obj.find("input").attr("checked", typeof (txt) != 'undefined' && txt && txt.indexOf("卧") != -1).change(); }); }); $("#chkAllSeat").click(function () { $(":checkbox[name=seatoption]").attr("checked", true).change(); }); //#endregion //#region 顯示額外的功能區 var extrahtml = []; 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>\ <table id='helpertooltable' style='width:100%;'><colgroup><col style='width:110px;' /><col style='width:370px;' /><col style='width:110px;' /><col style='width:auto;' /></colgroup>\ <tr class='fish_sep musicFunc' id='helperbox_bottom'><td class='name'>自定義音樂位址</td><td colspan='3'><input type='text' id='txtMusicUrl' value='" + utility.getAudioUrl() + "' onfocus='this.select();' style='width:50%;' /> <input type='button' Audio(document.getElementById(\"txtMusicUrl\").value).play();' value='測試'/><input type='button' onclick='utility.resetAudioUrl(); document.getElementById(\"txtMusicUrl\").value=utility.getAudioUrl();' value='恢複預設'/> (位址第一次使用可能會需要等待一會兒)</td></tr>\ <tr class='fish_sep musicFunc'><td class='name'>可用音樂位址</td><td colspan='3'>"); var host1 = "http://resbak.fishlee.net/res/"; //var host2 = "https://github.com/iccfish/12306_ticket_helper/raw/master/res/"; var musics = [["music1.ogg", "超級瑪麗"], ["music2.ogg", "藍精靈"]]; $.each(musics, function () { extrahtml.push("<a href='javascript:;' url='" + host1 + this[0] + "' class='murl'>" + this[1] + "</a> "); //extrahtml.push("<a href='javascript:;' url='" + host2 + this[0] + "' class='murl'>" + this[1] + "</a>(HTTPS) "); }); extrahtml.push("</td></tr><tr class='fish_sep'><td colspan='4'><input type='button' value='添加自定義車票時間段' id='btnDefineTimeRange' />\ <input type='button' value='清除自定義車票時間段' id='btnClearDefineTimeRange' /></td></tr>\ <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>\ </table></div></div>"); $("body").append(extrahtml.join("")); $("a.murl").live("click", function () { $("#txtMusicUrl").val(this.getAttribute("url")).change(); }); $("#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>"); $("#txtMusicUrl").change(function () { window.localStorage["audioUrl"] = this.value; }); $("form[name=querySingleForm]").attr("id", "querySingleForm"); //#endregion //#region 添加自定義時間段 function addCustomTimeRange() { var s = parseInt(prompt("請輸入自定義時間段的起始時間(請填入小時,0-23)", "0")); if (isNaN(s) || s < 0 || s > 23) { alert("起始時間不正确 >_<"); return; } var e = parseInt(prompt("請輸入自定義時間段的結束時間(請填入小時,1-24)", "24")); if (isNaN(e) || e < 0 || e > 24) { alert("結束時間不正确 >_<"); return; } var range = (s > 9 ? "" : "0") + s + ":00--" + (e > 9 ? "" : "0") + e + ":00"; if (confirm("您想要記住這個時間段嗎?")) { window.localStorage["customTimeRange"] = (window.localStorage["customTimeRange"] ? window.localStorage["customTimeRange"] + "|" : "") + range; }; addCustomeTimeRangeToList(range); } function addCustomeTimeRangeToList(g) { var obj = document.getElementById("startTime"); obj.options[obj.options.length] = new Option(g, g); obj.selectedIndex = obj.options.length - 1; } if (window.localStorage["customTimeRange"]) { var ctrs = window.localStorage["customTimeRange"].split("|"); $.each(ctrs, function () { addCustomeTimeRangeToList(this); }); } $("#btnClearDefineTimeRange").click(function () { if (!confirm("确定要清除自定義的時間段嗎?清除後請重新整理頁面。")) return; window.localStorage.removeItem("customTimeRange"); }); $("#btnDefineTimeRange").click(addCustomTimeRange); //#endregion //#region 過濾車次 var stopHover = window.onStopHover; window.onStopHover = function (info) { $("#stopDiv").attr("info", $.trim($("#id_" + info.split('#')[0]).text())); stopHover.call(this, info); $("#onStopHover").css("overflow", "hide"); }; $("#btnFilter").click(function () { //加入黑名單 var trainNo = $("#stopDiv").attr("info").split('#')[0]; if (!trainNo || !confirm("确定要将車次【" + trainNo + "】加入黑名單?以後的查詢将不再顯示此車次。")) return; list_blacklist.add(trainNo); }); $("#btnAutoBook").click(function () { //加入自動預定清單 var trainNo = $("#stopDiv").attr("info").split('#')[0]; if (isTrainInBlackList(trainNo)) { alert("指定的車次在黑名單裡呢……"); return; } if (!trainNo || !confirm("确定要将車次【" + trainNo + "】加入自動預定清單?如果下次查詢有符合要求的席别将會自動進入預定頁面。")) return; list_autoorder.add(trainNo); }); //清除進入指定頁面後提示的标記位 if (window.localStorage["bookTip"]) window.localStorage.removeItem("bookTip"); //#endregion //#region 自動重新查詢 var clickButton = null;//點選的查詢按鈕 var filterNonBookable = $("#chkFilterNonBookable")[0]; //過濾不可定車次 var filterNonNeeded = $("#chkFilterNonNeeded")[0]; //過濾不需要車次 var onRequery = function () { }; //當重新查詢時觸發 var onNoTicket = function () { }; //當沒有查到票時觸發 $("#autoRequery").change(function () { if (!this.checked) resetTimer(); }); //重新整理時間間隔 $("#refereshInterval").change(function () { timeCount = Math.max(5, parseInt($("#refereshInterval").val())); }).change(); //定時查詢 var isSmartOn = false; function resetTimer() { queryCount = 0; $("#btnStopRefresh")[0].disabled = true; if (timer) { clearInterval(timer); timer = null; } $("#refreshtimer").html(""); } function countDownTimer() { timerCountDown -= 0.2; var str = (Math.round(timerCountDown * 10) / 10) + ""; $("#refreshtimer").html("[" + (isSmartOn ? "等待正點," : "") + str + (str.indexOf('.') == -1 ? ".0" : "") + "秒後查詢...]"); if (timerCountDown > 0) return; clearInterval(timer); timer = null; onRequery(); doQuery(); } function startTimer() { if (timer) return; var d = new Date().getMinutes(); isSmartOn = document.getElementById("chkSmartSpeed").checked && time_server && time_server.getMinutes() >= 59; timerCountDown = isSmartOn ? 60 - time_server.getSeconds() + 2 : timeCount; var str = (Math.round(timerCountDown * 10) / 10) + ""; $("#refreshtimer").html("[" + (isSmartOn ? "等待正點," : "") + timerCountDown + (str.indexOf('.') == -1 ? ".0" : "") + "秒後查詢...]"); //沒有定時器的時候,開啟定時器準備重新整理 $("#btnStopRefresh")[0].disabled = false; timer = setInterval(countDownTimer, 200); } function displayQueryInfo() { queryCount++; $("#refreshinfo").html("已重新整理 " + queryCount + " 次,最後查詢:" + utility.getTimeInfo()); $("#refreshtimer").html("正在查詢"); } function doQuery() { timer = null; if (audio) audio.pause(); displayQueryInfo(); sendQueryFunc.call(clickBuyStudentTicket == "Y" ? document.getElementById("stu_submitQuery") : document.getElementById("submitQuery")); } //驗證車票有開始 var onticketAvailable = function () { resetTimer(); $("#refreshinfo").html("已經有票鳥!"); utility.notifyOnTop("可以訂票了!"); if (window.Audio && $("#chkAudioOn")[0].checked) { if (!audio) { audio = new Audio($("#txtMusicUrl").val()); } audio.loop = $("#chkAudioLoop")[0].checked; $("#btnStopSound")[0].disabled = false; audio.play(); } } //檢查是否可以訂票 var checkTicketsQueue = []; var checkTicketCellsQueue = []; function getTrainNo(row) { /// <summary>獲得行的車次号</summary> return $.trim($("td:eq(0)", row).text()); } //預設的單元格檢測函數 checkTicketCellsQueue.push(function (i, e) { if (!ticketType[i - 1]) return 0; var el = $(e); var info = $.trim(el.text()); //Firefox不支援 innerText if (info == "*" || info == "--" || info == "無") { return 0; } return 2; }); //預設的行檢測函數 checkTicketsQueue.push(function () { var trainNo = getTrainNo(this); var tr = this; this.attr("tcode", trainNo); //黑名單過濾 if (isTrainInBlackList(trainNo)) { this.hide(); return 0; } var hasTicket = 1; if ($("a.btn130", this).length > 0) return 0; $("td", this).each(function (i, e) { var cellResult = 0; e = $(e); var opt = { code: trainNo, tr: tr, index: e.index(), seatType: seatOptionTypeMap[e.index() - 1] }; e.attr("scode", opt.seatType); $.each(checkTicketCellsQueue, function () { cellResult = this(i, e, cellResult, opt) || cellResult; return cellResult != 0; }); e.attr("result", cellResult); if (cellResult == 2) { hasTicket = 2; e.css("background-color", "#95AFFD"); } }); tr.attr("result", hasTicket); return hasTicket; }); //檢測是否有餘票的函數 var checkTickets = function () { var result = 0; var row = this; $.each(checkTicketsQueue, function () { result = this.call(row, result); return true; }); return result; } //目标表格,當ajax完成時檢測是否有票 $("body").ajaxComplete(function (e, r, s) { //HACK-阻止重複調用 if (timer != null) return; if (s.url.indexOf("queryLeftTicket") == -1) return; //驗證有票 var rows = $("table.obj tr:gt(0)"); var ticketValid = false; var validRows = {}; rows.each(function () { var row = $(this); var valid = checkTickets.call(row); var code = getTrainNo(row); row.attr("tcode", code); row.find("td:eq(0)").click(putTrainCodeToList); console.log("[INFO][車票可用性校驗] " + code + " 校驗結果=" + valid); if (valid == 2) { row.css("background-color", "#FD855C"); validRows[code] = row; } else { if (valid == 1 && filterNonNeeded.checked) row.hide(); if (valid == 0 && filterNonBookable.checked) row.hide(); } ticketValid = ticketValid || valid == 2; }); //自動預定 if ($("#swAutoBook:checked").length > 0) { if (!seatLevelOrder || !seatLevelOrder.length) { //沒有席别優先級,那選第一個 for (var idx in list_autoorder.datalist) { var code = list_autoorder.datalist[idx]; var reg = utility.getRegCache(code); var row = $.first(validRows, function (i, v) { if (reg.test(i)) return v; }); if (row) { if (document.getElementById("autoBookTip").checked) { window.localStorage["bookTip"] = 1; } row.find("a[name=btn130_2]").click(); return false; } }; } else { console.log("按席别優先選擇-車次過濾"); var trains = $.makeArray($("#gridbox tr[result=2]")); var trainfiltered = []; for (var idx in list_autoorder.datalist) { //對車次進行過濾并按優先級排序 var rule = list_autoorder.datalist[idx]; var ruleTester = utility.getRegCache(rule); for (var i = trains.length - 1; i >= 0; i--) { var self = $(trains[i]); var code = self.attr("tcode"); if (ruleTester.test(code)) { trainfiltered.push(self); trains.splice(i, 1); } } } if (document.getElementById("autoorder_method").selectedIndex == 0) { $.each(seatLevelOrder, function () { var scode = this; for (var i in trainfiltered) { var t = trainfiltered[i]; if (t.find("td[scode=" + this + "][result=2]").length) { var tcode = scode == "empty" ? "1" : scode; window.localStorage.setItem("autoSelect_preSelectSeatType", tcode); $("#preSelectSeat").val(tcode) if (document.getElementById("autoBookTip").checked) { window.localStorage["bookTip"] = 1; } t.find(orderButtonClass).click(); return false; } } return true; }); } else { //車次優先 $.each(trainfiltered, function () { var t = this; for (var i in seatLevelOrder) { var scode = seatLevelOrder[i]; if (t.find("td[scode=" + scode + "][result=2]").length) { var tcode = scode == "empty" ? "1" : scode; window.localStorage.setItem("autoSelect_preSelectSeatType", tcode); $("#preSelectSeat").val(tcode) if (document.getElementById("autoBookTip").checked) { window.localStorage["bookTip"] = 1; } t.find(orderButtonClass).click(); return false; } } return true; }); } } } if (ticketValid) { onticketAvailable(); } else if (document.getElementById("autoRequery").checked) { onNoTicket(); startTimer(); } }); //系統繁忙時自動重複查詢 chkAutoResumitOrder $("#orderForm").submit(function () { if ($("#chkAutoResumitOrder")[0].checked) { parent.$("#orderForm").remove(); parent.$("body").append($("#orderForm").clone(false).attr("target", "main").attr("success", "0")); } }); $("body").ajaxComplete(function (e, r, s) { if (!$("#chkAutoRequery")[0].checked) return; if (s.url.indexOf("/otsweb/order/querySingleAction.do") != -1 && r.responseText == "-1") { //invalidQueryButton(); //delayButton(); //startTimer(); } else { $("#serverMsg").html(""); } }); $("body").ajaxError(function (e, r, s) { if (s.url.indexOf("queryLeftTicket") == -1) return; if (!$("#chkAutoRequery")[0].checked) return; if (s.url.indexOf("/otsweb/order/querySingleAction.do") != -1) { delayButton(); startTimer(); } }); //Hack掉原來的系統函數。丫居然把所有的click事件全部處理了,鄙視 window.invalidQueryButton = function () { var queryButton = $("#submitQuery"); queryButton.unbind("click", sendQueryFunc); if (queryButton.attr("class") == "research_u") { renameButton("research_x"); } else if (queryButton.attr("class") == "search_u") { renameButton("search_x"); } } //#endregion //#region 配置加載、儲存、權限檢測 //通知權限 if (!window.webkitNotifications || window.webkitNotifications.checkPermission() == 0) { $("#enableNotify").remove(); } //儲存資訊 function saveStateInfo() { if (!$("#keepinfo")[0].checked || $("#fromStationText")[0].disabled) return; utility.setPref("_from_station_text", $("#fromStationText").val()); utility.setPref("_from_station_telecode", $("#fromStation").val()); utility.setPref("_to_station_text", $("#toStationText").val()); utility.setPref("_to_station_telecode", $("#toStation").val()); utility.setPref("_depart_date", $("#startdatepicker").val()); utility.setPref("_depart_time", $("#startTime").val()); } $("#submitQuery, #stu_submitQuery").click(saveStateInfo); //回填資訊 if (!$("#fromStationText")[0].disabled) { var FROM_STATION_TEXT = utility.getPref('_from_station_text'); // 出發站名稱 var FROM_STATION_TELECODE = utility.getPref('_from_station_telecode'); // 出發站電報碼 var TO_STATION_TEXT = utility.getPref('_to_station_text'); // 到達站名稱 var TO_STATION_TELECODE = utility.getPref('_to_station_telecode'); // 到達站電報碼 var DEPART_DATE = utility.getPref('_depart_date'); // 出發日期 var DEPART_TIME = utility.getPref('_depart_time'); // 出發時間 if (FROM_STATION_TEXT) { $("#fromStationText").val(FROM_STATION_TEXT); $("#fromStation").val(FROM_STATION_TELECODE); $("#toStationText").val(TO_STATION_TEXT); $("#toStation").val(TO_STATION_TELECODE); $("#startdatepicker").val(DEPART_DATE); $("#startTime").val(DEPART_TIME); } } //音樂 if (!window.Audio) { $(".musicFunc").hide(); } //#endregion //#region 時間快捷修改 (function () { var datebox = $("table.cx_from tr:eq(0) td:eq(5), table.cx_from tr:eq(1) td:eq(3)"); datebox.width("170px"); datebox.find("input").width("70px").before('<input type="button" class="date_prev lineButton" value="<">').after('<input type="button" class="date_next lineButton" value=">">'); 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(); }); 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(); }); })(); //#endregion //#region 自動輪詢,自動更改時間 (function () { //初始化UI var html = "<tr class='fish_sep' id='autoChangeDateRow'><td class='name'>查詢日期</td><td>\ <label><input type='checkbox' id='autoCorrentDate' checked='checked' /> 查詢日期早于或等于今天時,自動修改為明天</label>\ </td><td class='name'>自動輪查</td><td><label><input type='checkbox' id='autoChangeDate' /> 無票時自動更改日期輪查</label>\ </td></tr><tr class='fish_sep' style='display:none;'><td class='name'>輪查日期設定</td><td colspan='3' id='autoChangeDateList'></td></tr>\ "; $("#helperbox_bottom").before(html); var autoChangeDateList = $("#autoChangeDateList"); var html = []; var now = new Date(); for (var i = 0; i < 20; i++) { now = utility.addTimeSpan(now, 0, 0, 1, 0, 0, 0); html.push("<label style='margin-right:16px;'><input type='checkbox' value='" + utility.formatDate(now) + "' cindex='" + i + "' />" + utility.formatDateShort(now) + "</label>"); if ((i + 1) % 10 == 0) html.push("<br />"); } autoChangeDateList.html(html.join("")); $("#autoChangeDate").change(function () { var tr = $(this).closest("tr").next(); if (this.checked) tr.show(); else tr.hide(); }); //配置 utility.reloadPrefs($("#autoChangeDateRow"), "autoChangeDateRow"); //日期點選 var stKey = "autoChangeDateRow_dates"; var stValue = window.localStorage.getItem(stKey); if (typeof (stValue) != 'undefined' && stValue) { var array = stValue.split('|'); autoChangeDateList.find(":checkbox").each(function () { this.checked = $.inArray(this.value, array) != -1; }); } autoChangeDateList.find(":checkbox").change(function () { var value = $.map(autoChangeDateList.find(":checkbox:checked"), function (e, i) { return e.value; }).join("|") window.localStorage.setItem(stKey, value); }); })(); (function () { //如果目前查詢日期在目前日期或之前,那麼自動修改日期 $("#startdatepicker, #roundTrainDate").change(function () { if (!document.getElementById("autoCorrentDate").checked) return; var obj = $(this); var val = utility.parseDate(obj.val()); var tomorrow = utility.addTimeSpan(utility.getDate(new Date()), 0, 0, 1, 0, 0, 0); if (!val || isNaN(val.getFullYear()) || tomorrow > val) { console.log("自動修改日期為 " + utility.formatDate(tomorrow)); obj.val(utility.formatDate(tomorrow)); } }).change(); })(); onNoTicket = (function (callback) { return function () { //Hook onNoTicket callback(); if (!document.getElementById("autoChangeDate").checked) return; console.log("自動輪詢日期中。"); var index = parseInt($("#autoChangeDate").attr("cindex")); if (isNaN(index)) index = -1; var current = index == -1 ? [] : $("#autoChangeDateList :checkbox:eq(" + index + ")").parent().nextAll(":has(:checked):eq(0)").find("input"); if (current.length == 0) { index = 0; current = $("#autoChangeDateList :checkbox:checked:first"); if (current.length == 0) return; //沒有選擇任何 } index = current.attr("cindex"); if (current.length > 0) { $("#autoChangeDate").attr("cindex", index); $("#startdatepicker").val(current.val()); //高亮 $("#cx_titleleft span").css({ color: 'red', 'font-weight': 'bold' }); } }; } )(onNoTicket); //#endregion //#region 攔截彈出的提示框,比如伺服器忙 (function () { var _bakAlert = window.alert; window.alert = function (msg) { if (msg.indexOf("伺服器忙") != -1) { $("#serverMsg").text(msg); } else _bakAlert(msg); } })(); //#endregion //#region 預設加入攔截Ajax緩存 (function () { $.ajaxSetup({ cache: false }); })(); //#endregion //#region 顯示所有的乘客 var list_autoorder = null; var list_blacklist = null; var list_whitelist = null; function isTrainInBlackList(trainNo) { /// <summary>傳回指定的車次是否在黑名單中</summary> return document.getElementById("swBlackList").checked && (list_blacklist.isInRegList(trainNo)) && !(document.getElementById("swWhiteList").checked && list_whitelist.isInRegList(trainNo)); } function putTrainCodeToList() { var code = $(this).closest("tr").attr("tcode"); if (confirm("是否要将【" + code + "】加入自動預定清單?如果不是,請點選取消并繼續選擇是否加入黑名單或白名單。")) { list_autoorder.add(code); } else if (confirm("是否要将【" + code + "】加入黑名單?如果不是,請點選取消并繼續選擇是否加入白名單。")) { list_blacklist.add(code); } else if (confirm("是否要将【" + code + "】加入白名單?")) { list_whitelist.add(code); }; } (function () { var html = "\ <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>\ <tr class='fish_sep'><td colspan='4' id='whiteListTd'></td></tr>\ <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>\ <tr class='fish_sep'><td colspan='4' id='blackListTd'></td></tr>\ <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' onclick=\"self.location='/otsweb/passengerAction.do?method=initAddPassenger&';\" value='添加聯系人' /> (提示:新加的聯系人五分鐘之内無法訂票)</td></tr>\ <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>\ <tr class='fish_sep'><td class='name'>已選擇</td><td id='passengerList1' colspan='3'></td></tr>\ <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>\ <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>\ <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>\ <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>\ <tr class='fish_sep'><td colspan='4' id='autobookListTd'></td></tr>\ <tr class='fish_sep'><td colspan='4'><label><input type='checkbox' id='autoBookTip' checked='checked' /> 如果自動預定成功,進入預定頁面後播放提示音樂并彈窗提示</label></td></tr>\ <tr class='fish_sep autoordertip' style='display:none;'><td class='name'>自動復原</td><td><label><input type='checkbox' id='autoorder_autocancel' /> 自動送出失敗時,自動取消自動送出并再次預定</label></td></tr>\ <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>\ <tr style='display:none;' class='autoordertip fish_sep'><td class='name' style='color:red;'>警告</td><td colspan='3' style='color:darkblue;'>\ <p style='font-weight:bold; color:purple;'>自動送出訂單使用流程:勾選要訂票的聯系人 -> 設定需要的席别 -> 将你需要訂票的車次按優先級别加入自動預定清單 -> 勾選自動送出訂單 -> 輸入驗證碼 -> 開始查票。資訊填寫不完整将會導緻助手忽略自動送出訂單,請務必注意。進入自動訂票模式後,席别選擇和自動預定都将被鎖定而無法手動切換。如果查詢的是學生票,那麼送出的将會是學生票訂單。<u style='color:red;'>一切都設定完成後,請點選查詢開始查票。一旦有票将會自動送出。</u></p>\ <p>1. 自動送出訂單使用的是自動預定的清單順序,取第一個有效的車次自動送出訂單!請确認設定正确!!</p>\ <p>2. 自動送出的席别和聯系人請在上方選擇,和預設的是一緻的,暫不支援不同的聯系人選擇不同的席别;</p>\ <p>3. 作者無法保證自動送出是否會因為鐵老大的修改失效,是以請務必同時使用<b>其它浏覽器</b>手動送出訂單!否則可能會造成您不必要的損失!</p>\ <p style='font-weight:bold;'>5. 當助手第一次因為功能性自動送出失敗後(非網絡錯誤和驗證碼錯誤,如餘票不足、占座失敗等),将會立刻禁用自動送出并復原到普通送出,并再次送出訂票請求,是以請時刻注意送出結果并及時填寫内容,并強烈建議你另外打開單獨的浏覽器同時手動下訂單!!</p>\ <p style='font-weight:bold;color:darkcylan;'>6. 為可靠起見,建議每隔一段時間重新整理下驗證碼重新填寫(點選驗證碼圖檔重新整理)。由于不同的浏覽器重新整理的結果不一樣,強烈建議多個浏覽器或多台機子一起重新整理!</p>\ <p style='font-size:16px; font-weight:bold;color:blue;'>一定要仔細看說明啊!切記多個浏覽器準備不要老想着一棵樹上吊死啊!千萬不要因為自動送出訂單導緻你訂不到票啊!!這樣老衲會内疚的啊!!!!</p>\ </td></tr>"; $("#helpertooltable tr:first").addClass("fish_sep").before(html); //優選邏輯 $("#autoorder_method").val(window.localStorage["autoorder_method"] || "0").change(function () { window.localStorage.setItem("autoorder_method", $(this).val()); }); $("#autoorder_autocancel").attr("checked", (window.localStorage["autoorder_autocancel"] || "1") == "1").change(function () { window.localStorage.setItem("autoorder_autocancel", this.checked ? "1" : "0"); }); //自動預定清單 list_autoorder = utility.selectionArea.call($("#autobookListTd"), { syncToStorageKey: "list_autoBookList", onAdd: onAutoOrderRowStyle, onRemove: onAutoOrderRowStyle, onClear: onAutoOrderRowStyle }); list_blacklist = utility.selectionArea.call($("#blackListTd"), { syncToStorageKey: "list_blackList" }); list_whitelist = utility.selectionArea.call($("#whiteListTd"), { syncToStorageKey: "list_whiteList" }); var autoBookHeader = $("#swAutoBook").closest("tr"); function onAutoOrderRowStyle() { if (!document.getElementById("autoorder").checked) return; autoBookHeader.removeClass("steps stepsok"); autoBookHeader.addClass(list_autoorder.datalist.length ? "stepsok" : "steps"); } function appendTrainCodeToList(target) { var code = prompt("請輸入您要加入清單的車次。車次可以使用正規表達式(親,不知道的話請直接填寫車次編号喔),比如 【.*】(不包括【】号) 可以代表所有車次,【K.*】可以代表所有K字頭的車次,【D.*】可以代表所有D字頭車次等等"); if (!code) return; //修正部分符号 code = code.replace(/(,|,|\/|\\|、|-)/g, "|"); try { new RegExp(code); } catch (e) { alert("嗯……看起來同學您輸入的不是正确的正規表達式哦。"); return; } target.add(code); } function emptyList(target) { target.emptyList(); } //綁定添加清空事件 $("#btnAddAutoBook").click(function () { appendTrainCodeToList(list_autoorder); }); $("#btnAddWhite").click(function () { appendTrainCodeToList(list_whitelist); }); $("#btnAddBlack").click(function () { appendTrainCodeToList(list_blacklist); }); $("#btnClearAutoBook").click(function () { emptyList(list_autoorder); }); $("#btnClearWhite").click(function () { emptyList(list_whitelist); }); $("#btnClearBlack").click(function () { emptyList(list_blacklist); }); $("#swBlackList, #swAutoBook").each(function () { var obj = $(this); var name = obj.attr("name"); var opt = localStorage.getItem(name); if (opt != null) this.checked = opt == "1"; }).change(function () { var obj = $(this); var name = obj.attr("name"); localStorage.setItem(name, this.checked ? "1" : "0"); }); var seatlist = [ ["", "=請選擇="], ["9", "商務座"], ["P", "特等座"], ["6", "進階軟卧"], ["4", "軟卧"], ["3", "硬卧"], ["2", "軟座"], ["1", "硬座"], ["empty", "硬座(無座)"], ["M", "一等座"], ["O", "二等座"] ]; var level = [[0, '随機'], [3, "上鋪"], [2, '中鋪'], [1, '下鋪']]; var seatDom = document.getElementById("preSelectSeatList"); var seatLevelDom = document.getElementById("preselectseatlevel"); $.each(seatlist, function () { seatDom.options[seatDom.options.length] = new Option(this[1], this[0]); }); $.each(level, function () { seatLevelDom.options[seatLevelDom.options.length] = new Option(this[1], this[0]); }); //重新整理優選清單 var seatLevelRow = $("#seatLevelRow"); function refreshSeatTypeOrder() { var list = $("#preseatlist input"); if (initialized) $(":checkbox[name=seatoption]").attr("checked", false).change(); seatLevelOrder = []; list.each(function () { var code = $(this).attr("code"); seatLevelOrder.push(code); if (initialized) $("#seatoption_" + code).attr("checked", true).change(); }); if (!list.length) { $("#preseatlist_empty").show(); $(":checkbox[name=seatoption]").attr("checked", true).change(); window.localStorage.setItem("autoSelect_preSelectSeatType", ""); } else { $("#preseatlist_empty").hide(); window.localStorage.setItem("autoSelect_preSelectSeatType", seatLevelOrder[0]); } if (initialized) utility.notifyOnTop("已經根據您選擇的席别自動切換了席别過濾選項,請注意,并作出需要的調整。"); window.localStorage.setItem("preSelectSeatType", seatLevelOrder.join('|')); if (document.getElementById("autoorder").checked) { seatLevelRow.removeClass("stepsok steps"); seatLevelRow.addClass(seatLevelOrder.length ? "stepsok" : "steps"); } } //選中後添加到清單中 $("#preSelectSeatList").change(function () { var index = seatDom.selectedIndex; if (index == 0) return; //添加 var opt = seatDom.options[index]; var html = "<input type='button' title='點選删除' class='seatTypeButton lineButton' value='" + opt.text + "' code='" + opt.value + "' />"; $("#preseatlist").append(html); $("#preseatlist_empty").hide(); //目前選項移除 seatDom.options[index] = null; seatDom.selectedIndex = 0; refreshSeatTypeOrder(); }); //席别的按鈕點選後自動删除 $("input.seatTypeButton").live("click", function () { var btn = $(this); btn.remove(); //加回清單 var code = btn.attr("code"); var name = btn.val(); seatDom.options[seatDom.options.length] = new Option(name, code); //重新整理清單 refreshSeatTypeOrder(); }); (function () { var preseattype = window.localStorage.getItem("preSelectSeatType") || window.localStorage.getItem("autoSelect_preSelectSeatType"); if (!preseattype) return; preseattype = preseattype.split('|'); var el = $(seatDom); $.each(preseattype, function () { el.val(this + ""); el.change(); }); })(); $(seatLevelDom).val(window.localStorage.getItem("preselectseatlevel") || "").change(function () { window.localStorage.setItem("preselectseatlevel", $(this).val()); }); var pre_autoorder_book_status; $("#autoorder").click(function () { if (this.checked) { pre_autoorder_book_status = document.getElementById("swAutoBook").checked; document.getElementById("swAutoBook").checked = true; //alert("警告!選中将會啟用自動下單功能,并取代自動預定功能,請輸入驗證碼,當指定的車次中的指定席别可用時,助手将會為您全自動下單。\n\n請确認您設定了正确的車次和席别!\n\n但是,作者無法保證是否會因為鐵道部的修改導緻失效,請使用此功能的同時務必使用傳統的手動下單以保證不會導緻您的損失!"); } document.getElementById("swAutoBook").disabled = this.checked; if (this.checked) { $(".autoordertip").show(); $(":checkbox[name=seatoption]").attr("disabled", true); refreshSeatTypeOrder(); onAutoOrderRowStyle(); } else { $(".autoordertip").hide(); document.getElementById("swAutoBook").checked = pre_autoorder_book_status; $(":checkbox[name=seatoption]").attr("disabled", false); $("tr.autoorder_steps").removeClass("steps").removeClass("stepsok"); } }); //禁用自動預定 //加載乘客 utility.getAllPassengers(function (list) { var h = []; var check = (localStorage.getItem("preSelectPassenger") || "").split('|'); var index = 0; $.each(list, function () { var value = this.passenger_name + this.passenger_id_type_code + this.passenger_id_no; this.index = index++; 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>"); }); $("#passengerList").html(h.join("")).find("input").change(function () { var self = $(this).closest("label"); if (this.checked) { var selected = $("#passengerList1 :checkbox"); if (selected.length >= 5) { alert("選擇的乘客不能多于五位喔~~"); this.checked = false; return; } $("#passengerList1").append(self); } else { $("#passengerList").append(self); } selected = $("#passengerList1 :checkbox"); var user = $.map(selected, function (e) { return e.value; }); $("#ticketLimition").val(selected.length); localStorage.setItem("preSelectPassenger", user.join("|")); refreshPasRowStyle(user); }); $.each(check, function () { $("#passengerList :checkbox[value=" + this + ']').change(); }); $.each(list, function () { $("#preSelectPassenger" + this.index).data('pasinfo', this); }); $("#ticketLimition").val($("#passengerList1 :checkbox").length); function refreshPasRowStyle(selected) { if (!document.getElementById("autoorder").checked) return; var row = $("#selectPasRow"); row.removeClass("steps stepsok"); row.addClass(selected.length ? "stepsok" : "steps"); } $("#autoorder").click(function () { refreshPasRowStyle($("#passengerList1 :checkbox")); }); }); })(); //#endregion //#region 預定界面加載快速查詢連結 (function () { var html = []; html.push("<tr class='caption fish_sep'><td colspan='4'>快速查詢連結</strong></td></tr>"); html.push("<tr class='fish_sep'><td colspan='4'>"); var urls = [ ["各始發站放票時間查詢", "http://www.12306.cn/mormhweb/zxdt/tlxw_tdbtz53.html"] ]; $.each(urls, function () { html.push("<div style='float:left;'><a href='" + this[1] + "' target='_blank'>" + this[0] + "</a></div>"); }); html.push("</td></tr>"); $("#helpertooltable tr:last").before(html.join("")); })(); //#endregion //#region 餘票數限制 (function () { var html = []; html.push("<tr class='caption'><td colspan='4'>票數限制</strong></td></tr>"); html.push("<tr class='fish_sep'><td><strong>最發票數</strong><td colspan='3'><select id='ticketLimition'></select>"); html.push("介個就是說……如果票票數小于這裡的數字的話……就無視的啦 =。=</td></tr>"); $("#helpertooltable tr:first").addClass("fish_sep").before(html.join("")); var dom = $("#ticketLimition").val($("#passengerList1 :checkbox").length)[0]; for (var i = 0; i < 6; i++) { dom.options[i] = new Option(i ? i : "(無限制)", i); } //注冊檢測函數 checkTicketCellsQueue.push(function (i, e, prevValue) { var limit = parseInt(dom.value); if (!prevValue || !(limit > 0) || $("#autoorder_part:visible:checked").length) return null; var text = $.trim(e.text()); if (text == "有") return 2; return parseInt(text) >= limit ? 2 : 1; }); })(); //#endregion //#region 儲存查詢車次類型配置 (function () { var ccTypeCheck = $("input:checkbox[name=trainClassArr]"); var preccType = (utility.getPref("cctype") || "").split("|"); if (preccType[0]) { ccTypeCheck.each(function () { this.checked = $.inArray(this.value, preccType) != -1; }); } ccTypeCheck.click(function () { utility.setPref("cctype", $.map(ccTypeCheck.filter(":checked"), function (v, i) { return v.value; }).join("|")); }); })(); //#endregion //#region 增加互換目标的功能 (function () { var fromCode = $("#fromStation"); var from = $("#fromStationText"); var toCode = $("#toStation"); var to = $("#toStationText"); from.css("width", "50px").after("<input type='button' value='<->' class='lineButton' title='交換出發地和目的地' id='btnExchangeStation' />"); $("#btnExchangeStation").click(function () { var f1 = fromCode.val(); var f2 = from.val(); fromCode.val(toCode.val()); from.val(to.val()); toCode.val(f1); to.val(f2); }); })(); //#endregion //#region 要求發到站和終點站完全比對 (function () { var fromText = $("#fromStationText"); var toText = $("#toStationText"); $("#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>"); $("#closeFuseSearch, #closeFuseSearch1").parent().attr("title", '預設情況下,例如查找‘杭州’時,會包括‘杭州南’這個車站。勾選此選項,将會在搜尋‘杭州’的時候,過濾那些不完全一緻的車站,如‘杭州南’。'); function getStationName() { var txt = $.trim(this.text()).split(/\s/); return txt[0]; } checkTicketsQueue.push(function (result) { if (document.getElementById("closeFuseSearch").checked) { var fs = getStationName.call(this.find("td:eq(1)")); if (fs != fromText.val()) { this.hide(); return 0; } } if (document.getElementById("closeFuseSearch1").checked) { var fs = getStationName.call(this.find("td:eq(2)")); if (fs != toText.val()) { this.hide(); return 0; } } return result; }); })(); //#endregion //#region 保持線上 var time_offset = null; var time_server = null; (function () { $("#helpertooltable tr:last").before("<tr class='fish_sep'><td class='name'>保持線上</td><td colspan='3'>助手每隔十分鐘會幫你重新整理存在感防止挂機而掉線的啦。。。。。最後重新整理時間:<strong id='lastonlinetime'>無</strong></td></tr>"); var label = $("#lastonlinetime"); function online() { var serverTime = null; utility.post("/otsweb/main.jsp", null, "text", function (data, status, xhr) { serverTime = new Date(xhr.getResponseHeader("Date")); time_offset = new Date() - serverTime; label.html(utility.formatTime(serverTime)); }); } online(); setInterval(online, 600 * 1000); })(); //顯示本地時間和伺服器時間 (function () { var dom = $("#servertime strong"); function display() { if (time_offset === null) return; var now = new Date(); time_server = new Date(); time_server.setTime(now.getTime() - time_offset); document.getElementById("chkSmartSpeed").disabled = time_server.getFullYear() < 2000; dom.eq(0).html(utility.formatTime(time_server)); dom.eq(1).html(utility.formatTime(now)); dom.eq(2).html((time_offset < 0 ? "快" : "慢") + (Math.abs(time_offset) / 1000) + "秒"); } setInterval(display, 1000); display(); })(); //#endregion //#region 車票模式配置 (function () { $("#helpertooltable tr:first").before("<tr class='fish_sep caption'><td class='name' colspan='4'>出行模式</td></tr>\ <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>\ </tr>\ "); var list = (window.localStorage["profilelist"] || "").split("\t"); var listDom = $("#profilelist"); var listEle = listDom[0]; if (list[0] == "") list.splice(0, 1); $.each(list, function () { listEle.options[listEle.options.length] = new Option(this + '', this + ''); }); listDom.change(function () { var value = listDom.val(); if (!value) return; applyProfile(loadProfile(value)); }); $("#profile_save").click(function () { if (!listDom.val()) $("#profile_add").click(); else { saveProfile(listDom.val(), generateProfile()); alert("存檔已經更新~"); } }); $("#profile_add").click(function () { var data = generateProfile(); var name = prompt("請輸入出行模式的名稱,如『出去鬼混』神馬的……", "嗷嗷回家~"); if (!name) return; name = name.replace(/\s+/g, ""); if (window.localStorage.getItem("profile_" + name)) { alert("啊嘞?這個名字的已經有了喔,重試呗~"); } else { saveProfile(name, data); list.push(name); listEle.options[listEle.options.length] = new Option(name, name); window.localStorage.setItem("profilelist", list.join("\t")); alert("已儲存唷。"); } }); $("#profile_delete").click(function () { var idx = listEle.selectedIndex; if (!idx || !confirm("親,确定要下此狠手咩?")) return; listEle.options[idx] = null; window.localStorage.removeItem("profile_" + list[idx - 1]); list.splice(idx - 1, 1); window.localStorage.setItem("profilelist", list.join("\t")); alert("乃伊佐特~"); }); $("#profile_reset").click(function () { listDom.val(""); applyProfile({ "blackListEnabled": true, "whiteListEnabled": true, "autoBookListEnabled": true, "seatOrder": [], "prePassenger": [], "whiteList": [], "blackList": [], "autoBookList": [], "autoBookMethod": "1" }); }); function loadProfile(name) { return $.parseJSON(window.localStorage.getItem("profile_" + name)); } function saveProfile(name, profile) { if (!profile) window.localStorage.removeItem(name); else window.localStorage.setItem("profile_" + name, $.toJSON(profile)); } function generateProfile() { var pro = {}; pro.blackListEnabled = document.getElementById("swBlackList").checked; pro.whiteListEnabled = document.getElementById("swWhiteList").checked; pro.autoBookListEnabled = document.getElementById("swAutoBook").checked; pro.seatOrder = seatLevelOrder; pro.prePassenger = $.map($("#passengerList1 :checkbox"), function (e) { var data = $(e).data("pasinfo"); return { type: data.passenger_type, idtype: data.passenger_id_type_code, id: data.passenger_id_no }; });; pro.whiteList = list_whitelist.datalist; pro.blackList = list_blacklist.datalist; pro.autoBookList = list_autoorder.datalist; pro.autoBookMethod = $("#autoorder_method").val(); pro.queryInfo = $("#querySingleForm").serializeArray(); return pro; } function applyProfile(pro) { $("#swBlackList").attr("checked", pro.blackListEnabled).change(); $("#swWhiteList").attr("checked", pro.whiteListEnabled).change(); $("#swAutoBook").attr("checked", pro.autoBookListEnabled).change(); //清除席别優選 $("#preseatlist input").click(); var seatList = $("#preSelectSeatList"); $.each(pro.seatOrder, function () { seatList.val(this + '').change(); }); //黑名單白名單神馬的。 list_whitelist.emptyList(); $.each(pro.whiteList, function () { list_whitelist.add(this + ''); }); list_blacklist.emptyList(); $.each(pro.blackList, function () { list_blacklist.add(this + ''); }); list_autoorder.emptyList(); $.each(pro.autoBookList, function () { list_autoorder.add(this + ''); }); //聯系人 var plist = $("input:checkbox[name=preSelectPassenger]"); plist.attr("checked", false); plist.change(); $.each(pro.prePassenger, function () { var p = this; plist.each(function () { var data = $(this).data("pasinfo"); if (data.passenger_type == p.type && data.passenger_id_type_code == p.idtype && data.passenger_id_no == p.id) { this.checked = true; $(this).change(); return false; } return true; }); }); //優選方式 $("#autoorder_method").val(pro.autoBookMethod).change(); //查詢方式 if (pro.queryInfo) { $.each(pro.queryInfo, function () { if (this.name.indexOf("orderRequest.") == -1) return; $("input[name=" + this.name + "]").val(this.value).change(); }); } utility.notifyOnTop("已加載出行模式"); } })(); //#endregion utility.reloadPrefs($("tr.append_row"), "ticket_query"); //完成初始化 initialized = true; parent.$("#main").css("height", ($(document).height() + 300) + "px"); parent.window.setHeight(parent.window); } //#endregion //#region 自動送出訂單 function initDirectSubmitOrder() { //if (Math.random() > 0.10) return; console.log("[INFO] initialize direct submit order."); var html = "<div id='fishSubmitFormStatus' class='outerBox' style='position:fixed;left:0px;bottom:-100px;'><div class='box'><div class='title'>自動送出訂單中</div>\ <div class='content' style='width:150px;'><ul id='tipScript'>\ <li class='fish_clock' id='countEle' style='font-weight:bold;'>等待操作</li>\ <li style='color:green;'><strong>操作資訊</strong>:<span>休息中</span></li>\ <li style='color:green;'><strong>最後操作時間</strong>:<span>--</span></li></div>\ </div></div>"; parent.window.$("#fishSubmitFormStatus").remove(); parent.window.$("body").append(html); var tip = parent.window.$("#tipScript li"); var counter = parent.window.$("#countEle"); var status = parent.window.$("#fishSubmitFormStatus"); var formData = null; var tourFlag; var data = null; $("#autoorder")[0].disabled = false; function setCurOperationInfo(running, msg) { counter.removeClass().addClass(running ? "fish_running" : "fish_clock").html(msg || (running ? "正在操作中……" : "等待中……")); } function setTipMessage(msg) { tip.eq(2).find("span").html(utility.getTimeInfo()); tip.eq(1).find("span").html(msg); } //視窗狀态 var statusShown = false; function showStatus() { if (statusShown) return; statusShown = true; status.animate({ bottom: "0px" }); } function hideStatus() { if (!statusShown) return; statusShown = false; status.animate({ bottom: "-100px" }); } //驗證碼事件 var randRow = $("#randCodeTxt").closest("tr"); function refreshRandRowStyle() { randRow.removeClass("steps stepsok"); randRow.addClass(getVcCode().length == 4 ? "stepsok" : "steps"); } $("#randCodeTxt").keyup(function () { refreshRandRowStyle(); if (statusShown && document.getElementById("randCodeTxt").value.length == 4) checkOrderInfo(); }); $("#autoorder").change(refreshRandRowStyle); //重新整理驗證碼 function reloadCode() { $("#randCode").attr("src", "/otsweb/passCodeAction.do?rand=randp&" + Math.random()); var vcdom = document.getElementById("randCodeTxt"); vcdom.focus(); vcdom.select(); } $("#randCode").click(reloadCode); function getVcCode() { return document.getElementById("randCodeTxt").value; } function isCanAutoSubmitOrder() { if (!document.getElementById("autoorder").checked) return []; var result = []; if (!$("#passengerList1 :checkbox").length) result.push("選擇乘客"); if (!$("#preseatlist input").length) result.push("設定優選席别"); if (getVcCode().length != 4) result.push("填寫驗證碼"); if (!$("#autobookListTd input").length) result.push("設定自動預定車次"); return result; } function redirectToNotCompleteQuery() { window.location.replace("/otsweb/order/myOrderAction.do?method=queryMyOrderNotComplete&leftmenu=Y"); } $("#orderForm").submit(function () { if (!document.getElementById("autoorder").checked || isCanAutoSubmitOrder().length || !($("#preSelectSeat").val())) return true; showStatus(); utility.notifyOnTop("開始自動送出預定訂單!"); setCurOperationInfo(true, "正在自動送出訂單"); //确定乘客 var tcode = $("#station_train_code").val(); var seatCode = $("#preSelectSeat").val(); var count = parseInt($.trim($("#gridbox tr[tcode=" + tcode + "] td[scode=" + seatCode + "]").text())) || 0; if (seatCode == "1" && $("#preseatlist input[code=empty]").length) { //允許了無座,那就加上無座的票數 count = parseInt($.trim($("#gridbox tr[tcode=" + tcode + "] td[scode=empty]").text())) || 0; } var pases = $("#passengerList1 :checkbox"); console.log("欲購票數=" + pases.length + ",實際票數=" + count + " (isNaN 為很多 =。=)"); if (!isNaN(count) && count > 0 && count < pases.length) { $("#passengerList1 :checkbox:gt(" + (count - 1) + ")").attr("checked", false).change(); } var form = $(this); utility.post(form.attr("action"), form.serialize(), "text", function (html) { if (html.indexOf("您還有未處理") != -1) { hideStatus(); utility.notifyOnTop("您還有未處理訂單!"); redirectToNotCompleteQuery(); return; } setTipMessage("正在分析内容"); getOrderFormInfo(html); }, function () { utility.notifyOnTop("送出預定請求發生錯誤,稍等重試!"); utility.delayInvoke(counter, function () { $("#orderForm").submit(); }, 2000); }); return false; }); function getOrderFormInfo(html) { if (typeof (html) != 'undefined' && html) { data = utility.analyzeForm(html); data.fields["orderRequest.reserve_flag"] = "A"; //網上支付 tourFlag = data.tourFlag; //組裝請求 formData = []; $.each(data.fields, function (i) { if (i.indexOf("orderRequest") != -1 || i.indexOf("org.") == 0 || i == "leftTicketStr") formData.push(i + "=" + encodeURIComponent(this)); }); formData.push("tFlag=" + data.tourFlag); //添加乘客 var pas = $("#passengerList1 :checkbox"); var seat = $("#preSelectSeat").val(); var seatType = $("#preselectseatlevel").val(); for (var i = 0; i < 5; i++) { if (i >= pas.length) { formData.push("oldPassengers="); formData.push("checkbox9="); continue; } var p = pas.eq(i).data("pasinfo"); var ptype = p.passenger_type; var idtype = p.passenger_id_type_code; var idno = p.passenger_id_no; var name = p.passenger_name; //學生票? if (clickBuyStudentTicket != "Y" && ptype == "3" && !document.getElementById("autoorder_stu").checked) ptype = 1; formData.push("passengerTickets=" + seat + "," + seatType + "," + ptype + "," + encodeURIComponent(name) + "," + idtype + "," + encodeURIComponent(idno) + "," + p.mobile_no + ",Y"); formData.push("oldPassengers=" + encodeURIComponent(name) + "," + idtype + "," + encodeURIComponent(idno)); formData.push("passenger_" + (i + 1) + "_seat=" + seat); formData.push("passenger_" + (i + 1) + "_seat_detail=" + seatType); formData.push("passenger_" + (i + 1) + "_ticket=" + ptype); formData.push("passenger_" + (i + 1) + "_name=" + encodeURIComponent(name)); formData.push("passenger_" + (i + 1) + "_cardtype=" + idtype); formData.push("passenger_" + (i + 1) + "_cardno=" + idno); formData.push("passenger_" + (i + 1) + "_mobileno=" + p.mobile_no); formData.push("checkbox9=Y"); } } checkOrderInfo(); } function checkOrderInfo() { setCurOperationInfo(true, "正在檢測訂單狀态...."); utility.notifyOnTop("開始自動送出訂單!"); console.log(data); utility.post("confirmPassengerAction.do?method=checkOrderInfo&rand=" + getVcCode(), formData.join("&") + "&randCode=" + getVcCode(), "json", function (data) { console.log(data); if ('Y' != data.errMsg || 'N' == data.checkHuimd || 'N' == data.check608) { if (data.errMsg && data.errMsg.indexOf("驗證碼") != -1) { utility.notifyOnTop("驗證碼不正确。請輸入驗證碼!"); setTipMessage("請重新輸入驗證碼。"); reloadCode(); } else { setCurOperationInfo(false, data.msg || data.errMsg); document.getElementById("autoorder").checked = false; $("#orderForm").submit(); } return; } queryQueueInfo(); }, function () { setCurOperationInfo(false, "網絡出現錯誤,稍等重試"); utility.delayInvoke(counter, checkOrderInfo, 500); }); } function queryQueueInfo() { if (!document.getElementById("autoorder").checked) { hideStatus(); return; } setCurOperationInfo(true, "正在送出訂單"); setTipMessage("正在檢查隊列。"); var queryLeftData = { train_date: data.fields["orderRequest.train_date"], station: data.fields["orderRequest.station_train_code"], train_no: data.fields["orderRequest.train_no"], seat: $("#preSelectSeat").val(), from: data.fields["orderRequest.from_station_telecode"], to: data.fields["orderRequest.to_station_telecode"], ticket: data.fields["leftTicketStr"] }; utility.get("/otsweb/order/confirmPassengerAction.do?method=getQueueCount", queryLeftData, "json", function (data) { if (data.op_2) { //utility.notifyOnTop("排隊人數過多,系統禁止排隊,稍等重試。要重新查詢,請重新整理頁面!"); setTipMessage("排隊人數過多 (人數=" + data.count + ")"); setCurOperationInfo(true, "排隊人數過多"); utility.delayInvoke(counter, queryQueueInfo, 500); } else { submitOrder(); } }, function () { utility.delayInvoke(counter, queryQueueInfo, 500); }); } function submitOrder() { if (!document.getElementById("autoorder").checked) { hideStatus(); return; } setCurOperationInfo(true, "正在送出訂單"); setTipMessage("已檢測狀态。"); var order_type = 'confirmSingleForQueueOrder'; //'dc' 單程 if (tourFlag == 'wc') { // 異步下單-往程 order_type = 'confirmPassengerInfoGoForQueue'; } else if (tourFlag == 'fc') { // 異步下單-返程 order_type = 'confirmPassengerInfoBackForQueue'; } else if (tourFlag == 'gc') { // 異步下單-改簽 order_type = 'confirmPassengerInfoResignForQueue'; } utility.post('/otsweb/order/confirmPassengerAction.do?method=' + order_type, formData.join("&") + "&randCode=" + getVcCode(), "json", function (data) { var msg = data.errMsg; if (msg == "Y") { setTipMessage("訂單送出成功"); setCurOperationInfo(false, "訂單送出成功,請等待排隊完成。"); utility.notifyOnTop("訂單送出成功,請等待排隊完成。"); redirectToNotCompleteQuery(); } else { if (msg.indexOf("包含未付款訂單") != -1) { hideStatus(); alert("您有未支付訂單! 等啥呢, 趕緊點确定支付去."); redirectToNotCompleteQuery(); return; } if (msg.indexOf("重複送出") != -1) { setTipMessage("TOKEN失效,重新整理Token中...."); $("#orderForm").submit(); return; } if (msg.indexOf("包含排隊中") != -1) { hideStatus(); alert("您有排隊中訂單! 點确定轉到排隊頁面"); redirectToNotCompleteQuery(); return; } if (msg.indexOf("排隊人數現已超過餘票數") != -1) { //排隊人數超過餘票數,那麼必須重新送出 document.getElementById("autoorder").checked = false; setTipMessage(msg); reloadCode(); setCurOperationInfo(false, "警告:" + msg + ",自動復原為手動送出,請切換車次或席别,請盡快重試!"); sendQueryFunc.call(clickBuyStudentTicket == "Y" ? document.getElementById("stu_submitQuery") : document.getElementById("submitQuery")); return; } setTipMessage(msg); setCurOperationInfo(false, "未知錯誤:" + msg + ",請告知作者。"); utility.notifyOnTop("未知錯誤:" + msg + ",請告知作者。"); if (document.getElementById("autoorder_autocancel").checked) { document.getElementById("autoorder").checked = false; $("#autoorder").change(); $("#orderForm").submit(); } } }, function () { setCurOperationInfo(false, "網絡出現錯誤,稍等重試"); utility.delayInvoke(counter, submitOrder, 2000); }); } //周期性檢測狀态,已确認可以自動送出 setInterval(function () { if (document.getElementById("autoorder").checked) { var r = isCanAutoSubmitOrder(); if (r.length) { utility.notifyOnTop("您選擇了自動送出訂單,但是資訊沒有設定完整!請" + r.join("、") + "!"); } } }, 30 * 1000); //最後顯示界面,防止初始化失敗卻顯示了界面 $("tr.autoordertd, td.autoordertd *").show(); } //#endregion //#region -----------------自動登入---------------------- function initLogin() { //啟用日志 utility.enableLog(); //如果已經登入,則自動跳轉 utility.unsafeCallback(function () { if (parent && parent.$) { var str = parent.$("#username_ a").attr("href"); if (str && str.indexOf("sysuser/user_info") != -1) { window.location.href = "https://dynamic.12306.cn/otsweb/order/querySingleAction.do?method=init"; } return; } }); //檢測主架構是否是頂級視窗 var isTop = false; try { isTop = (top.location + '').indexOf("dynamic.12306.cn") != -1; } catch (e) { } if (!isTop) { $("#loginForm table tr:first td:last").append("<a href='https://dynamic.12306.cn/otsweb/' target='_blank' style='font-weight:bold;color:red;'>點選全屏訂票</a>"); if (!utility.getPref("login.fullscreenAlert")) { utility.setPref("login.fullscreenAlert", 1); utility.notifyOnTop("強烈建議你點選界面中的『點選全屏訂票』來全屏購票,否則助手有些提示消息您将無法看到!"); } } //Hack目前UI顯示 $(".enter_right").empty().append("<div class='enter_enw'>" + "<div class='enter_rtitle' style='padding: 40px 0px 10px 0px; font-size: 20px;'>腳本提示資訊</div>" + "<div class='enter_rfont'>" + "<ul id='tipScript'>" + "<li class='fish_clock' id='countEle' style='font-weight:bold;'>等待操作</li>" + "<li style='color:green;'><strong>操作資訊</strong>:<span>休息中</span></li>" + "<li style='color:green;'><strong>最後操作時間</strong>:<span>--</span></li>" + "<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>" + '<li id="enableNotification"><input type="button" id="enableNotify" onclick="$(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>' + "</ul>" + "</div>" + "</div>"); var html = []; html.push("<div class='outerbox' style='margin:15px;'><div class='box'><div class='title'>小提示</div><div style='padding:10px;'>"); 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>"); 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>"); 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>"); html.push("</ul></td><td><ol>"); $.each([ ["http://www.fishlee.net/soft/44/tour.html", "訂票助手使用指南", "font-weight:bold;color:red;"], ["http://www.fishlee.net/soft/44/12306faq.html", "訂票的常見問題&指南", ""], ["http://www.fishlee.net/soft/44/faq.html", "助手運作的常見問題", ] ], function (i, n) { html.push("<li style='list-style:disc inside;'><a style='" + n[2] + "' href='" + n[0] + "' target='blank'>" + (n[1] || n[0]) + "</a></li>"); }); html.push("</ol></td><td><ul>"); var info = []; info.push("已許可于:" + utility.regInfo.name); if (utility.regInfo.bindAcc) { if (!utility.regInfo.bindAcc[0] || utility.regInfo.bindAcc[0] == "*") info.push("許可12306帳戶:<em>無限</em>"); else info.push("許可12306帳戶:" + utility.regInfo.bindAcc); } info.push(utility.regInfo.typeDesc); info.push("版本:<strong>" + window.helperVersion + "</strong>"); $.each(info, function (i, n) { html.push("<li style='list-style:disc inside;'>" + n + "</li>"); }); html.push("<li style='list-style:disc inside;'>【<a href='javascript:;' class='reSignHelper'>重新注冊</a>】</li>"); html.push("</ul></td></tr></table>"); html.push("</div></div></div>"); $("div.enter_help").before(html.join("")); //插入登入标記 var form = $("#loginForm"); var trs = form.find("tr"); trs.eq(1).find("td:last").html('<label><input type="checkbox" id="keepInfo" /> 記錄密碼</label>'); $("#loginForm td:last").html('<label><input type="checkbox" checked="checked" id="autoLogin" name="autoLogin" /> 自動登入</label>'); utility.reloadPrefs($("#loginForm td:last")); $("#keepInfo").change(function () { if (!this.checked) { if (localStorage.getItem("__un") != null) { localStorage.removeItem("__un"); localStorage.removeItem("__up"); alert("儲存的密碼已經删除!"); } } }); //注冊判斷 form.submit(function () { utility.setPref("_sessionuser", $("#UserName").val()); }); if (!window.webkitNotifications || window.webkitNotifications.checkPermission() == 0) { $("#enableNotification").remove(); } var tip = $("#tipScript li"); var count = 1; var errorCount = 0; var inRunning = false; //以下是函數 function setCurOperationInfo(running, msg) { var ele = $("#countEle"); ele.removeClass().addClass(running ? "fish_running" : "fish_clock").html(msg || (running ? "正在操作中……" : "等待中……")); } function setTipMessage(msg) { tip.eq(2).find("span").html(utility.getTimeInfo()); tip.eq(1).find("span").html(msg); } function getLoginRandCode() { setCurOperationInfo(true, "正在獲得登入随機碼"); $.ajax({ url: "/otsweb/loginAction.do?method=loginAysnSuggest", method: "POST", dataType: "json", cache: false, success: function (json, code, jqXhr) { //{"loginRand":"211","randError":"Y"} if (json.randError != 'Y') { setTipMessage("錯誤:" + json.randError); utility.delayInvoke("#countEle", getLoginRandCode, utility.getLoginRetryTime()); } else { setTipMessage("登入随機碼 -> " + json.loginRand); $("#loginRand").val(json.loginRand); submitForm(); } }, error: function (xhr) { errorCount++; if (xhr.status == 403) { setTipMessage("[" + errorCount + "] 警告! 403錯誤, IP已被封!") utility.delayInvoke("#countEle", getLoginRandCode, 10 * 1000); } else { setTipMessage("[" + errorCount + "] 網絡請求錯誤,重試") utility.delayInvoke("#countEle", getLoginRandCode, utility.getLoginRetryTime()); } } }); } function submitForm() { var data = {}; $.each($("#loginForm").serializeArray(), function () { if (this.name == "refundFlag" && !document.getElementById("refundFlag").checked) return; data[this.name] = this.value; }); if (!data["loginUser.user_name"] || !data["user.password"] || !data.randCode || data.randCode.length != 4/* || (utility.regInfo.bindAcc && utility.regInfo.bindAcc != data["loginUser.user_name"])*/) return; if ($("#keepInfo")[0].checked) { utility.setPref("__un", data["loginUser.user_name"]); utility.setPref("__up", data["user.password"]) } setCurOperationInfo(true, "正在登入中……"); $.ajax({ type: "POST", url: "/otsweb/loginAction.do?method=login", data: data, timeout: 10000, dataType: "text", success: function (html) { msg = utility.getErrorMsg(html); if (html.indexOf('請輸入正确的驗證碼') > -1) { setTipMessage("驗證碼不正确"); setCurOperationInfo(false, "請重新輸入驗證碼。"); stopLogin(); } else if (msg.indexOf('密碼') > -1) { setTipMessage(msg); setCurOperationInfo(false, "請重新輸入。"); stopLogin(); } else if (msg.indexOf('鎖定') > -1) { setTipMessage(msg); setCurOperationInfo(false, "請重新輸入。"); stopLogin(); } else if (html.indexOf("歡迎您登入") != -1) { utility.notifyOnTop('登入成功,開始查詢車票吧!'); window.location.href = "https://dynamic.12306.cn/otsweb/order/querySingleAction.do?method=init"; } else { setTipMessage(msg); utility.delayInvoke("#countEle", getLoginRandCode, utility.getLoginRetryTime()); } }, error: function (msg) { errorCount++; if (xhr.status == 403) { setTipMessage("[" + errorCount + "] 警告! 403錯誤, IP已被封!") utility.delayInvoke("#countEle", getLoginRandCode, 10 * 1000); } else { setTipMessage("[" + errorCount + "] 網絡請求錯誤,重試") utility.delayInvoke("#countEle", getLoginRandCode, utility.getLoginRetryTime()); } } }); } function relogin() { if (inRunning) return; var user = $("#UserName").val(); if (!user) return; if (utility.regInfo.bindAcc && utility.regInfo.bindAcc.length && utility.regInfo.bindAcc[0] && $.inArray(user, utility.regInfo.bindAcc) == -1 && utility.regInfo.bindAcc[0] != "*") { alert("很抱歉,12306訂票助手的授權許可已綁定至【" + utility.regInfo.bindAcc.join() + "】,未授權使用者,助手停止運作,請手動操作。\n您可以在登入頁面下方的幫助區點選【重新注冊】來修改綁定。"); return; } count++; utility.setPref("_sessionuser", $("#UserName").val()); inRunning = true; getLoginRandCode(); } function stopLogin() { //等待重試時,重新整理驗證碼 $("#img_rrand_code").click(); $("#randCode").val("")[0].select(); inRunning = false; } //初始化 function executeLogin() { count = 1; utility.notify("自動登入中:(1) 次登入中..."); setTipMessage("開始登入中...."); getLoginRandCode(); return false; } var kun = utility.getPref("__un"); var kup = utility.getPref("__up"); if (kun && kup) { $("#UserName").val(kun); $("#password").val(kup); $("#randCode")[0].focus(); } $("#randCode").keyup(function (e) { if (!$("#autoLogin")[0].checked) return; e = e || event; if (e.charCode == 13 || $("#randCode").val().length == 4) relogin(); }); //#region 起售時間提示和查詢 function addDays(count) { return new Date(this.getFullYear(), this.getMonth(), this.getDate() + count); } var curDate = new Date(); var html = ["<li style='font-weight:bold; color:blue;'><u>助手提示</u>:網上和電話訂票提前20天,本日起售【<u>"]; html.push(utility.formatDate(addDays.call(curDate, 19))); html.push("</u>】日車票;代售點和車站提前18天,本日起售【<u>"); html.push(utility.formatDate(addDays.call(curDate, 17))); html.push("</u>】日車票。<br />【<a href='javascript:;' id='querySaleDate'>根據乘車日期推算起售日期</a>】【<a href='http://www.12306.cn/mormhweb/zxdt/tlxw_tdbtz53.html' target='_blank'>以相關公告、車站公告為準</a>】"); $("div.enter_from ul").append(html.join("")); $("#querySaleDate").click(function () { var date = prompt("請輸入您要乘車的日期,如:2013-02-01"); if (!date) return; if (!/(\d{4})[-/]0?(\d{1,2})[-/]0?(\d{1,2})/.exec(date)) { alert("很抱歉未能識别日期"); } date = new Date(parseInt(RegExp.$1), parseInt(RegExp.$2) - 1, parseInt(RegExp.$3)); alert("您查詢的乘車日期是:" + utility.formatDate(date) + "\n\n網際網路、電話起售日期是:" + utility.formatDate(addDays.call(date, -19)) + "\n車站、代售點起售日期是:" + utility.formatDate(addDays.call(date, -17)) + "\n\n以上結果僅供參考。"); }); //#endregion } //#endregion //#region 自動重新支付 function initPayOrder() { //如果出錯,自動重新整理 if ($("div.error_text").length > 0) { utility.notifyOnTop("頁面出錯,稍後自動重新整理!"); setTimeout(function () { self.location.reload(); }, 3000); } return; // undone window.payOrder = this; //epayOrder var oldCall = window.epayOrder; var formUrl, formData; $("#myOrderForm").submit(function () { var form = $(this); var action = form.attr("action"); if (acton && action.index("laterEpay") != -1) { return false; } }); window.epayOrder = function () { oldCall.apply(arguments); var form = $("#myOrderForm"); var formData = utility.serializeForm(form); var formUrl = form.attr("action"); }; function getsubmitForm() { utility.post(formUrl, formData, "text", function (html) { }, function () { }); } } //#endregion //#region 更新專用檢測代碼 if (location.pathname == "/otsweb/" || location.pathname == "/otsweb/main.jsp") { if (isFirefox) { //firefox 專用檢測代碼 GM_xmlhttpRequest({ method: "GET", url: "http://www.fishlee.net/service/update/44/version.js", function (o) { eval(o.responseText); if (typeof (fishlee12306_msgid) != 'undefined') { if (utility.getPref("helperlastmsgid") != fishlee12306_msgid) { utility.setPref("helperlastmsgid", fishlee12306_msgid); if (!fishlee12306_msgver || compareVersion(version, fishlee12306_msgver) < 0) { if (fishlee12306_msg) alert(fishlee12306_msg); } } } console.log("[INFO] 更新檢查:目前助手版本=" + version + ",新版本=" + version_12306_helper); if (compareVersion(version, version_12306_helper) < 0 && confirm("訂票助手已釋出新版 【" + version_12306_helper + "】,為了您的正常使用,請及時更新!是否立刻更新?\n\n本次更新内容如下:\n" + version_updater.join("\n"))) { GM_openInTab("http://www.fishlee.net/Service/Download.ashx/44/47/12306_ticket_helper.user.js", true, true); } } }); } else { unsafeInvoke(function () { $("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>'); }); } } function compareVersion(v1, v2) { var vv1 = v1.split('.'); var vv2 = v2.split('.'); var length = Math.min(vv1.length, vv2.length); for (var i = 0; i < length; i++) { var s1 = parseInt(vv1[i]); var s2 = parseInt(vv2[i]); if (s1 < s2) return -1; if (s1 > s2) return 1; } return vv1.length > vv2.length ? 1 : vv1.length < vv2.length ? -1 : 0; } //#endregion