之前一直用的额度统计脚本今天突然用不了 额度换算出来都是0

问gpt说是官方接口的 totals、clients 还是 models,**credits 全部精确等于 0.0
让gpt5.6调试了一下搞了一个新脚本出来 亲测可用 (不建议用了不是很精准)

(async () => {
"use strict";
// ============================================================
// Codex Quota Compass V2.3
// 多模型费率反校正版 · 纯实测 · 无套餐倍率
//
// 数据来源:
//
// 1. /backend-api/wham/usage
// -> 实时 weekly used_percent / reset
//
// 2. /backend-api/wham/usage/daily-token-usage-breakdown
// -> 每天每个模型消耗的 allowance 百分点
//
// 3. /backend-api/wham/analytics/daily-workspace-usage-counts
// -> 每日总 uncached / cached / output token
// -> 每模型 turns(只展示,不用于价格分配)
//
// 个人账号没有 per-model token breakdown。
//
// 多模型日算法:
//
// 当天 Token 结构:
// fu = uncached / total
// fc = cached / total
// fo = output / total
//
// 模型综合费率:
// Rm = fu * inputRate
// + fc * cachedRate
// + fo * outputRate
//
// OpenAI 给出的该模型 allowance 百分点 = Pm
//
// Token 权重:
// Wm = Pm / Rm
//
// 模型 Token share:
// Sm = Wm / sum(W)
//
// 再按 Sm 分配当天三类总 Token。
//
// 这样可以保证昂贵模型不会因为 quota 占比高
// 就被错误分配同样比例的 Token。
//
// 注意:
// - 完全没有 Plus×1 / ProLite×5 / Pro×20
// - plan_type 只显示
// - 忽略 >272K long-context multiplier
// - 所有价格始终使用基础 Token 单价
// ============================================================
const CONFIG = {
HISTORY_DAYS: 45,
USD_PER_CREDIT: 0.04,
// allowance 百分比太小的日子容易受统计舍入影响。
MIN_DAY_PERCENT: 0.10,
// 同一周期多个反推结果的允许离散。
CLUSTER_TOLERANCE: 0.10,
// ==========================================================
// OpenAI 基础 API / ChatGPT Work Token rate card
// USD / 1M tokens
//
// 按用户要求:
// 不考虑 >272K context 的 2x / 1.5x 加价。
// ==========================================================
MODEL_RATES: {
"gpt-6-astra": {
input: 10.00,
cached: 1.00,
output: 50.00,
},
"gpt-5.6-sol": {
input: 4.00,
cached: 0.40,
output: 20.00,
},
"gpt-5.6-terra": {
input: 2.00,
cached: 0.20,
output: 12.00,
},
"gpt-5.6-luna": {
input: 0.20,
cached: 0.02,
output: 1.20,
},
"gpt-5.5": {
input: 5.00,
cached: 0.50,
output: 30.00,
},
"gpt-5.4": {
input: 2.50,
cached: 0.25,
output: 15.00,
},
"gpt-5.4-mini": {
input: 0.75,
cached: 0.075,
output: 4.50,
},
"gpt-5.3-codex": {
input: 1.75,
cached: 0.175,
output: 14.00,
},
"gpt-5.2": {
input: 1.75,
cached: 0.175,
output: 14.00,
},
"daybreak-blue": {
input: 4.00,
cached: 0.40,
output: 20.00,
},
"daybreak-red": {
input: 12.50,
cached: 1.25,
output: 75.00,
},
},
};
// ============================================================
// 基础工具
// ============================================================
const n = (v) => {
const x = Number(v);
return Number.isFinite(x) ? x : 0;
};
const clamp = (v, min, max) =>
Math.min(max, Math.max(min, v));
const fmtMoney = (v) =>
Number.isFinite(v)
? `$${v.toFixed(2)}`
: "—";
const fmtPct = (v, d = 3) =>
Number.isFinite(v)
? `${v.toFixed(d)}%`
: "—";
const fmtNum = (v) => {
if (!Number.isFinite(v)) return "—";
if (v >= 1e9)
return `${(v / 1e9).toFixed(2)}B`;
if (v >= 1e6)
return `${(v / 1e6).toFixed(2)}M`;
if (v >= 1e3)
return `${(v / 1e3).toFixed(2)}K`;
return Math.round(v).toLocaleString();
};
const dayKey = (ms) =>
new Date(ms).toISOString().slice(0, 10);
const addDays = (key, days) => {
const d = new Date(`${key}T00:00:00Z`);
d.setUTCDate(d.getUTCDate() + days);
return d.toISOString().slice(0, 10);
};
function median(values) {
const a = values
.filter(Number.isFinite)
.sort((x, y) => x - y);
if (!a.length) return null;
const i = Math.floor(a.length / 2);
return a.length % 2
? a[i]
: (a[i - 1] + a[i]) / 2;
}
// ============================================================
// Auth
// ============================================================
function getAccessToken() {
const boot =
document.getElementById("client-bootstrap")
?.textContent || "";
return (
boot.match(
/[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}/
)?.[0] || null
);
}
async function apiGet(path, token) {
const res = await fetch(path, {
credentials: "include",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json",
},
});
const text = await res.text();
if (!res.ok) {
throw new Error(
`HTTP ${res.status}: ${text.slice(0, 300)}`
);
}
return JSON.parse(text);
}
// ============================================================
// Model helpers
// ============================================================
function normalizeModel(model) {
return String(model || "")
.trim()
.toLowerCase();
}
function getRate(model, speed = "standard") {
// 这里故意不把 Fast 套用 Standard 价格。
// 当前脚本只精确处理 standard。
if (speed && speed !== "standard") {
return null;
}
return (
CONFIG.MODEL_RATES[
normalizeModel(model)
] || null
);
}
function getModelTurns(countRow) {
const result = new Map();
for (const m of countRow?.models || []) {
const model = normalizeModel(m.model);
result.set(
model,
(result.get(model) || 0) +
n(m.turns)
);
}
return result;
}
// ============================================================
// 多模型反向分配
// ============================================================
function estimateDay(countRow, pctRow) {
const totals = countRow?.totals;
if (!totals) {
return {
valid: false,
reason: "Token 尚未结算",
};
}
const uncached =
n(totals.uncached_text_input_tokens);
const cached =
n(totals.cached_text_input_tokens);
const output =
n(totals.text_output_tokens);
const total =
uncached + cached + output;
if (!(total > 0)) {
return {
valid: false,
reason: "无 Token",
};
}
// 当天 Token 类型结构。
const fu = uncached / total;
const fc = cached / total;
const fo = output / total;
const modelRows = (pctRow?.models || [])
.map((m) => ({
model: normalizeModel(m.model),
speed: m.speed || "standard",
percent: n(m.credits),
}))
.filter((m) => m.percent > 0);
const totalPercent =
modelRows.reduce(
(sum, m) => sum + m.percent,
0
);
if (!(totalPercent > 0)) {
return {
valid: false,
reason: "无 allowance 百分比",
};
}
if (
totalPercent <
CONFIG.MIN_DAY_PERCENT
) {
return {
valid: false,
reason: "allowance 样本太小",
};
}
const turns =
getModelTurns(countRow);
const priced = [];
const unknown = [];
for (const m of modelRows) {
const rate =
getRate(m.model, m.speed);
if (!rate) {
unknown.push(m);
continue;
}
// 当前一天的综合费率。
// USD / 1M “当天平均结构 Token”
const compositeRate =
fu * rate.input +
fc * rate.cached +
fo * rate.output;
if (!(compositeRate > 0)) {
continue;
}
priced.push({
...m,
rate,
compositeRate,
// 关键:
//
// quota share ≈ token * price
//
// 所以:
//
// token weight ≈ quota share / price
tokenWeight:
m.percent /
compositeRate,
});
}
if (!priced.length) {
return {
valid: false,
reason: "当天模型价格均未知",
};
}
const knownPct =
priced.reduce(
(sum, m) => sum + m.percent,
0
);
// 为了避免未知模型偷偷导致金额偏低,
// 只有所有 allowance 都能定价时
// 才允许用于周额度反推。
const coverage =
knownPct / totalPercent;
if (coverage < 0.999) {
return {
valid: false,
reason:
`价格覆盖仅 ${(coverage * 100).toFixed(2)}%`,
unknown,
};
}
const weightTotal =
priced.reduce(
(sum, m) =>
sum + m.tokenWeight,
0
);
if (!(weightTotal > 0)) {
return {
valid: false,
reason: "无法计算 Token 权重",
};
}
let dayUsd = 0;
const allocatedModels =
priced.map((m) => {
const share =
m.tokenWeight /
weightTotal;
// 假设各模型当天 uncached/cache/output
// 结构与当天总结构一致。
//
// 个人接口没有更细的数据,
// 这是必要的估算假设。
const mu =
uncached * share;
const mc =
cached * share;
const mo =
output * share;
const modelUsd =
(mu / 1e6) *
m.rate.input +
(mc / 1e6) *
m.rate.cached +
(mo / 1e6) *
m.rate.output;
dayUsd += modelUsd;
return {
model: m.model,
speed: m.speed,
allowancePercent:
m.percent,
turns:
turns.get(m.model) || 0,
tokenShare:
share,
uncached:
mu,
cached:
mc,
output:
mo,
totalTokens:
mu + mc + mo,
compositeRate:
m.compositeRate,
usd:
modelUsd,
};
});
// ==========================================================
// 一整份 allowance 的等价美元价值
// ==========================================================
const allowanceUsd =
dayUsd /
(totalPercent / 100);
return {
valid: true,
date:
countRow.date,
totalPercent,
uncached,
cached,
output,
totalTokens:
total,
dayUsd,
allowanceUsd,
models:
allocatedModels,
estimatedAllocation:
allocatedModels.length > 1,
unknown,
};
}
// ============================================================
// 合并 daily 两个接口
// ============================================================
function buildDays(counts, percents) {
const countMap =
new Map(
(counts?.data || []).map(
(x) => [x.date, x]
)
);
const pctMap =
new Map(
(percents?.data || []).map(
(x) => [x.date, x]
)
);
const dates = [
...new Set([
...countMap.keys(),
...pctMap.keys(),
]),
].sort();
return dates.map((date) => {
const count =
countMap.get(date) || null;
const pct =
pctMap.get(date) || null;
const result =
estimateDay(count, pct);
return {
date,
count,
pct,
...result,
};
});
}
// ============================================================
// 当前周期额度聚合
// ============================================================
function estimateCycle(rows) {
const usable =
rows.filter(
(r) =>
r.valid &&
Number.isFinite(r.allowanceUsd) &&
r.allowanceUsd > 0
);
if (!usable.length) {
return null;
}
if (usable.length === 1) {
return {
value:
usable[0].allowanceUsd,
samples: 1,
spread: 0,
rows: usable,
};
}
const initial =
median(
usable.map(
(r) => r.allowanceUsd
)
);
const cluster =
usable.filter(
(r) =>
Math.abs(
r.allowanceUsd -
initial
) /
initial <=
CONFIG.CLUSTER_TOLERANCE
);
if (!cluster.length) {
return null;
}
// 按当天消耗百分比加权。
// 额度消耗越大的日子统计误差通常越小。
const weight =
cluster.reduce(
(sum, r) =>
sum + r.totalPercent,
0
);
const weighted =
cluster.reduce(
(sum, r) =>
sum +
r.allowanceUsd *
r.totalPercent,
0
) / weight;
const values =
cluster.map(
(r) => r.allowanceUsd
);
const spread =
values.length > 1
? (
Math.max(...values) -
Math.min(...values)
) /
weighted
: 0;
return {
value: weighted,
samples:
cluster.length,
spread,
dropped:
usable.length -
cluster.length,
rows:
cluster,
};
}
// ============================================================
// UI
// ============================================================
function addStyle() {
document
.getElementById(
"cqv23-style"
)
?.remove();
const style =
document.createElement("style");
style.id = "cqv23-style";
style.textContent = `
#cqv23 {
position: fixed;
top: 2vh;
left: 50%;
transform: translateX(-50%);
width: min(1180px, calc(100vw - 24px));
max-height: 96vh;
overflow: auto;
z-index: 2147483647;
background: white;
color: #222;
border: 1px solid #ddd;
border-radius: 14px;
padding: 20px;
box-shadow:
0 18px 70px rgba(0,0,0,.28);
font-family:
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
sans-serif;
}
#cqv23 * {
box-sizing: border-box;
}
#cqv23 .head {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 14px;
}
#cqv23 .title {
font-size: 19px;
font-weight: 700;
}
#cqv23 .close {
font-size: 28px;
cursor: pointer;
color: #888;
}
#cqv23 .cards {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 10px;
margin-bottom: 14px;
}
#cqv23 .card {
border: 1px solid #ececec;
background: #f7f7f7;
border-radius: 9px;
padding: 11px;
}
#cqv23 .card.good {
background: #eefaf5;
border-color: #cfeee1;
}
#cqv23 .card.used {
background: #fff8ea;
border-color: #f4dfad;
}
#cqv23 .label {
color: #777;
font-size: 11px;
margin-bottom: 5px;
}
#cqv23 .value {
font-size: 16px;
font-weight: 750;
color: #0f8f70;
white-space: nowrap;
}
#cqv23 .card.used .value {
color: #a35d00;
}
#cqv23 .sub {
color: #777;
font-size: 10px;
margin-top: 4px;
}
#cqv23 .note {
background: #fafafa;
border: 1px solid #eee;
border-radius: 8px;
padding: 10px 12px;
margin-bottom: 14px;
font-size: 12px;
line-height: 1.6;
color: #555;
}
#cqv23 .tablebox {
max-height: 390px;
overflow: auto;
border: 1px solid #eee;
border-radius: 8px;
margin-bottom: 14px;
}
#cqv23 table {
width: 100%;
border-collapse: collapse;
font-size: 11px;
}
#cqv23 th,
#cqv23 td {
padding: 7px 6px;
border-bottom: 1px solid #eee;
text-align: left;
white-space: nowrap;
}
#cqv23 th {
position: sticky;
top: 0;
z-index: 1;
background: #f5f5f5;
color: #666;
}
#cqv23 .goodtext {
color: #0f8f70;
font-weight: 600;
}
#cqv23 .warn {
color: #a35d00;
}
#cqv23 .muted {
color: #999;
}
#cqv23 details {
margin-top: 5px;
}
#cqv23 summary {
cursor: pointer;
}
@media(max-width: 900px) {
#cqv23 .cards {
grid-template-columns: repeat(3,1fr);
}
}
`;
document.head.appendChild(style);
}
function render({
usage,
rows,
cycleStartDate,
estimate,
}) {
document
.getElementById("cqv23")
?.remove();
addStyle();
const root =
document.createElement("div");
root.id = "cqv23";
const window =
usage?.rate_limit
?.secondary_window ||
usage?.rate_limit
?.primary_window;
const livePercent =
clamp(
n(window?.used_percent),
0,
100
);
const weeklyUsd =
estimate?.value ?? null;
const usedUsd =
weeklyUsd != null
? weeklyUsd *
livePercent /
100
: null;
const leftUsd =
weeklyUsd != null
? weeklyUsd - usedUsd
: null;
const weeklyCredits =
weeklyUsd != null
? weeklyUsd /
CONFIG.USD_PER_CREDIT
: null;
const usedCredits =
usedUsd != null
? usedUsd /
CONFIG.USD_PER_CREDIT
: null;
const currentRows =
rows.filter(
(r) =>
r.date >= cycleStartDate
);
const settledPct =
currentRows.reduce(
(sum, r) =>
sum + n(r.totalPercent),
0
);
const rowsHtml =
[...rows]
.sort(
(a, b) =>
b.date.localeCompare(a.date)
)
.map((r) => {
const current =
r.date >= cycleStartDate;
if (!r.valid) {
return `
<tr>
<td>${current ? "● " : ""}${r.date}</td>
<td>${fmtPct(
(r.pct?.models || [])
.reduce(
(s,m) => s+n(m.credits),
0
)
)}</td>
<td colspan="4" class="muted">
${r.reason || "无可用数据"}
</td>
</tr>
`;
}
const modelText =
r.models
.map(
(m) =>
`${m.model.replace("gpt-","")} ` +
`${fmtPct(m.allowancePercent)}`
)
.join(" / ");
return `
<tr>
<td>
${current ? "● " : ""}
${r.date}
</td>
<td>
${fmtPct(r.totalPercent)}
</td>
<td>
${modelText}
</td>
<td>
${fmtNum(r.totalTokens)}
</td>
<td>
${fmtMoney(r.dayUsd)}
</td>
<td class="goodtext">
${fmtMoney(r.allowanceUsd)}
${
r.estimatedAllocation
? " ≈"
: ""
}
</td>
</tr>
`;
})
.join("");
const modelDetails =
currentRows
.filter((r) => r.valid)
.flatMap((r) =>
r.models.map((m) => ({
date: r.date,
...m,
}))
)
.map(
(m) => `
<tr>
<td>${m.date}</td>
<td>${m.model.replace("gpt-","")}</td>
<td>${m.turns}</td>
<td>${fmtPct(m.allowancePercent)}</td>
<td>${(m.tokenShare * 100).toFixed(2)}%</td>
<td>${fmtNum(m.uncached)}</td>
<td>${fmtNum(m.cached)}</td>
<td>${fmtNum(m.output)}</td>
<td>${fmtNum(m.totalTokens)}</td>
<td>${fmtMoney(m.usd)}</td>
</tr>
`
)
.join("");
root.innerHTML = `
<div class="head">
<div class="title">
📊 Codex Quota Compass V2.3 · 多模型费率反校正
</div>
<div
class="close"
id="cqv23-close"
>
×
</div>
</div>
<div class="cards">
<div class="card">
<div class="label">
当前计划
</div>
<div class="value">
${usage?.plan_type || "unknown"}
</div>
<div class="sub">
仅展示,不参与任何额度计算
</div>
</div>
<div class="card">
<div class="label">
实时周额度已用
</div>
<div class="value">
${livePercent.toFixed(1)}%
</div>
<div class="sub">
每日接口已结算 ${settledPct.toFixed(3)}%
</div>
</div>
<div class="card good">
<div class="label">
当前完整周额度
</div>
<div class="value">
${
weeklyUsd != null
? fmtMoney(weeklyUsd)
: "等待当天 Token"
}
</div>
<div class="sub">
${
estimate
? `${estimate.samples} 个当前周期真实日样本`
: "无套餐倍率 / 无历史兜底"
}
</div>
</div>
<div class="card used">
<div class="label">
本周已用等价价值
</div>
<div class="value">
${
usedUsd != null
? fmtMoney(usedUsd)
: "—"
}
</div>
<div class="sub">
${
usedCredits != null
? `${fmtNum(usedCredits)} Credits eq.`
: "—"
}
</div>
</div>
<div class="card">
<div class="label">
本周剩余等价价值
</div>
<div class="value">
${
leftUsd != null
? fmtMoney(leftUsd)
: "—"
}
</div>
</div>
<div class="card">
<div class="label">
周总等价 Credits
</div>
<div class="value">
${
weeklyCredits != null
? fmtNum(weeklyCredits)
: "—"
}
</div>
<div class="sub">
$0.04 / Credit 仅作换算展示
</div>
</div>
</div>
<div class="note">
<b>算法:</b>
多模型日期不会再被丢弃,也不会简单按调用次数或额度百分比直接分 Token。
脚本先用当天真实 uncached / cached / output 结构计算每个模型的
<b>综合 API 费率</b>,再按照
<code>模型 allowance% ÷ 综合费率</code>
反向估算模型 Token 权重。
<br><br>
每模型的 <b>turns 是接口真实调用轮数</b>,
但不会拿 turns 直接计价,因为不同调用的 Token 长度差异可能极大。
<br>
混模日的 per-model Token 属于
<b>费率校正估算</b>;
当天只有一个模型时,三类 Token 则无需分配,属于直接值。
<br>
<b>长上下文加价已完全忽略。</b>
无论单次请求是否超过 272K,本脚本都只使用基础 API Token rate card。
</div>
<div class="tablebox">
<table>
<thead>
<tr>
<th>日期</th>
<th>Allowance%</th>
<th>模型占比</th>
<th>总 Tokens</th>
<th>当日等价$</th>
<th>反推完整周$</th>
</tr>
</thead>
<tbody>
${rowsHtml}
</tbody>
</table>
</div>
<details>
<summary>
🤖 查看当前周期各模型估算用量
</summary>
<div class="tablebox" style="margin-top:8px">
<table>
<thead>
<tr>
<th>日期</th>
<th>模型</th>
<th>实际 Turns</th>
<th>Allowance%</th>
<th>估算 Token 占比</th>
<th>未缓存输入</th>
<th>缓存输入</th>
<th>输出</th>
<th>总 Token</th>
<th>等价$</th>
</tr>
</thead>
<tbody>
${
modelDetails ||
`<tr>
<td colspan="10" class="muted">
当前周期 Token 尚未结算
</td>
</tr>`
}
</tbody>
</table>
</div>
</details>
<div class="note" style="margin-top:14px;margin-bottom:0">
当前周期开始:
<b>${cycleStartDate}</b>
${
estimate
? `
<br>
当前周期有效样本:
<b>${estimate.samples}</b> 天;
完整周额度:
<b>${fmtMoney(estimate.value)}</b>;
样本离散:
<b>${(estimate.spread * 100).toFixed(2)}%</b>。
`
: `
<br>
当前周期目前没有同时拥有
<b>日 Token + 日 allowance%</b>
的完整样本,因此还无法确定分母。
这不是套餐倍率问题,而是当天 Token 数据尚未落库。
`
}
</div>
`;
document.body.appendChild(root);
document
.getElementById("cqv23-close")
.onclick = () => {
root.remove();
document
.getElementById("cqv23-style")
?.remove();
};
}
// ============================================================
// MAIN
// ============================================================
try {
console.log(
"[Quota Compass V2.3] 获取登录信息..."
);
const token =
getAccessToken();
if (!token) {
throw new Error(
"无法取得 ChatGPT access token"
);
}
const usage =
await apiGet(
"/backend-api/wham/usage",
token
);
const window =
usage?.rate_limit
?.secondary_window ||
usage?.rate_limit
?.primary_window;
if (!window) {
throw new Error(
"没有找到 weekly rate limit window"
);
}
const now = Date.now();
const today =
dayKey(now);
const startDate =
dayKey(
now -
CONFIG.HISTORY_DAYS *
86400000
);
const endDate =
addDays(today, 1);
const range =
`start_date=${encodeURIComponent(startDate)}` +
`&end_date=${encodeURIComponent(endDate)}` +
`&group_by=day`;
const cycleStartMs =
(
n(window.reset_at) -
n(window.limit_window_seconds)
) * 1000;
const cycleStartDate =
dayKey(cycleStartMs);
console.log(
"[Quota Compass V2.3] 当前周期:",
cycleStartDate
);
const [
counts,
percents,
] = await Promise.all([
apiGet(
"/backend-api/wham/analytics/" +
"daily-workspace-usage-counts?" +
range +
"&workspace_user=true",
token
),
apiGet(
"/backend-api/wham/usage/" +
"daily-token-usage-breakdown?" +
range,
token
),
]);
const rows =
buildDays(
counts,
percents
);
const currentRows =
rows.filter(
(r) =>
r.date >= cycleStartDate
);
const estimate =
estimateCycle(
currentRows
);
console.table(
rows
.filter(
(r) =>
r.valid ||
(
r.pct?.models ||
[]
).some(
(m) =>
n(m.credits) > 0
)
)
.map((r) => ({
date:
r.date,
current:
r.date >= cycleStartDate,
allowance_pct:
r.totalPercent || 0,
tokens:
r.totalTokens || 0,
day_usd:
r.dayUsd
? +r.dayUsd.toFixed(3)
: null,
full_week_usd:
r.allowanceUsd
? +r.allowanceUsd.toFixed(2)
: null,
result:
r.valid
? (
r.estimatedAllocation
? "费率校正"
: "单模型直接值"
)
: r.reason,
}))
);
if (estimate) {
const live =
clamp(
n(window.used_percent),
0,
100
);
console.log(
"====== 当前周实测 ======"
);
console.log(
"周额度 API 等价价值:",
estimate.value
);
console.log(
"实时已用:",
live + "%"
);
console.log(
"本周已用等价价值:",
estimate.value *
live /
100
);
console.log(
"本周剩余等价价值:",
estimate.value *
(
1 -
live /
100
)
);
}
render({
usage,
rows,
cycleStartDate,
estimate,
});
console.log(
"[Quota Compass V2.3] ✅ 完成"
);
} catch (e) {
console.error(
"[Quota Compass V2.3]",
e
);
alert(
"Quota Compass V2.3 失败:\n\n" +
(
e?.message ||
String(e)
)
);
}
})();