Light12306/Web12306/js/otn/queryticket.js

403 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

define(function (require, exports, module) {
var ajax = require("../platform/webRequest.js");
var param = require("../data.js");
var parser = require("../platform/parser.js");
var ev = require("../platform/EventObject.js");
var dynamicjs = require("../otn/dynamicjs.js");
var sessmgr = require("../account/sessionMgr.js");
var stationData = require("../station/station_data.js");
var utility = require('../utility.js');
var extensionVersion = parseInt(document.body.dataset["targetExtensionVersion"].replace(/\./g, ""));
exports.events = new ev();
//最后二十次的查询平均时间
var lastQueryTimes = [];
var averageQueryTime = null;
var calculateQueryTime = function (time) {
lastQueryTimes.push(time);
while (lastQueryTimes.length > 20)
lastQueryTimes.shift();
averageQueryTime = lastQueryTimes.length > 0 ? _.reduce(lastQueryTimes, function (x, y) { return x + y; }) / lastQueryTimes : 0;
};
Object.defineProperty(exports, "averageQueryTime", {
get: function () {
return averageQueryTime;
}
});
//记录参数
var queryTicketUrl = null;
var lastLogTime = null;
var isLogOpen = false;
var detectSuggest = function (result) {
result.suggestTransit = result.available.length > 0 && result.available.length <= 3;
var notFeCount = _.count(result.available, function (t) { return t.from.endpoint && t.to.endpoint; });
result.suggestMoreStat = notFeCount < 4 && notFeCount < result.available.length / 3;
result.hasSuggest = result.suggestMoreStat | result.suggestTransit;
};
var getTicketInfo = function (v) {
var data = [], info = v.indexOf("#") === -1 ? v : /getSelected\(['"](.*?)['"]\)/i.exec(v)[1].split('#')[11],
match = info.match(/([A-Z\d])0*?([\*\d]{5})0*?(\d{4})/gi);
for (var j in match) {
if (match.hasOwnProperty(j)) {
var m = /([A-Z\d])0*?([\*\d]{5})0*?(\d{4})/i.exec(match[j]);
var sc = m[1];
var sp = m[2][0] === '*' ? null : parseInt(m[2], 10);
var st = parseInt(m[3], 10);
var seat = { code: sc, name: param.toSeatTypeName(sc), price: sp, selected: false };
if (st < 3000) {
seat.count = st;
//TODO 二等软座提交是否和二等座一样都用的MO
//一等软座 7 二等软座 8
if (sc === "7") {
data.push({ code: "M", name: param.toSeatTypeName("M"), price: sp, count: st, selected: false });
} else if (sc === "8") {
data.push({ code: "O", name: param.toSeatTypeName("O"), price: sp, count: st, selected: false });
} else {
data.push(seat);
}
} else {
seat.count = st - 3000;
seat.code = '0';
seat.name = "无座";
data.push(seat);
}
}
};
return data;
};
var transferData = function (query, data, noProcess, noAction) {
var result = data;
if (!Array.isArray(result.data) || !result.data.length || !result.data[0].queryLeftNewDTO) {
exports.events.fireEvent("requestFailed");
};
var date = query.date;
var trainData = { query: query, raw: result, rawTrainMap: {}, trainMap: {}, auto: null, nextTime: null, noProcess: noProcess, noAction: noAction };
var messages = (result.messages || []).join("");
trainData.notInSellTime = messages.indexOf("在预售日期范围") !== -1;
_.each(result.data, function (t) {
var train = {
id: t.queryLeftNewDTO.train_no,
code: t.queryLeftNewDTO.station_train_code,
available: t.queryLeftNewDTO.canWebBuy === 'Y' ? 1 : 0,
start: {
code: t.queryLeftNewDTO.start_station_telecode,
name: t.queryLeftNewDTO.start_station_name
},
from: {
code: t.queryLeftNewDTO.from_station_telecode,
fromStationNo: t.queryLeftNewDTO.from_station_no,
name: t.queryLeftNewDTO.from_station_name,
endpoint: t.queryLeftNewDTO.from_station_telecode === t.queryLeftNewDTO.start_station_telecode,
time: t.queryLeftNewDTO.start_time
},
to: {
code: t.queryLeftNewDTO.to_station_telecode,
toStationNo: t.queryLeftNewDTO.to_station_no,
name: t.queryLeftNewDTO.to_station_name,
endpoint: t.queryLeftNewDTO.end_station_telecode === t.queryLeftNewDTO.to_station_telecode,
time: t.queryLeftNewDTO.arrive_time
},
elapsedTime: {
days: t.queryLeftNewDTO.day_difference,
total: t.queryLeftNewDTO.lishi
},
end: {
code: t.queryLeftNewDTO.end_station_telecode,
name: t.queryLeftNewDTO.end_station_name,
},
ypinfo: t.queryLeftNewDTO.yp_info,
ypinfo_ex: t.queryLeftNewDTO.yp_ex,
locationCode: t.queryLeftNewDTO.location_code,
controlDay: t.queryLeftNewDTO.control_day,
supportCard: t.queryLeftNewDTO.is_support_card,
saleTime: t.queryLeftNewDTO.sale_time,
secureStr: t.secretStr,
selltime: null,
date: date,
limitSellInfo: t.buttonTextInfo && t.buttonTextInfo.indexOf("暂售") !== -1 ? t.buttonTextInfo.replace(/<[^>]+>/i, "") : null,
controlFlag: parseInt(t.queryLeftNewDTO.controlled_train_flag, 10),
controlMessage: t.queryLeftNewDTO.controlled_train_message
};
var kp = getTicketInfo(t.queryLeftNewDTO.yp_info);
train.tickets = kp;
train.ticketMap = _.mapObject(kp, function (e) { return e.code; });
//起售时间
var selltimem = /(0*(\d+)月0*(\d+)日)?(\d+)\s*点\s*((\d+)分)?\s*起售/i.exec(t.buttonTextInfo.replace(/<.*?>/g, ''));
if (selltimem) {
train.available = -1;
train.selltime = new Date();
train.selltime.setHours(parseInt(selltimem[4]));
train.selltime.setMinutes(parseInt(selltimem[6] || "0", 10));
train.selltime.setSeconds(0);
if (selltimem[1]) {
//带日期
train.selltime.setDate(parseInt(selltimem[3]));
train.selltime.setMonth(parseInt(selltimem[2]) - 1);
if (train.selltime.getMonth() < new Date().getMonth()) {
train.selltime.setFullYear(train.selltime.getFullYear() + 1);
}
}
}
trainData.rawTrainMap[train.id] = t;
trainData.trainMap[train.id] = train;
});
trainData.original = _.values(trainData.trainMap);
trainData.available = trainData.original;
trainData.trainCodes = _.pluck(trainData.original, "code");
trainData.filtered = [];
trainData.include = trainData.available;
if (!noProcess) {
//执行车次预过滤。过滤内容:出发地,目标地,时间
exports.events.fireEvent("filterTrains", trainData);
//处理车次
exports.events.fireEvent("processTrains", trainData);
//过滤数据
if (trainData.filtered && trainData.filtered.length) {
//从原始数据中删除
var orgMap = _.mapObject(result.data, function (e) {
return e.queryLeftNewDTO.train_no;
});
var filtered = _.map(trainData.filtered, function (t) {
return orgMap[t.id];
});
trainData.rawDataFiltered = _.without.apply(null, [result.data].concat(filtered));
result.data = trainData.rawDataFiltered;
}
}
//处理跨站购票预售提醒
_.each(trainData.available, function (t) {
//非预售,或预售的非当天的,始发站的,则跳过
if (!t.selltime || Math.floor(new Date().getTime() / 86400000) !== Math.floor(t.selltime.getTime() / 86400000))
return;
//查询始发站起售时间
var firstStationSellTime = stationData.sellTime[t.start.code];
if (!firstStationSellTime)
return;
//判断始发站和当前站时间间隔。如果间隔超过指定的时间,则放弃建议
var spanSellCurrent = Math.floor((t.selltime.getTime() % 86400000) / 1000) + 8 * 3600; //需要加上时区
var spanSellNow = Math.floor((new Date().getTime() % 86400000) / 1000) + 8 * 3600;
var spanSellStart = utility.toTimeSpan(firstStationSellTime, true);
var timeDifference = Math.abs((spanSellCurrent - spanSellStart) / 60);
var isEarly = spanSellStart < spanSellCurrent;
var isStartInSell = spanSellNow >= spanSellStart;
var tCode = t.code[0];
//if (
// (tCode === 'G' && timeDifference > 120) //高铁超过2小时
// ||
// (tCode === 'D' && timeDifference > 180) //动车超过3小时
// ||
// ((tCode === 'Z' || tCode === 'T') && timeDifference > 360) //直达/特快超过6小时
// ||
// timeDifference > 600 //其它类型车次大于10小时
// )
// return;
t.preStationInfo = "<span class='train-nostarttip train-nostarttip-" + (isStartInSell ? "insell" : isEarly ? "early" : "later") + "'>";
t.preStationInfo += "始发站【<a href='javascript:;' data-ts-code='" + t.start.code + "' data-train-code='" + t.code + "' data-command='suggest-swtichrelate'>" + t.start.name + "</a>】起售时间为【" + firstStationSellTime + "】," + (isStartInSell ? "已经在售" : isEarly ? "比当前车站起售时间早,可先去看看" : "可稍后留意");
t.preStationInfo += "</span>";
});
detectSuggest(trainData);
return trainData;
};
exports.queryTicket = function (from, fromName, to, toName, date, student, resign, noProcess, noAction, byAuto) {
var def = new $.Deferred();
var queryCount = 0;
var queryLogSubmited = false;
var queryStartTime, queryEndTime;
def.fail(function () {
exports.events.fireEvent("requestFailed");
});
//before query event.
if (!noAction && !noProcess) {
var evdata = {
from: from,
fromName: fromName,
to: to,
toName: toName,
auto: byAuto || false
};
exports.events.fireEvent("beforeQueryTicket", evdata);
from = evdata.from;
to = evdata.to;
fromName = evdata.fromName;
toName = evdata.toName;
}
var queryFail = function () {
if (queryCount++ < 5) {
def.notify({ action: "requery" });
//def.notify("12306出问题了正在第 " + queryCount + " 次重连...");
setTimeout(sendQueryRequest, 2000);
} else {
def.reject("12306出问题了请稍后重试...");
}
};
var sendQueryRequest = function () {
var p = {
"leftTicketDTO.train_date": date,
"leftTicketDTO.from_station": from,
"leftTicketDTO.to_station": to,
"purpose_codes": student ? "0X00" : "ADULT"
};
var cookie = (function (obj) {
var arr = [];
_.forEach(obj, function (v, k) { arr.push(k + '=' + v); });
return arr.join("; ");
})(extensionVersion >= 720 ? {
"_jc_save_fromStation": escape(fromName + "," + from),
"_jc_save_toStation": escape(toName + "," + to),
"_jc_save_fromDate": date,
"_jc_save_toDate": date,
"_jc_save_wfdc_flag": resign ? "gc" : "dc"
} : {});
if (isLogOpen) {
exports.log(p, cookie);
}
queryStartTime = new Date().getTime();
ajax.sendGet(queryTicketUrl, "leftTicket/init", p, "json", function () {
if (!this.model) {
queryFail();
return;
}
//url changed?
if (!this.model.status && this.model.c_url) {
queryTicketUrl = this.model.c_url;
sendQueryRequest();
} else if (!this.model.status) {
var error = parser.getError(this.model);
if (error && error.message && error.message.indexOf("查询失败") !== -1) {
exports.log(p, cookie, true).always(queryFail);
return;
}
queryFail();
} else {
queryEndTime = new Date().getTime();
calculateQueryTime(queryEndTime - queryStartTime);
var data = transferData({
from: from,
fromName: fromName,
to: to,
toName: toName,
auto: byAuto || false,
date: date,
resign: resign,
student: student || false
}, this.model, noProcess, noAction);
def.resolveWith(data);
}
}, queryFail, false, {
"Cookie": cookie,
"If-Modified-Since": "0"
});
};
var fetchTicketUrl = function () {
ajax.sendGet("leftTicket/init", "/otn/", null, "text")
.done(function () {
var html = this.model;
dynamicjs.checkDynamicJs(html, "leftTicket/init");
var r = /(CLeftTicketUrl|isSaveQueryLog)\s*=\s*['"]([^'"]+)['"]/gi;
var m;
while (m = r.exec(html)) {
if (m[1] === "CLeftTicketUrl")
queryTicketUrl = m[2];
else if (m[1] === "isSaveQueryLog")
isLogOpen = m[2] === "Y";
}
if (!queryTicketUrl) {
document.dispatchEvent(new CustomEvent("platformError"));
def.reject("未能初始化查询地址");
}
else postFetchTicketUrl();
}).fail(function () {
def.reject("网络错误");
});
};
var postFetchTicketUrl = function () {
//加载查询页之后,必须要加载一次联系人,否则妥妥地出票失败。这傻逼逻辑啊。。
if (sessmgr.isLogined) {
sessmgr.reloadPassengers();
sessmgr.getPassengers().always(sendQueryRequest);
} else {
sendQueryRequest();
}
};
if (queryTicketUrl) {
sendQueryRequest();
}
else {
fetchTicketUrl();
}
return def.promise();
};
exports.log = function (data, cookies, force) {
var def = new $.Deferred();
if (!isLogOpen || ((lastLogTime && (new Date() - lastLogTime) < 5000) && !force)) {
def.reject();
return def.promise();
}
lastLogTime = new Date();
ajax.sendGet("leftTicket/log", "leftTicket/init", data, "json", function () {
def.resolve();
}, function () {
def.reject();
}, false, {
"Cookie": cookies
});
return def.promise();
};
exports.queryTrainStop = function (id, from, to, date) {
var data = {
train_no: id,
from_station_telecode: from,
to_station_telecode: to,
depart_date: date
};
var def = new $.Deferred();
ajax.sendGet("czxx/queryByTrainNo", "leftTicket/init", data, "json", function (json) {
if (!json || !json.data || !json.data.data) {
def.reject((parser.getError(json) || { message: "查询失败" }).message);
} else {
def.resolve(json.data.data);
}
}, function () {
def.reject("网络错误");
});
return def.promise();
};
});