refactor shared flow settings and runtime cleanup

This commit is contained in:
QLHazyCoder
2026-05-24 19:36:08 +08:00
parent c649d43ee6
commit 3a60560e27
40 changed files with 487 additions and 861 deletions
+1 -1
View File
@@ -1263,7 +1263,7 @@ function updateIpProxyUI(state = latestState) {
const isAccountMode = mode === 'account';
const showSessionOptions = isAccountMode && service === '711proxy';
const hasAccountListConfigured = accountListAvailable && isAccountMode && hasCurrentInputAccountListEntries();
const canOperate = !isAutoRunLockedPhase() && !isAutoRunScheduledPhase();
const canOperate = !isAutoRunLockedPhase();
const actionState = getIpProxyActionState();
const actionBusy = Boolean(actionState.busy);
const busyAction = normalizeIpProxyActionType(actionState.action);
+19 -23
View File
@@ -1268,6 +1268,19 @@ header {
width: 76px;
}
#row-flow-selector .data-label,
#row-source-selector .data-label,
#row-grok-webchat2api-url .data-label,
#row-grok-webchat2api-key .data-label,
#row-grok-register-status .data-label,
#row-grok-sso-status .data-label,
#row-grok-webchat2api-upload-status .data-label,
#row-grok-sso-settings .data-label {
width: 76px;
text-transform: none;
letter-spacing: 0.02em;
}
#row-codex2api-url .data-label {
font-size: 10px;
letter-spacing: 0.02em;
@@ -2197,15 +2210,6 @@ header {
justify-content: flex-end;
}
.auto-delay-setting-pair {
flex-wrap: nowrap;
}
#row-auto-delay-settings .setting-group-secondary {
margin-left: auto;
min-width: 0;
}
.step6-cookie-cleanup-setting {
gap: 8px;
}
@@ -2227,10 +2231,6 @@ header {
text-align: center;
}
.auto-run-delay-setting {
margin-left: auto !important;
}
.oauth-flow-timeout-setting {
gap: 8px;
min-width: 0;
@@ -2242,10 +2242,6 @@ header {
text-overflow: ellipsis;
}
#row-auto-delay-settings .setting-caption {
min-width: auto;
}
.setting-caption-left {
text-align: left;
}
@@ -2720,7 +2716,7 @@ header {
.auto-continue-bar svg { color: var(--orange); flex-shrink: 0; }
.auto-hint { font-size: 13px; color: var(--orange); flex: 1; font-weight: 500; }
.auto-schedule-bar {
.auto-countdown-bar {
margin-top: 8px;
padding: 10px;
background: var(--blue-soft);
@@ -2732,12 +2728,12 @@ header {
gap: 10px;
}
.auto-schedule-bar svg {
.auto-countdown-bar svg {
color: var(--blue);
flex-shrink: 0;
}
.auto-schedule-copy {
.auto-countdown-copy {
display: flex;
flex-direction: column;
gap: 2px;
@@ -2745,19 +2741,19 @@ header {
min-width: 0;
}
.auto-schedule-title {
.auto-countdown-title {
font-size: 13px;
font-weight: 700;
color: var(--blue);
}
.auto-schedule-meta {
.auto-countdown-meta {
font-size: 12px;
line-height: 1.5;
color: var(--text-secondary);
}
.auto-schedule-actions {
.auto-countdown-actions {
display: flex;
align-items: center;
flex-wrap: wrap;
+45 -54
View File
@@ -121,7 +121,7 @@
<section id="data-section">
<div id="settings-card" class="data-card">
<div class="data-row">
<div class="data-row" id="row-flow-selector">
<span class="data-label">注册</span>
<select id="select-flow" class="data-select" aria-label="Flow 选择">
<option value="openai" selected>Codex / OpenAI</option>
@@ -129,13 +129,16 @@
<option value="grok">Grok</option>
</select>
</div>
<div class="data-row">
<div class="data-row" id="row-source-selector">
<span id="label-source-selector" class="data-label">来源</span>
<select id="select-panel-mode" class="data-select">
<option value="cpa">CPA 面板</option>
<option value="sub2api">SUB2API</option>
<option value="codex2api">Codex2API</option>
</select>
<div class="data-inline">
<select id="select-panel-mode" class="data-select">
<option value="cpa">CPA 面板</option>
<option value="sub2api">SUB2API</option>
<option value="codex2api">Codex2API</option>
</select>
<button id="btn-open-webchat2api-github" class="btn btn-ghost btn-xs data-inline-btn" type="button">GitHub</button>
</div>
</div>
<div id="contribution-mode-panel" class="contribution-mode-panel" hidden>
<div class="contribution-mode-panel-header">
@@ -291,20 +294,8 @@
<span class="data-label">上传状态</span>
<span id="display-kiro-upload-status" class="data-value mono">未开始</span>
</div>
<div class="data-row" id="row-grok-register-status" style="display:none;">
<span class="data-label">Grok 注册</span>
<span id="display-grok-register-status" class="data-value mono">未开始</span>
</div>
<div class="data-row" id="row-grok-sso-status" style="display:none;">
<span class="data-label">SSO 状态</span>
<span id="display-grok-sso-status" class="data-value mono">未提取</span>
</div>
<div class="data-row" id="row-grok-webchat2api-upload-status" style="display:none;">
<span class="data-label">上传状态</span>
<span id="display-grok-webchat2api-upload-status" class="data-value mono">未开始</span>
</div>
<div class="data-row" id="row-grok-webchat2api-url" style="display:none;">
<span class="data-label">webchat2api</span>
<span class="data-label">webchat</span>
<input type="text" id="input-grok-webchat2api-url" class="data-input"
placeholder="请输入 webchat2api 地址,例如 http://localhost:83" />
</div>
@@ -319,6 +310,18 @@
title="显示 webchat2api 管理密钥"></button>
</div>
</div>
<div class="data-row" id="row-grok-register-status" style="display:none;">
<span class="data-label">Grok 注册</span>
<span id="display-grok-register-status" class="data-value mono">未开始</span>
</div>
<div class="data-row" id="row-grok-sso-status" style="display:none;">
<span class="data-label">SSO 状态</span>
<span id="display-grok-sso-status" class="data-value mono">未提取</span>
</div>
<div class="data-row" id="row-grok-webchat2api-upload-status" style="display:none;">
<span class="data-label">上传状态</span>
<span id="display-grok-webchat2api-upload-status" class="data-value mono">未开始</span>
</div>
<div class="data-row" id="row-grok-sso-settings" style="display:none;">
<span class="data-label">SSO Cookie</span>
<div class="data-inline">
@@ -694,26 +697,7 @@
</div>
</div>
</div>
<div class="data-row module-divider-start" id="row-auto-delay-settings">
<span class="data-label">启动前</span>
<div class="data-inline setting-pair auto-delay-setting-pair">
<div class="setting-group setting-group-secondary auto-run-delay-setting">
<span class="setting-caption">延迟</span>
<label class="toggle-switch" for="input-auto-delay-enabled">
<input type="checkbox" id="input-auto-delay-enabled" />
<span class="toggle-switch-track" aria-hidden="true">
<span class="toggle-switch-thumb"></span>
</span>
</label>
<div class="setting-controls">
<input type="number" id="input-auto-delay-minutes" class="data-input auto-delay-input" value="30" min="1"
max="1440" step="1" title="启动前倒计时分钟数" />
<span class="data-unit">分钟</span>
</div>
</div>
</div>
</div>
<div class="data-row">
<div class="data-row module-divider-start" id="row-shared-auto-run">
<span class="data-label">自动重试</span>
<div class="data-inline setting-pair">
<div class="setting-group setting-group-primary">
@@ -734,6 +718,16 @@
</div>
</div>
</div>
<div class="data-row" id="row-auto-run-thread-interval">
<span class="data-label">线程间隔</span>
<div class="data-inline">
<div class="setting-controls">
<input type="number" id="input-auto-skip-failures-thread-interval-minutes"
class="data-input auto-delay-input" value="0" min="0" max="1440" step="1" title="兜底模式下,两轮线程之间的等待分钟数" />
<span class="data-unit">分钟</span>
</div>
</div>
</div>
<div class="data-row" id="row-oauth-flow-timeout">
<span class="data-label">授权总超时</span>
<div class="data-inline setting-pair">
@@ -748,14 +742,6 @@
</label>
<span class="setting-caption oauth-flow-timeout-caption">关闭后只取消 Step 7 后链总预算</span>
</div>
<div class="setting-group setting-group-secondary">
<span class="setting-caption">线程间隔</span>
<div class="setting-controls">
<input type="number" id="input-auto-skip-failures-thread-interval-minutes"
class="data-input auto-delay-input" value="0" min="0" max="1440" step="1" title="兜底模式下,两轮线程之间的等待分钟数" />
<span class="data-unit">分钟</span>
</div>
</div>
</div>
</div>
<div class="data-row" id="row-step-execution-range">
@@ -782,10 +768,15 @@
<span class="data-label">OAuth</span>
<span id="display-oauth-url" class="data-value mono truncate">等待中...</span>
</div>
<div class="data-row">
<div class="data-row" id="row-oauth-callback">
<span class="data-label">回调</span>
<div class="data-inline data-value-actions">
<span id="display-localhost-url" class="data-value data-value-fill mono truncate">等待中...</span>
</div>
</div>
<div class="data-row module-divider-start" id="row-settings-actions">
<span class="data-label">设置</span>
<div class="data-inline data-value-actions">
<button id="btn-save-settings" class="btn btn-outline btn-sm data-inline-btn" type="button">保存</button>
</div>
</div>
@@ -1798,16 +1789,16 @@
<span class="auto-hint">先自动获取邮箱,或手动粘贴邮箱后再继续</span>
<button id="btn-auto-continue" class="btn btn-primary btn-sm">继续</button>
</div>
<div id="auto-schedule-bar" class="auto-schedule-bar" style="display:none;">
<div id="auto-countdown-bar" class="auto-countdown-bar" style="display:none;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10" />
<polyline points="12 6 12 12 16 14" />
</svg>
<div class="auto-schedule-copy">
<span id="auto-schedule-title" class="auto-schedule-title">已计划自动运行</span>
<span id="auto-schedule-meta" class="auto-schedule-meta">等待倒计时开始...</span>
<div class="auto-countdown-copy">
<span id="auto-countdown-title" class="auto-countdown-title">等待继续</span>
<span id="auto-countdown-meta" class="auto-countdown-meta">等待倒计时开始...</span>
</div>
<div class="auto-schedule-actions">
<div class="auto-countdown-actions">
<button id="btn-auto-run-now" class="btn btn-primary btn-sm" type="button">立即开始</button>
<button id="btn-auto-cancel-schedule" class="btn btn-outline btn-sm" type="button">取消</button>
</div>
+51 -160
View File
@@ -77,11 +77,10 @@ const stepsProgress = document.getElementById('steps-progress');
const btnAutoRun = document.getElementById('btn-auto-run');
const btnAutoContinue = document.getElementById('btn-auto-continue');
const autoContinueBar = document.getElementById('auto-continue-bar');
const autoScheduleBar = document.getElementById('auto-schedule-bar');
const autoScheduleTitle = document.getElementById('auto-schedule-title');
const autoScheduleMeta = document.getElementById('auto-schedule-meta');
const autoCountdownBar = document.getElementById('auto-countdown-bar');
const autoCountdownTitle = document.getElementById('auto-countdown-title');
const autoCountdownMeta = document.getElementById('auto-countdown-meta');
const btnAutoRunNow = document.getElementById('btn-auto-run-now');
const btnAutoCancelSchedule = document.getElementById('btn-auto-cancel-schedule');
const btnClearLog = document.getElementById('btn-clear-log');
const configMenuShell = document.getElementById('config-menu-shell');
const btnConfigMenu = document.getElementById('btn-config-menu');
@@ -91,6 +90,7 @@ const btnImportSettings = document.getElementById('btn-import-settings');
const inputImportSettingsFile = document.getElementById('input-import-settings-file');
const labelSourceSelector = document.getElementById('label-source-selector');
const selectPanelMode = document.getElementById('select-panel-mode');
const btnOpenWebchat2ApiGithub = document.getElementById('btn-open-webchat2api-github');
const rowVpsUrl = document.getElementById('row-vps-url');
const inputVpsUrl = document.getElementById('input-vps-url');
const rowVpsPassword = document.getElementById('row-vps-password');
@@ -428,8 +428,6 @@ const inputRunCount = document.getElementById('input-run-count');
const inputAutoSkipFailures = document.getElementById('input-auto-skip-failures');
const inputAutoSkipFailuresThreadIntervalMinutes = document.getElementById('input-auto-skip-failures-thread-interval-minutes');
const inputStep6CookieCleanupEnabled = document.getElementById('input-step6-cookie-cleanup-enabled');
const inputAutoDelayEnabled = document.getElementById('input-auto-delay-enabled');
const inputAutoDelayMinutes = document.getElementById('input-auto-delay-minutes');
const inputAutoStepDelaySeconds = document.getElementById('input-auto-step-delay-seconds');
const inputOAuthFlowTimeoutEnabled = document.getElementById('input-oauth-flow-timeout-enabled');
const rowStepExecutionRange = document.getElementById('row-step-execution-range');
@@ -628,9 +626,6 @@ let SKIPPABLE_STEPS = new Set(STEP_IDS);
let NODE_IDS = workflowNodes.map((node) => String(node.nodeId || '').trim()).filter(Boolean);
let NODE_DEFAULT_STATUSES = Object.fromEntries(NODE_IDS.map((nodeId) => [nodeId, 'pending']));
let SKIPPABLE_NODES = new Set(NODE_IDS);
const AUTO_DELAY_MIN_MINUTES = 1;
const AUTO_DELAY_MAX_MINUTES = 1440;
const AUTO_DELAY_DEFAULT_MINUTES = 30;
const AUTO_FALLBACK_THREAD_INTERVAL_MIN_MINUTES = 0;
const AUTO_FALLBACK_THREAD_INTERVAL_MAX_MINUTES = 1440;
const AUTO_FALLBACK_THREAD_INTERVAL_DEFAULT_MINUTES = 0;
@@ -1365,7 +1360,6 @@ let currentAutoRun = {
currentRun: 0,
totalRuns: 1,
attemptRun: 0,
scheduledAt: null,
countdownAt: null,
countdownTitle: '',
countdownNote: '',
@@ -1386,7 +1380,7 @@ let currentModalActions = [];
let modalResultBuilder = null;
let activePlusManualConfirmationRequestId = '';
let plusManualConfirmationDialogInFlight = false;
let scheduledCountdownTimer = null;
let autoRunCountdownTimer = null;
let configMenuOpen = false;
let configActionInFlight = false;
let currentReleaseSnapshot = null;
@@ -1426,9 +1420,7 @@ function shouldAttachAutomationWindow(message = {}) {
return [
'EXECUTE_NODE',
'AUTO_RUN',
'SCHEDULE_AUTO_RUN',
'RESUME_AUTO_RUN',
'START_SCHEDULED_AUTO_RUN_NOW',
'SKIP_AUTO_RUN_COUNTDOWN',
'PROBE_IP_PROXY_EXIT',
].includes(String(message?.type || '').trim());
@@ -1680,7 +1672,6 @@ const ICLOUD_FORWARD_MAIL_PROVIDER_LABELS = Object.fromEntries(
const getIcloudLoginUrlForHost = window.IcloudUtils?.getIcloudLoginUrlForHost
|| ((host) => host === 'icloud.com.cn' ? 'https://www.icloud.com.cn/' : (host === 'icloud.com' ? 'https://www.icloud.com/' : ''));
btnAutoCancelSchedule?.remove();
const MAIL_PROVIDER_LOGIN_CONFIGS = {
[ICLOUD_PROVIDER]: {
label: 'iCloud 邮箱',
@@ -2982,7 +2973,7 @@ function applyStepExecutionRangeState(state = latestState) {
if (inputStepExecutionRangeEnabled) {
inputStepExecutionRangeEnabled.checked = Boolean(range.enabled);
}
const controlsDisabled = !available || isAutoRunLockedPhase() || isAutoRunScheduledPhase();
const controlsDisabled = !available || isAutoRunLockedPhase();
if (inputStepExecutionRangeEnabled) inputStepExecutionRangeEnabled.disabled = controlsDisabled;
if (inputStepExecutionRangeFrom) inputStepExecutionRangeFrom.disabled = controlsDisabled || !inputStepExecutionRangeEnabled?.checked;
if (inputStepExecutionRangeTo) inputStepExecutionRangeTo.disabled = controlsDisabled || !inputStepExecutionRangeEnabled?.checked;
@@ -3083,7 +3074,7 @@ function hasSavedProgress(state = latestState) {
function isContributionModeSwitchBlocked(state = latestState) {
const statuses = getStepStatuses(state);
const anyRunning = Object.values(statuses).some((status) => status === 'running');
return anyRunning || isAutoRunLockedPhase() || isAutoRunPausedPhase() || isAutoRunScheduledPhase();
return anyRunning || isAutoRunLockedPhase() || isAutoRunPausedPhase();
}
function shouldOfferAutoModeChoice(state = latestState) {
@@ -3630,7 +3621,7 @@ function syncAutoRunState(source = {}) {
const autoRunning = source.autoRunning !== undefined
? Boolean(source.autoRunning)
: (source.autoRunPhase !== undefined || source.phase !== undefined
? ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase)
? ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase)
: currentAutoRun.autoRunning);
currentAutoRun = {
@@ -3639,7 +3630,6 @@ function syncAutoRunState(source = {}) {
currentRun: readAutoRunStateValue(source, ['autoRunCurrentRun', 'currentRun'], currentAutoRun.currentRun),
totalRuns: readAutoRunStateValue(source, ['autoRunTotalRuns', 'totalRuns'], currentAutoRun.totalRuns),
attemptRun: readAutoRunStateValue(source, ['autoRunAttemptRun', 'attemptRun'], currentAutoRun.attemptRun),
scheduledAt: readAutoRunStateValue(source, ['scheduledAutoRunAt', 'scheduledAt'], currentAutoRun.scheduledAt),
countdownAt: readAutoRunStateValue(source, ['autoRunCountdownAt', 'countdownAt'], currentAutoRun.countdownAt),
countdownTitle: readAutoRunStateValue(source, ['autoRunCountdownTitle', 'countdownTitle'], currentAutoRun.countdownTitle),
countdownNote: readAutoRunStateValue(source, ['autoRunCountdownNote', 'countdownNote'], currentAutoRun.countdownNote),
@@ -3649,8 +3639,7 @@ function syncAutoRunState(source = {}) {
function isContributionButtonLocked() {
const autoActive = currentAutoRun.autoRunning
|| isAutoRunLockedPhase()
|| isAutoRunPausedPhase()
|| isAutoRunScheduledPhase();
|| isAutoRunPausedPhase();
if (autoActive) {
return false;
}
@@ -3675,12 +3664,8 @@ function isAutoRunWaitingStepPhase() {
return currentAutoRun.phase === 'waiting_step';
}
function isAutoRunScheduledPhase() {
return currentAutoRun.phase === 'scheduled';
}
function isAutoRunSourceSyncPhase(phase) {
return ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
return ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
}
function shouldSyncRunCountFromAutoRunSource(source = {}) {
@@ -3717,14 +3702,6 @@ function getAutoRunLabel(payload = currentAutoRun) {
return attemptLabel ? ` (${attemptLabel.slice(3)})` : '';
}
function normalizeAutoDelayMinutes(value) {
const numeric = Number(value);
if (!Number.isFinite(numeric)) {
return AUTO_DELAY_DEFAULT_MINUTES;
}
return Math.min(AUTO_DELAY_MAX_MINUTES, Math.max(AUTO_DELAY_MIN_MINUTES, Math.floor(numeric)));
}
function normalizeAutoRunThreadIntervalMinutes(value) {
const rawValue = String(value ?? '').trim();
if (!rawValue) {
@@ -3948,12 +3925,6 @@ function updateFallbackThreadIntervalInputState() {
inputAutoSkipFailuresThreadIntervalMinutes.disabled = Boolean(inputAutoSkipFailures.disabled);
}
function updateAutoDelayInputState() {
const scheduled = isAutoRunScheduledPhase();
inputAutoDelayEnabled.disabled = scheduled;
inputAutoDelayMinutes.disabled = scheduled || !inputAutoDelayEnabled.checked;
}
function formatCountdown(remainingMs) {
const totalSeconds = Math.max(0, Math.ceil(remainingMs / 1000));
const hours = Math.floor(totalSeconds / 3600);
@@ -3974,21 +3945,12 @@ function formatScheduleTime(timestamp) {
});
}
function stopScheduledCountdownTicker() {
clearInterval(scheduledCountdownTimer);
scheduledCountdownTimer = null;
function stopAutoRunCountdownTicker() {
clearInterval(autoRunCountdownTimer);
autoRunCountdownTimer = null;
}
function getActiveAutoRunCountdown() {
if (isAutoRunScheduledPhase() && Number.isFinite(currentAutoRun.scheduledAt)) {
return {
at: currentAutoRun.scheduledAt,
title: '已计划自动运行',
note: `计划于 ${formatScheduleTime(currentAutoRun.scheduledAt)} 开始`,
tone: 'scheduled',
};
}
if (currentAutoRun.phase !== 'waiting_interval') {
return null;
}
@@ -4005,48 +3967,45 @@ function getActiveAutoRunCountdown() {
};
}
function renderScheduledAutoRunInfo() {
if (!autoScheduleBar) {
function renderAutoRunCountdownInfo() {
if (!autoCountdownBar) {
return;
}
const countdown = getActiveAutoRunCountdown();
if (!countdown) {
autoScheduleBar.style.display = 'none';
autoCountdownBar.style.display = 'none';
return;
}
const remainingMs = countdown.at - Date.now();
autoScheduleBar.style.display = 'flex';
autoCountdownBar.style.display = 'flex';
if (btnAutoRunNow) {
btnAutoRunNow.hidden = false;
btnAutoRunNow.textContent = currentAutoRun.phase === 'waiting_interval' ? '立即继续' : '立即开始';
btnAutoRunNow.textContent = '立即继续';
}
if (btnAutoCancelSchedule) {
btnAutoCancelSchedule.hidden = true;
}
autoScheduleTitle.textContent = countdown.title;
autoScheduleMeta.textContent = remainingMs > 0
autoCountdownTitle.textContent = countdown.title;
autoCountdownMeta.textContent = remainingMs > 0
? `${countdown.note ? `${countdown.note}` : ''}剩余 ${formatCountdown(remainingMs)}`
: '倒计时即将结束,正在准备继续...';
return;
}
function syncScheduledCountdownTicker() {
renderScheduledAutoRunInfo();
function syncAutoRunCountdownTicker() {
renderAutoRunCountdownInfo();
if (getActiveAutoRunCountdown()) {
if (scheduledCountdownTimer) {
if (autoRunCountdownTimer) {
return;
}
scheduledCountdownTimer = setInterval(() => {
renderScheduledAutoRunInfo();
autoRunCountdownTimer = setInterval(() => {
renderAutoRunCountdownInfo();
updateStatusDisplay(latestState);
}, 1000);
return;
}
stopScheduledCountdownTicker();
stopAutoRunCountdownTicker();
return;
}
@@ -5159,8 +5118,6 @@ function collectSettingsPayload() {
stepExecutionRangeByFlow: typeof buildStepExecutionRangeByFlowPayload === 'function'
? buildStepExecutionRangeByFlowPayload(latestState?.stepExecutionRangeByFlow)
: (latestState?.stepExecutionRangeByFlow || {}),
autoRunDelayEnabled: inputAutoDelayEnabled.checked,
autoRunDelayMinutes: normalizeAutoDelayMinutes(inputAutoDelayMinutes.value),
autoStepDelaySeconds: normalizeAutoStepDelaySeconds(inputAutoStepDelaySeconds.value),
oauthFlowTimeoutEnabled: typeof inputOAuthFlowTimeoutEnabled !== 'undefined' && inputOAuthFlowTimeoutEnabled
? Boolean(inputOAuthFlowTimeoutEnabled.checked)
@@ -9337,7 +9294,7 @@ function canSelectPhoneSignupMethod() {
}
function isSignupMethodSwitchLocked() {
return isAutoRunLockedPhase() || isAutoRunPausedPhase() || isAutoRunScheduledPhase();
return isAutoRunLockedPhase() || isAutoRunPausedPhase();
}
function updateSignupMethodUI(options = {}) {
@@ -9581,7 +9538,7 @@ function updatePhoneVerificationSettingsUI() {
}
}
phoneSignupReuseUiWasLocked = phoneSignupReuseLocked;
const settingsLocked = isAutoRunLockedPhase() || isAutoRunScheduledPhase();
const settingsLocked = isAutoRunLockedPhase();
if (typeof inputPhoneSignupReloginAfterBindEmail !== 'undefined' && inputPhoneSignupReloginAfterBindEmail) {
inputPhoneSignupReloginAfterBindEmail.disabled = settingsLocked || !showPhoneSignupReloginAfterBindEmail;
}
@@ -10744,8 +10701,7 @@ function applyAutoRunStatus(payload = currentAutoRun) {
const runLabel = getAutoRunLabel(currentAutoRun);
const locked = isAutoRunLockedPhase();
const paused = isAutoRunPausedPhase();
const scheduled = isAutoRunScheduledPhase();
const settingsCardLocked = scheduled || locked;
const settingsCardLocked = locked;
setSettingsCardLocked(settingsCardLocked);
setFreePhoneReuseControlsLocked(settingsCardLocked);
@@ -10766,14 +10722,14 @@ function applyAutoRunStatus(payload = currentAutoRun) {
if (typeof inputSub2ApiAccountPriority !== 'undefined' && inputSub2ApiAccountPriority) {
inputSub2ApiAccountPriority.disabled = locked;
}
inputAutoSkipFailures.disabled = scheduled;
inputAutoSkipFailures.disabled = locked;
const lockedRunCount = typeof getLockedRunCountFromEmailPool === 'function'
? getLockedRunCountFromEmailPool()
: 0;
const isSyncPhase = typeof isAutoRunSourceSyncPhase === 'function'
? isAutoRunSourceSyncPhase
: (phase) => ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
: (phase) => ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
const shouldSyncRunCount = typeof shouldSyncRunCountFromAutoRunSource === 'function'
? shouldSyncRunCountFromAutoRunSource(currentAutoRun)
: (currentAutoRun.autoRunning || isSyncPhase(currentAutoRun.phase));
@@ -10784,10 +10740,6 @@ function applyAutoRunStatus(payload = currentAutoRun) {
}
switch (currentAutoRun.phase) {
case 'scheduled':
autoContinueBar.style.display = 'none';
btnAutoRun.innerHTML = `已计划${runLabel}`;
break;
case 'waiting_step':
autoContinueBar.style.display = 'none';
btnAutoRun.innerHTML = `等待中${runLabel}`;
@@ -10818,10 +10770,9 @@ function applyAutoRunStatus(payload = currentAutoRun) {
break;
}
updateAutoDelayInputState();
updateFallbackThreadIntervalInputState();
syncScheduledCountdownTicker();
updateStopButtonState(scheduled || paused || locked || Object.values(getStepStatuses()).some(status => status === 'running'));
syncAutoRunCountdownTicker();
updateStopButtonState(paused || locked || Object.values(getStepStatuses()).some(status => status === 'running'));
updateConfigMenuControls();
renderContributionMode();
}
@@ -11422,8 +11373,6 @@ function applySettingsState(state) {
if (typeof inputStep6CookieCleanupEnabled !== 'undefined' && inputStep6CookieCleanupEnabled) {
inputStep6CookieCleanupEnabled.checked = Boolean(state?.step6CookieCleanupEnabled);
}
inputAutoDelayEnabled.checked = Boolean(state?.autoRunDelayEnabled);
inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(state?.autoRunDelayMinutes));
inputAutoStepDelaySeconds.value = formatAutoStepDelayInputValue(state?.autoStepDelaySeconds);
if (typeof inputOAuthFlowTimeoutEnabled !== 'undefined' && inputOAuthFlowTimeoutEnabled) {
inputOAuthFlowTimeoutEnabled.checked = state?.oauthFlowTimeoutEnabled !== undefined
@@ -11598,7 +11547,7 @@ function applySettingsState(state) {
}
const isSyncPhase = typeof isAutoRunSourceSyncPhase === 'function'
? isAutoRunSourceSyncPhase
: (phase) => ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
: (phase) => ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
const shouldSyncInitialRunCount = typeof shouldSyncRunCountFromAutoRunSource === 'function'
? shouldSyncRunCountFromAutoRunSource(state)
: (Boolean(state?.autoRunning) || isSyncPhase(state?.autoRunPhase ?? state?.phase));
@@ -11608,7 +11557,6 @@ function applySettingsState(state) {
applyAutoRunStatus(state);
markSettingsDirty(false);
updateAutoDelayInputState();
updateFallbackThreadIntervalInputState();
updateAccountRunHistorySettingsUI();
updatePhoneVerificationSettingsUI();
@@ -13657,7 +13605,6 @@ function updateButtonStates() {
const statuses = getNodeStatuses();
const anyRunning = Object.values(statuses).some(s => s === 'running');
const autoLocked = isAutoRunLockedPhase();
const autoScheduled = isAutoRunScheduledPhase();
const enabledNodeIds = getEnabledNodeIdsForStepExecutionRange(latestState);
const icloudTargetMailboxTypeValue = typeof selectIcloudTargetMailboxType !== 'undefined'
? selectIcloudTargetMailboxType?.value
@@ -13671,7 +13618,7 @@ function updateButtonStates() {
if (currentStatus === 'disabled') {
btn.disabled = true;
} else if (anyRunning || autoLocked || autoScheduled) {
} else if (anyRunning || autoLocked) {
btn.disabled = true;
} else if (enabledNodeIds.indexOf(nodeId) === 0) {
btn.disabled = false;
@@ -13691,7 +13638,7 @@ function updateButtonStates() {
const prevNodeId = currentIndex > 0 ? enabledNodeIds[currentIndex - 1] : null;
const prevStatus = prevNodeId === null ? 'completed' : statuses[prevNodeId];
if (!SKIPPABLE_NODES.has(nodeId) || currentStatus === 'disabled' || anyRunning || autoLocked || autoScheduled || currentStatus === 'running' || isDoneStatus(currentStatus)) {
if (!SKIPPABLE_NODES.has(nodeId) || currentStatus === 'disabled' || anyRunning || autoLocked || currentStatus === 'running' || isDoneStatus(currentStatus)) {
btn.style.display = 'none';
btn.disabled = true;
btn.title = '当前不可跳过';
@@ -13710,8 +13657,8 @@ function updateButtonStates() {
btn.title = `跳过节点 ${nodeId}`;
});
btnReset.disabled = anyRunning || autoScheduled || isAutoRunPausedPhase() || autoLocked;
const disableIcloudControls = anyRunning || autoScheduled || autoLocked;
btnReset.disabled = anyRunning || isAutoRunPausedPhase() || autoLocked;
const disableIcloudControls = anyRunning || autoLocked;
if (btnIcloudRefresh) btnIcloudRefresh.disabled = disableIcloudControls;
if (btnIcloudDeleteUsed) btnIcloudDeleteUsed.disabled = disableIcloudControls || !hasDeletableUsedIcloudAliases();
if (selectIcloudHostPreference) selectIcloudHostPreference.disabled = disableIcloudControls;
@@ -13733,7 +13680,7 @@ function updateButtonStates() {
if (checkboxAutoDeleteIcloud) checkboxAutoDeleteIcloud.disabled = disableIcloudControls;
if (btnContributionMode) btnContributionMode.disabled = isContributionButtonLocked();
applyStepExecutionRangeState(latestState);
updateStopButtonState(anyRunning || autoScheduled || isAutoRunPausedPhase() || autoLocked);
updateStopButtonState(anyRunning || isAutoRunPausedPhase() || autoLocked);
renderContributionMode();
}
@@ -13753,18 +13700,7 @@ function updateStatusDisplay(state) {
displayStatus.textContent = remainingMs > 0
? `${countdown.title},剩余 ${formatCountdown(remainingMs)}`
: `${countdown.title},即将结束...`;
statusBar.classList.add(countdown.tone === 'scheduled' ? 'scheduled' : 'running');
return;
}
if (isAutoRunScheduledPhase()) {
const remainingMs = Number.isFinite(currentAutoRun.scheduledAt)
? currentAutoRun.scheduledAt - Date.now()
: 0;
displayStatus.textContent = remainingMs > 0
? `自动计划中,剩余 ${formatCountdown(remainingMs)}`
: '倒计时即将结束,正在准备启动...';
statusBar.classList.add('scheduled');
statusBar.classList.add('running');
return;
}
@@ -14973,7 +14909,7 @@ btnSaveSettings.addEventListener('click', async () => {
btnStop.addEventListener('click', async () => {
btnStop.disabled = true;
await chrome.runtime.sendMessage({ type: 'STOP_FLOW', source: 'sidepanel', payload: {} });
showToast(isAutoRunScheduledPhase() ? '正在取消倒计时计划...' : '正在停止当前流程...', 'warn', 2000);
showToast(currentAutoRun.phase === 'waiting_interval' ? '正在取消等待中的倒计时...' : '正在停止当前流程...', 'warn', 2000);
});
btnConfigMenu?.addEventListener('click', (event) => {
@@ -15150,24 +15086,18 @@ async function startAutoRunFromCurrentSettings() {
btnAutoRun.disabled = true;
inputRunCount.disabled = true;
const delayEnabled = inputAutoDelayEnabled.checked;
const delayMinutes = normalizeAutoDelayMinutes(inputAutoDelayMinutes.value);
const activeFlowId = typeof getSelectedFlowId === 'function'
? getSelectedFlowId(latestState)
: (String(latestState?.activeFlowId || latestState?.flowId || DEFAULT_ACTIVE_FLOW_ID).trim().toLowerCase() || DEFAULT_ACTIVE_FLOW_ID);
const targetId = typeof getSelectedTargetId === 'function'
? getSelectedTargetId(activeFlowId)
: normalizeTargetIdForFlow(activeFlowId, latestState?.targetId || '', getDefaultTargetIdForFlow(activeFlowId));
inputAutoDelayMinutes.value = String(delayMinutes);
btnAutoRun.innerHTML = delayEnabled
? '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg> 计划中...'
: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg> 运行中...';
btnAutoRun.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg> 运行中...';
const response = await sendSidepanelMessage({
type: delayEnabled ? 'SCHEDULE_AUTO_RUN' : 'AUTO_RUN',
type: 'AUTO_RUN',
source: 'sidepanel',
payload: {
totalRuns,
delayMinutes,
activeFlowId,
targetId,
autoRunSkipFailures,
@@ -15213,15 +15143,12 @@ btnAutoContinue.addEventListener('click', async () => {
btnAutoRunNow?.addEventListener('click', async () => {
try {
btnAutoRunNow.disabled = true;
const waitingInterval = currentAutoRun.phase === 'waiting_interval';
await sendSidepanelMessage({
type: waitingInterval ? 'SKIP_AUTO_RUN_COUNTDOWN' : 'START_SCHEDULED_AUTO_RUN_NOW',
type: 'SKIP_AUTO_RUN_COUNTDOWN',
source: 'sidepanel',
payload: {},
});
if (waitingInterval) {
showToast('已跳过当前倒计时,自动流程将立即继续。', 'info', 1800);
}
showToast('已跳过当前倒计时,自动流程将立即继续。', 'info', 1800);
} catch (err) {
showToast(err.message, 'error');
} finally {
@@ -15229,18 +15156,6 @@ btnAutoRunNow?.addEventListener('click', async () => {
}
});
btnAutoCancelSchedule?.addEventListener('click', async () => {
try {
btnAutoCancelSchedule.disabled = true;
await chrome.runtime.sendMessage({ type: 'CANCEL_SCHEDULED_AUTO_RUN', source: 'sidepanel', payload: {} });
showToast('已取消倒计时计划。', 'info', 1800);
} catch (err) {
showToast(err.message, 'error');
} finally {
btnAutoCancelSchedule.disabled = false;
}
});
// Reset
btnReset.addEventListener('click', async () => {
const confirmed = await openConfirmModal({
@@ -15270,7 +15185,6 @@ btnReset.addEventListener('click', async () => {
autoRunCurrentRun: 0,
autoRunTotalRuns: 1,
autoRunAttemptRun: 0,
scheduledAutoRunAt: null,
autoRunCountdownAt: null,
autoRunCountdownTitle: '',
autoRunCountdownNote: '',
@@ -15460,6 +15374,10 @@ btnOpenKiroRsGithub?.addEventListener('click', () => {
openExternalUrl('https://github.com/QLHazyCoder/kiro.rs');
});
btnOpenWebchat2ApiGithub?.addEventListener('click', () => {
openExternalUrl('https://github.com/zqbxdev/webchat2api');
});
btnGpcHelperBalance?.addEventListener('click', async () => {
try {
const response = await chrome.runtime.sendMessage({
@@ -16576,12 +16494,6 @@ inputAutoSkipFailuresThreadIntervalMinutes.addEventListener('blur', () => {
saveSettings({ silent: true }).catch(() => { });
});
inputAutoDelayEnabled.addEventListener('change', () => {
updateAutoDelayInputState();
markSettingsDirty(true);
saveSettings({ silent: true }).catch(() => { });
});
inputStep6CookieCleanupEnabled?.addEventListener('change', () => {
markSettingsDirty(true);
saveSettings({ silent: true }).catch(() => { });
@@ -16655,17 +16567,6 @@ selectFlow?.addEventListener('change', () => {
});
});
inputAutoDelayMinutes.addEventListener('input', () => {
markSettingsDirty(true);
scheduleSettingsAutoSave();
});
inputAutoDelayMinutes.addEventListener('blur', () => {
inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(inputAutoDelayMinutes.value));
saveSettings({ silent: true }).catch(() => { });
});
function getPhoneSmsCountrySelectionForProvider(provider = getSelectedPhoneSmsProvider(), options = {}) {
const normalizedProvider = normalizePhoneSmsProvider(provider);
const countrySelect = selectHeroSmsCountry || selectHeroSmsCountryFallback;
@@ -17457,7 +17358,6 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
password: null,
nodeStatuses: NODE_DEFAULT_STATUSES,
logs: [],
scheduledAutoRunAt: null,
autoRunCountdownAt: null,
autoRunCountdownTitle: '',
autoRunCountdownNote: '',
@@ -17492,7 +17392,6 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
autoRunCurrentRun: 0,
autoRunTotalRuns: 1,
autoRunAttemptRun: 0,
scheduledAutoRunAt: null,
autoRunCountdownAt: null,
autoRunCountdownTitle: '',
autoRunCountdownNote: '',
@@ -17926,10 +17825,6 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
inputAutoSkipFailures.checked = Boolean(message.payload.autoRunSkipFailures);
updateFallbackThreadIntervalInputState();
}
if (message.payload.autoRunDelayEnabled !== undefined) {
inputAutoDelayEnabled.checked = Boolean(message.payload.autoRunDelayEnabled);
updateAutoDelayInputState();
}
if (
message.payload.step6CookieCleanupEnabled !== undefined
&& typeof inputStep6CookieCleanupEnabled !== 'undefined'
@@ -17945,9 +17840,6 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
renderStepStatuses(latestState);
updateButtonStates();
}
if (message.payload.autoRunDelayMinutes !== undefined) {
inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(message.payload.autoRunDelayMinutes));
}
if (message.payload.autoRunFallbackThreadIntervalMinutes !== undefined) {
inputAutoSkipFailuresThreadIntervalMinutes.value = String(
normalizeAutoRunThreadIntervalMinutes(message.payload.autoRunFallbackThreadIntervalMinutes)
@@ -18239,12 +18131,11 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
case 'AUTO_RUN_STATUS': {
syncLatestState({
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(message.payload.phase),
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(message.payload.phase),
autoRunPhase: message.payload.phase,
autoRunCurrentRun: message.payload.currentRun,
autoRunTotalRuns: message.payload.totalRuns,
autoRunAttemptRun: message.payload.attemptRun,
scheduledAutoRunAt: message.payload.scheduledAt ?? null,
autoRunCountdownAt: message.payload.countdownAt ?? null,
autoRunCountdownTitle: message.payload.countdownTitle ?? '',
autoRunCountdownNote: message.payload.countdownNote ?? '',
@@ -18252,7 +18143,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
applyAutoRunStatus(message.payload);
updateStatusDisplay(latestState);
updateButtonStates();
if (!['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(message.payload.phase)) {
if (!['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(message.payload.phase)) {
scheduleAccountRunHistoryRefresh();
}
break;