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 DEFAULT_LOCAL_CPA_STEP9_MODE = 'submit';
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 currentAutoRun = {
@@ -351,29 +354,26 @@ async function openConfirmModal({ title, message, confirmLabel = '确认', confi
return choice === 'confirm';
}
function isAutoSkipFailuresPromptDismissed() {
return localStorage.getItem(AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY) === '1';
}
function setAutoSkipFailuresPromptDismissed(dismissed) {
if (dismissed) {
localStorage.setItem(AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY, '1');
} else {
localStorage.removeItem(AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY);
}
}
async function openAutoSkipFailuresConfirmModal() {
async function openConfirmModalWithOption({
title,
message,
confirmLabel = '确认',
confirmVariant = 'btn-primary',
optionLabel = '不再提示',
optionChecked = false,
optionDisabled = false,
}) {
const result = await openActionModal({
title: '兜底说明',
message: '开启后,当某一轮失败且无法继续时,会直接放弃当前线程,重新开新一轮,直到补足目标运行次数。线程间隔只在开启兜底且运行次数大于 1 时生效。',
title,
message,
actions: [
{ id: null, label: '取消', variant: 'btn-ghost' },
{ id: 'confirm', label: '确认开启', variant: 'btn-primary' },
{ id: 'confirm', label: confirmLabel, variant: confirmVariant },
],
option: {
label: '不再提示',
checked: false,
label: optionLabel,
checked: optionChecked,
disabled: optionDisabled,
},
buildResult: (choice, meta) => ({
choice,
@@ -383,7 +383,69 @@ async function openAutoSkipFailuresConfirmModal() {
return {
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
btnAutoRun.addEventListener('click', async () => {
try {
const totalRuns = Math.min(50, Math.max(1, parseInt(inputRunCount.value, 10) || 1));
const totalRuns = getRunCountValue();
let mode = 'restart';
if (shouldOfferAutoModeChoice()) {
@@ -2501,6 +2563,25 @@ btnAutoRun.addEventListener('click', async () => {
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;
inputRunCount.disabled = true;
const delayEnabled = inputAutoDelayEnabled.checked;
@@ -2515,7 +2596,7 @@ btnAutoRun.addEventListener('click', async () => {
payload: {
totalRuns,
delayMinutes,
autoRunSkipFailures: inputAutoSkipFailures.checked,
autoRunSkipFailures,
mode,
},
});