逻辑:U(用量)/ 使用配额占账号百分比

开发过程:

// ==UserScript==
// @name Sub2API 账号周限额预估
// @namespace https://example.invalid/sub2api-userscripts
// @version 1.2.0
// @description 在账号管理页根据周用户扣费和周配额占用比例显示预估周限额
// @match *://*/admin/accounts*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
// ==================== 在这里添加适配域名 ====================
// 添加方法:
// 1. 每行填写一个域名,并用英文逗号结尾。
// 2. 只填写域名,不要包含 http://、https://、端口或页面路径。
// 3. 需要添加多个域名时,照着下面的格式继续增加新行即可。
// 4. 下方均为示例域名,安装后请替换成自己的 Sub2API 域名。
const TARGET_HOSTS = [
'sub2api.example.com',
// 'sub2api-2.example.net',
// 'sub2api-3.example.org',
];
// ==================== 域名配置结束 ====================
if (!TARGET_HOSTS.includes(location.hostname)) return;
const MARKER_CLASS = 'tm-estimated-weekly-limit';
const USD_FORMATTER = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
function readNumber(text) {
const match = text.replaceAll(',', '').match(/-?\d+(?:\.\d+)?/);
return match ? Number(match[0]) : Number.NaN;
}
function findWeeklyBadge() {
return [...document.querySelectorAll('table tbody td span')]
.filter((span) => span.textContent.trim() === '7d');
}
function updateWeeklyLimit(weeklyBadge) {
const progressRow = weeklyBadge.parentElement;
const weeklyBlock = progressRow?.parentElement;
if (!progressRow || !weeklyBlock) return;
const userCostElement = [...weeklyBlock.querySelectorAll('span')].find((span) =>
span.title === '用户扣费' || /^\s*U\s*\$/.test(span.textContent),
);
const percentElement = [...progressRow.querySelectorAll('span')].find((span) =>
/^\d+(?:\.\d+)?%$/.test(span.textContent.trim()),
);
const existing = progressRow.querySelector(`.${MARKER_CLASS}`);
const userCost = userCostElement ? readNumber(userCostElement.textContent) : Number.NaN;
const percent = percentElement ? readNumber(percentElement.textContent) : Number.NaN;
if (!Number.isFinite(userCost) || !Number.isFinite(percent) || userCost <= 0 || percent <= 0) {
existing?.remove();
return;
}
const estimatedLimit = userCost / (percent / 100);
const formattedLimit = USD_FORMATTER.format(estimatedLimit);
const label = `周限额(预估)${formattedLimit}`;
const title = `按页面显示值估算:U $${userCost.toFixed(2)} ÷ ${percent}% = ${formattedLimit};页面百分比经过取整,结果仅供参考。`;
const limitElement = existing || document.createElement('span');
limitElement.className = `${MARKER_CLASS} shrink-0 text-[10px] font-medium text-gray-500 dark:text-gray-400`;
if (limitElement.textContent !== label) limitElement.textContent = label;
limitElement.title = title;
limitElement.dataset.estimatedWeeklyLimit = String(estimatedLimit);
if (!existing) progressRow.append(limitElement);
}
function updateAll() {
findWeeklyBadge().forEach(updateWeeklyLimit);
}
let updateQueued = false;
function queueUpdate() {
if (updateQueued) return;
updateQueued = true;
requestAnimationFrame(() => {
updateQueued = false;
updateAll();
});
}
const observer = new MutationObserver(queueUpdate);
observer.observe(document.documentElement, {
childList: true,
subtree: true,
characterData: true,
});
updateAll();
})();