feat: support manual HeroSMS maxPrice and defer phone reuse confirmation until final flow success

- 合并 PR #170 的核心改动:新增 HeroSMS 手动 maxPrice 配置,并调整手机号验证链路直接按手填价格取号
- 本地补充修复:吸收延后确认手机号复用计数、仅在整轮成功后提交 pending activation,以及保留 fresh reset 后的可复用号码状态
- 影响范围:background phone verification flow、platform-verify success cleanup、auto-run fresh reset、sidepanel phone verification settings
This commit is contained in:
markyal
2026-04-28 22:03:27 +08:00
committed by GitHub
13 changed files with 599 additions and 389 deletions
+5
View File
@@ -425,6 +425,11 @@
<option value="52" selected>Thailand</option>
</select>
</div>
<div class="data-row" id="row-hero-sms-max-price" style="display:none;">
<span class="data-label">最高价格</span>
<input type="number" id="input-hero-sms-max-price" class="data-input mono" min="0.0001" step="0.0001" required
placeholder="必填,例如 0.08" />
</div>
<div class="data-row" id="row-hero-sms-api-key" style="display:none;">
<span class="data-label">接码 API</span>
<div class="input-with-icon">
+34 -1
View File
@@ -292,8 +292,10 @@ const rowPhoneVerificationEnabled = document.getElementById('row-phone-verificat
const inputPhoneVerificationEnabled = document.getElementById('input-phone-verification-enabled');
const rowHeroSmsPlatform = document.getElementById('row-hero-sms-platform');
const rowHeroSmsCountry = document.getElementById('row-hero-sms-country');
const rowHeroSmsMaxPrice = document.getElementById('row-hero-sms-max-price');
const rowHeroSmsApiKey = document.getElementById('row-hero-sms-api-key');
const inputHeroSmsApiKey = document.getElementById('input-hero-sms-api-key');
const inputHeroSmsMaxPrice = document.getElementById('input-hero-sms-max-price');
const selectHeroSmsCountry = document.getElementById('select-hero-sms-country');
const displayHeroSmsPlatform = document.getElementById('display-hero-sms-platform');
const rowAccountRunHistoryHelperBaseUrl = document.getElementById('row-account-run-history-helper-base-url');
@@ -2220,6 +2222,9 @@ function collectSettingsPayload() {
const heroSmsApiKeyValue = typeof inputHeroSmsApiKey !== 'undefined' && inputHeroSmsApiKey
? (inputHeroSmsApiKey.value || '')
: '';
const heroSmsMaxPriceValue = typeof inputHeroSmsMaxPrice !== 'undefined' && inputHeroSmsMaxPrice
? normalizeHeroSmsMaxPriceValue(inputHeroSmsMaxPrice.value)
: '';
const heroSmsCountry = typeof getSelectedHeroSmsCountryOption === 'function'
? getSelectedHeroSmsCountryOption()
: {
@@ -2323,6 +2328,7 @@ function collectSettingsPayload() {
DEFAULT_VERIFICATION_RESEND_COUNT
),
heroSmsApiKey: heroSmsApiKeyValue,
heroSmsMaxPrice: heroSmsMaxPriceValue,
heroSmsCountryId: heroSmsCountry.id,
heroSmsCountryLabel: heroSmsCountry.label,
};
@@ -2381,6 +2387,18 @@ function normalizeHeroSmsCountryLabel(value = '') {
return String(value || '').trim() || DEFAULT_HERO_SMS_COUNTRY_LABEL;
}
function normalizeHeroSmsMaxPriceValue(value, fallback = '') {
const trimmed = String(value ?? '').trim();
if (!trimmed) {
return String(fallback || '').trim();
}
const numeric = Number(trimmed);
if (!Number.isFinite(numeric) || numeric <= 0) {
return String(fallback || '').trim();
}
return String(numeric);
}
function getSelectedHeroSmsCountryOption() {
if (!selectHeroSmsCountry) {
return {
@@ -2496,7 +2514,7 @@ function updateAccountRunHistorySettingsUI() {
function updatePhoneVerificationSettingsUI() {
const enabled = Boolean(inputPhoneVerificationEnabled?.checked);
[rowHeroSmsPlatform, rowHeroSmsCountry, rowHeroSmsApiKey].forEach((row) => {
[rowHeroSmsPlatform, rowHeroSmsCountry, rowHeroSmsMaxPrice, rowHeroSmsApiKey].forEach((row) => {
if (!row) {
return;
}
@@ -3000,6 +3018,9 @@ function applySettingsState(state) {
if (inputHeroSmsApiKey) {
inputHeroSmsApiKey.value = state?.heroSmsApiKey || '';
}
if (inputHeroSmsMaxPrice) {
inputHeroSmsMaxPrice.value = normalizeHeroSmsMaxPriceValue(state?.heroSmsMaxPrice);
}
if (selectHeroSmsCountry) {
const restoredCountryId = String(normalizeHeroSmsCountryId(state?.heroSmsCountryId));
if (Array.from(selectHeroSmsCountry.options).some((option) => option.value === restoredCountryId)) {
@@ -6520,6 +6541,15 @@ inputHeroSmsApiKey?.addEventListener('blur', () => {
saveSettings({ silent: true }).catch(() => { });
});
inputHeroSmsMaxPrice?.addEventListener('input', () => {
markSettingsDirty(true);
scheduleSettingsAutoSave();
});
inputHeroSmsMaxPrice?.addEventListener('blur', () => {
inputHeroSmsMaxPrice.value = normalizeHeroSmsMaxPriceValue(inputHeroSmsMaxPrice.value);
saveSettings({ silent: true }).catch(() => { });
});
selectHeroSmsCountry?.addEventListener('change', () => {
updateHeroSmsPlatformDisplay(getSelectedHeroSmsCountryOption().label);
markSettingsDirty(true);
@@ -6922,6 +6952,9 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
if (message.payload.heroSmsApiKey !== undefined && inputHeroSmsApiKey) {
inputHeroSmsApiKey.value = message.payload.heroSmsApiKey || '';
}
if (message.payload.heroSmsMaxPrice !== undefined && inputHeroSmsMaxPrice) {
inputHeroSmsMaxPrice.value = normalizeHeroSmsMaxPriceValue(message.payload.heroSmsMaxPrice);
}
if (message.payload.phoneVerificationEnabled !== undefined && inputPhoneVerificationEnabled) {
inputPhoneVerificationEnabled.checked = Boolean(message.payload.phoneVerificationEnabled);
updatePhoneVerificationSettingsUI();