feat: 添加自动运行风险提示功能,优化用户确认流程
This commit is contained in:
+102
-21
@@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user