feat: 添加自动运行风险提示功能,优化用户确认流程

This commit is contained in:
QLHazyCoder
2026-04-13 23:32:58 +08:00
parent 6b6d90e918
commit c4ea41203c
+102 -21
View File
@@ -131,6 +131,9 @@ const AUTO_STEP_DELAY_MIN_SECONDS = 0;
const AUTO_STEP_DELAY_MAX_SECONDS = 600; const AUTO_STEP_DELAY_MAX_SECONDS = 600;
const DEFAULT_LOCAL_CPA_STEP9_MODE = 'submit'; const DEFAULT_LOCAL_CPA_STEP9_MODE = 'submit';
const AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY = 'multipage-auto-skip-failures-prompt-dismissed'; const AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY = 'multipage-auto-skip-failures-prompt-dismissed';
const AUTO_RUN_FALLBACK_RISK_PROMPT_DISMISSED_STORAGE_KEY = 'multipage-auto-run-fallback-risk-prompt-dismissed';
const AUTO_RUN_FALLBACK_RISK_WARNING_MIN_RUNS = 15;
const AUTO_RUN_FALLBACK_RISK_RECOMMENDED_THREAD_INTERVAL_MINUTES = 5;
let latestState = null; let latestState = null;
let currentAutoRun = { let currentAutoRun = {
@@ -351,29 +354,26 @@ async function openConfirmModal({ title, message, confirmLabel = '确认', confi
return choice === 'confirm'; return choice === 'confirm';
} }
function isAutoSkipFailuresPromptDismissed() { async function openConfirmModalWithOption({
return localStorage.getItem(AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY) === '1'; title,
} message,
confirmLabel = '确认',
function setAutoSkipFailuresPromptDismissed(dismissed) { confirmVariant = 'btn-primary',
if (dismissed) { optionLabel = '不再提示',
localStorage.setItem(AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY, '1'); optionChecked = false,
} else { optionDisabled = false,
localStorage.removeItem(AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY); }) {
}
}
async function openAutoSkipFailuresConfirmModal() {
const result = await openActionModal({ const result = await openActionModal({
title: '兜底说明', title,
message: '开启后,当某一轮失败且无法继续时,会直接放弃当前线程,重新开新一轮,直到补足目标运行次数。线程间隔只在开启兜底且运行次数大于 1 时生效。', message,
actions: [ actions: [
{ id: null, label: '取消', variant: 'btn-ghost' }, { id: null, label: '取消', variant: 'btn-ghost' },
{ id: 'confirm', label: '确认开启', variant: 'btn-primary' }, { id: 'confirm', label: confirmLabel, variant: confirmVariant },
], ],
option: { option: {
label: '不再提示', label: optionLabel,
checked: false, checked: optionChecked,
disabled: optionDisabled,
}, },
buildResult: (choice, meta) => ({ buildResult: (choice, meta) => ({
choice, choice,
@@ -383,7 +383,69 @@ async function openAutoSkipFailuresConfirmModal() {
return { return {
confirmed: result?.choice === 'confirm', confirmed: result?.choice === 'confirm',
dismissPrompt: Boolean(result?.optionChecked), optionChecked: Boolean(result?.optionChecked),
};
}
function isPromptDismissed(storageKey) {
return localStorage.getItem(storageKey) === '1';
}
function setPromptDismissed(storageKey, dismissed) {
if (dismissed) {
localStorage.setItem(storageKey, '1');
} else {
localStorage.removeItem(storageKey);
}
}
function isAutoSkipFailuresPromptDismissed() {
return isPromptDismissed(AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY);
}
function setAutoSkipFailuresPromptDismissed(dismissed) {
setPromptDismissed(AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY, dismissed);
}
function isAutoRunFallbackRiskPromptDismissed() {
return isPromptDismissed(AUTO_RUN_FALLBACK_RISK_PROMPT_DISMISSED_STORAGE_KEY);
}
function setAutoRunFallbackRiskPromptDismissed(dismissed) {
setPromptDismissed(AUTO_RUN_FALLBACK_RISK_PROMPT_DISMISSED_STORAGE_KEY, dismissed);
}
async function openAutoSkipFailuresConfirmModal() {
const result = await openConfirmModalWithOption({
title: '兜底说明',
message: '开启后,当某一轮失败且无法继续时,会直接放弃当前线程,重新开新一轮,直到补足目标运行次数。线程间隔只在开启兜底且运行次数大于 1 时生效。',
confirmLabel: '确认开启',
});
return {
confirmed: result.confirmed,
dismissPrompt: result.optionChecked,
};
}
function shouldWarnAutoRunFallbackRisk(totalRuns, autoRunSkipFailures) {
return Boolean(autoRunSkipFailures) && totalRuns >= AUTO_RUN_FALLBACK_RISK_WARNING_MIN_RUNS;
}
async function openAutoRunFallbackRiskConfirmModal(totalRuns, fallbackThreadIntervalMinutes) {
const intervalLabel = Number.isFinite(fallbackThreadIntervalMinutes)
? `${fallbackThreadIntervalMinutes} 分钟`
: '未设置';
const result = await openConfirmModalWithOption({
title: '自动运行风险提醒',
message: `当前设置为 ${totalRuns} 轮自动化,已开启兜底,线程间隔为 ${intervalLabel}。次数太多,可能会因为 IP 短时间注册过多原因而都失败。建议控制在 ${AUTO_RUN_FALLBACK_RISK_WARNING_MIN_RUNS} 轮以下,并将线程间隔设置在 ${AUTO_RUN_FALLBACK_RISK_RECOMMENDED_THREAD_INTERVAL_MINUTES} 分钟以上。是否继续?`,
confirmLabel: '继续',
});
return {
confirmed: result.confirmed,
dismissPrompt: result.optionChecked,
}; };
} }
@@ -2488,7 +2550,7 @@ btnAutoStartClose?.addEventListener('click', () => resolveModalChoice(null));
// Auto Run // Auto Run
btnAutoRun.addEventListener('click', async () => { btnAutoRun.addEventListener('click', async () => {
try { try {
const totalRuns = Math.min(50, Math.max(1, parseInt(inputRunCount.value, 10) || 1)); const totalRuns = getRunCountValue();
let mode = 'restart'; let mode = 'restart';
if (shouldOfferAutoModeChoice()) { if (shouldOfferAutoModeChoice()) {
@@ -2501,6 +2563,25 @@ btnAutoRun.addEventListener('click', async () => {
mode = choice; mode = choice;
} }
const autoRunSkipFailures = inputAutoSkipFailures.checked;
const fallbackThreadIntervalMinutes = normalizeAutoRunThreadIntervalMinutes(
inputAutoSkipFailuresThreadIntervalMinutes.value
);
inputAutoSkipFailuresThreadIntervalMinutes.value = String(fallbackThreadIntervalMinutes);
if (
shouldWarnAutoRunFallbackRisk(totalRuns, autoRunSkipFailures)
&& !isAutoRunFallbackRiskPromptDismissed()
) {
const result = await openAutoRunFallbackRiskConfirmModal(totalRuns, fallbackThreadIntervalMinutes);
if (!result.confirmed) {
return;
}
if (result.dismissPrompt) {
setAutoRunFallbackRiskPromptDismissed(true);
}
}
btnAutoRun.disabled = true; btnAutoRun.disabled = true;
inputRunCount.disabled = true; inputRunCount.disabled = true;
const delayEnabled = inputAutoDelayEnabled.checked; const delayEnabled = inputAutoDelayEnabled.checked;
@@ -2515,7 +2596,7 @@ btnAutoRun.addEventListener('click', async () => {
payload: { payload: {
totalRuns, totalRuns,
delayMinutes, delayMinutes,
autoRunSkipFailures: inputAutoSkipFailures.checked, autoRunSkipFailures,
mode, mode,
}, },
}); });