JavaScript代码
(async function ctexcelSmallTopup() {
'use strict';
const inputAmount = prompt('请输入充值金额(例如 0.01 或 10):');
if (inputAmount === null) return;
const AMOUNT = inputAmount.trim();
const RUN_KEY = '__ctexcelSmallTopupRunning';
function pennies(value) {
if (!/^(?:0|[1-9]\d*)(?:\.\d{1,2})?$/.test(String(value))) {
return NaN;
}
const [whole, fraction = ''] = String(value).split('.');
return Number(whole) * 100 + Number(fraction.padEnd(2, '0'));
}
function verifyPreview(response, expected) {
if (!response || String(response.code) !== '0') {
throw new Error(
`接口拒绝请求:${response?.code ?? '未知代码'} ${
response?.message ?? ''
}`
);
}
const info = response.data;
if (!info || typeof info !== 'object' || Array.isArray(info)) {
throw new Error('接口没有返回有效充值预览。');
}
console.info('服务器预览结果:', {
号码状态: info.slrStatus,
充值金额: info.subtotal
});
if (
['-1', '-2', '-3', '-4', '-5'].includes(
String(info.slrStatus)
)
) {
throw new Error(
`官网返回异常号码状态:${info.slrStatus},停止。`
);
}
if (
info.subtotal == null ||
pennies(info.subtotal) !== expected
) {
throw new Error(`服务器返回的金额不是 £${AMOUNT},停止。`);
}
for (const field of [
'rechargeAmount',
'totalAmount',
'orderPrice'
]) {
if (
info[field] != null &&
pennies(info[field]) !== expected
) {
throw new Error(`返回金额字段 ${field} 不一致,停止。`);
}
}
return info;
}
let ownRun = false;
try {
if (
location.origin !== 'https://www.ctexcel.com' ||
location.pathname !== '/uk/recharge/prepaid'
) {
throw new Error(
'请先打开 https://www.ctexcel.com/uk/recharge/prepaid'
);
}
const expected = pennies(AMOUNT);
if (
!Number.isSafeInteger(expected) ||
expected < 1 ||
expected > 50000
) {
throw new Error('金额必须为 £0.01–£500.00,最多两位小数。');
}
if (window[RUN_KEY]) {
throw new Error('已有预览请求正在进行,请等待结果。');
}
window[RUN_KEY] = true;
ownRun = true;
const visibleInput = placeholder =>
[...document.querySelectorAll('input')].find(
el =>
el.placeholder === placeholder &&
el.getClientRects().length
);
const msisdn =
visibleInput('CTExcel number')?.value.trim() ||
visibleInput('手机号码')?.value.trim() ||
prompt(
'请输入你自己的 CTExcel 英国号码(不是中国副号):'
)?.trim();
const email =
visibleInput('Please enter your email')?.value.trim() ||
[...document.querySelectorAll('input')]
.find(
el =>
/邮箱/.test(el.placeholder) &&
el.getClientRects().length
)
?.value.trim() ||
prompt('请输入用于本次充值的邮箱:')?.trim();
if (!msisdn || !/^\d{10,12}$/.test(msisdn)) {
throw new Error(
'号码应为 10–12 位数字,请使用官网接受的号码格式。'
);
}
if (
!email ||
!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
) {
throw new Error('邮箱为空或格式不正确。');
}
const entry = [
...document.querySelectorAll('script[type="module"][src]')
].find(el =>
/^https:\/\/www\.ctexcel\.com\/uk\/js\/app\.[^/]+\.js$/.test(
el.src
)
);
if (!entry) {
throw new Error(
'找不到官网模块,请等待页面完整加载后再试。'
);
}
const officialModule = await import(entry.src);
const http = officialModule.z;
const api = officialModule.P;
const previewURL =
'https://www.ctexcel.com/newcteuk/recharge/onlineRechargeDetail';
if (
typeof http?.post !== 'function' ||
api?.onlineRechargeDetail !== previewURL
) {
throw new Error('官网模块接口已变化,停止。');
}
console.info(
`正在请求 £${AMOUNT} 充值预览;未提交付款订单。`
);
const response = await new Promise((resolve, reject) => {
const timer = setTimeout(
() =>
reject(
new Error(
'未收到可用预览结果。请查看官网提示;请求可能已到达服务器,请勿反复提交。'
)
),
35000
);
const finish = callback => value => {
clearTimeout(timer);
callback(value);
};
try {
http.post(
previewURL,
{
msisdn,
rechargeType: 1,
rechargeAmount: AMOUNT,
email
},
finish(resolve),
finish(reject)
);
} catch (error) {
clearTimeout(timer);
reject(error);
}
});
const info = verifyPreview(response, expected);
function normalizeUKPhone(value) {
let phone = String(value ?? '').replace(/\D/g, '');
if (phone.startsWith('0044')) {
phone = '0' + phone.slice(4);
} else if (phone.startsWith('44')) {
phone = '0' + phone.slice(2);
} else if (/^7\d{9}$/.test(phone)) {
phone = '0' + phone;
}
return phone;
}
const phoneMatches =
info.msisdn != null &&
normalizeUKPhone(info.msisdn) === normalizeUKPhone(msisdn);
const emailMatches =
info.email != null &&
String(info.email).trim() === email.trim();
console.info('返回信息核对:', {
服务器金额: info.subtotal,
是否返回号码: info.msisdn != null,
号码统一格式后是否一致: phoneMatches,
是否返回邮箱: info.email != null,
邮箱是否一致: emailMatches
});
if (!phoneMatches) {
throw new Error('服务器返回的号码不匹配,停止。');
}
if (info.email != null && !emailMatches) {
throw new Error('服务器返回的邮箱不匹配,停止。');
}
if (info.email == null) {
info.email = email;
}
console.info(
`服务器预览金额为 £${AMOUNT},进入确认页后请再次核对金额。`
);
sessionStorage.setItem(
'rechargeInfos',
JSON.stringify(info)
);
location.assign(
'https://www.ctexcel.com/uk/recharge/confirm'
);
} catch (error) {
console.error(
'充值预览已停止:',
error instanceof Error ? error.message : String(error)
);
} finally {
if (ownRun) {
window[RUN_KEY] = false;
}
}
})();