feat: 按任务管理比特浏览器临时窗口

This commit is contained in:
2026-09-23 18:15:08 +08:00
parent 04309f60c7
commit ff2879f102
15 changed files with 577 additions and 226 deletions
+4 -65
View File
@@ -177,7 +177,6 @@ function geminiApp() {
inlineEditRechargeStatusEmail: null,
inlineEditAccountRefundEmail: null,
inlineEditRefundProcessEmail: null,
importAutoSetup: true,
exportFields: {
email: true, password: true, recovery_email: true, secret_key: true,
country: false, sheerid_link: false, status: false, message: false, customer_name: false,
@@ -1316,17 +1315,8 @@ function geminiApp() {
this.accountPage = 1;
await this.loadAccounts();
// 自动初始化:测速 → 创建浏览器 → 设置代理
if (this.importAutoSetup && importedEmails.length > 0) {
const importedEmailSet = new Set(importedEmails);
const setupAccounts = this.accounts.filter(a => importedEmailSet.has(a.email));
if (setupAccounts.length > 0) {
await new Promise(resolve => {
if (typeof requestAnimationFrame === 'function') requestAnimationFrame(() => resolve());
else setTimeout(resolve, 0);
});
await this._runImportSetup(setupAccounts);
}
if (importedEmails.length > 0) {
this.addLog('账号已入库;执行具体任务时会自动创建临时比特浏览器,任务结束后自动删除', 'info');
}
} else {
this.addLog(`导入失败: ${data.msg}`, 'error');
@@ -1336,44 +1326,6 @@ function geminiApp() {
}
},
async _runImportSetup(accounts) {
if (this.isRunning) {
this.addLog('⚠️ 有任务正在运行,跳过自动初始化', 'warn');
return;
}
// 大批量任务默认收起日志,避免数百条日志同时参与 DOM 更新。
this.logDrawerOpen = accounts.length <= 200;
this.clearLogs();
this.addLog(`🚀 开始初始化 ${accounts.length} 个账号(测速 / 创建浏览器 / 设置代理)...`, 'info');
try {
const res = await fetch('/api/operations/run', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
taskType: 'import_setup',
accounts,
params: { threadCount: parseInt(this.threadCount) },
}),
});
const data = await res.json();
if (!data.success) {
this.addLog(`❌ 启动失败: ${data.msg}`, 'error');
return;
}
this.currentTaskId = data.taskId;
this._rememberTaskBatch('import_setup', accounts, data.taskId);
this._activeTaskType = 'import_setup';
this._setActiveTaskEmails(this._lastTaskEmails);
this._activeTaskStartedAt = this._lastTaskStartedAt;
this.isRunning = true;
this.isPaused = false;
this._rebuildDashboardStats();
this.startSSEListener(data.taskId);
} catch (e) {
this.addLog(`❌ 网络错误: ${e.message}`, 'error');
}
},
async deleteSelectedAccounts() {
if (this.selectedEmails.size === 0) return;
if (this.isDeletingAccounts) {
@@ -1564,18 +1516,8 @@ function geminiApp() {
this.stagedBatchDetail = null;
await Promise.all([this.loadStagingBatches(), this.loadAccounts()]);
const restoredAccounts = Array.isArray(data.accounts) ? data.accounts : [];
if (restoredAccounts.length === 0) {
this.addLog('⚠️ 账号已恢复,但没有取得创建窗口所需的账号数据', 'warn');
return;
}
this.addLog(`正在为恢复的 ${restoredAccounts.length} 个账号自动创建比特浏览器窗口`, 'info');
const started = await this.runTask(
'create_accounts',
{ reuseExistingBrowsers: true },
restoredAccounts,
);
if (!started) {
this.addLog('⚠️ 账号已回到主列表,但自动创建窗口任务启动失败,可勾选“刚刚运行”后点击创建浏览器重试', 'warn');
if (restoredAccounts.length > 0) {
this.addLog('恢复完成;执行具体任务时会自动创建临时比特浏览器', 'info');
}
} catch (e) {
this.addLog(`恢复失败: ${e.message}`, 'error');
@@ -2947,7 +2889,6 @@ function geminiApp() {
open: '等待打开浏览器...',
open_url: '等待打开网页...',
delete: '等待删除浏览器...',
import_setup: '等待初始化...',
custom_pipeline: '等待组合任务...',
};
return messages[taskType] || '等待处理...';
@@ -2972,7 +2913,6 @@ function geminiApp() {
ag_get_credential: '获取凭证', aistudio_combo: 'AI Studio 一键组合', aistudio_sync_key: '同步人工AI Key', gemini_cli_get_credential: '获取Cli凭证', ag_revoke_authorization: '取消授权',
google_account_ag_credential: '链接提取+获取凭证',
open: '打开浏览器', open_manual_aistudio: '打开浏览器(自动保存人工 Key)', open_url: '打开网页', delete: '删除浏览器',
import_setup: '账号初始化',
};
return labels[taskType] || taskType || '任务';
},
@@ -3429,7 +3369,6 @@ function geminiApp() {
},
// 各操作快捷方法
runCreateAccounts() { this.runTask('create_accounts'); },
runChangeProxy() { this.runTask('change_proxy'); },
runOpenBrowsers() {
this.runTask('open_manual_aistudio', { watchTimeoutMs: 30 * 60 * 1000 });
+6 -4
View File
@@ -204,7 +204,6 @@
<div class="btn-group">
<span class="btn-group-label">操作</span>
<button @click="openBatchStatusModal()" :disabled="selectedCount===0" class="btn btn-orange">更改状态</button>
<button @click="runCreateAccounts()" :disabled="isRunning" class="btn btn-primary">创建浏览器</button>
<button @click="runDeleteBrowsers()" :disabled="isRunning || selectedCount===0"
class="btn btn-red" title="删除所选账号的比特浏览器窗口并清空浏览器编号,账号保留">删除浏览器</button>
<button @click="runChangeProxy()" :disabled="isRunning" class="btn btn-primary">换代理</button>
@@ -2082,6 +2081,9 @@
<input type="checkbox" x-model="importSkipDuplicates" class="h-4 w-4">
<span>跳过重复邮箱(已有账号不做任何修改)</span>
</label>
<div class="text-xs text-blue-600 bg-blue-50 border border-blue-100 rounded p-2">
导入只保存账号;执行具体任务时才创建临时比特浏览器窗口,单个账号处理结束后自动删除。
</div>
<!-- 解析预览(第1行) -->
<template x-if="importText.trim() && getImportPreview().length > 0">
@@ -2162,7 +2164,7 @@
<button @click="copyStagedBatch()" class="btn btn-primary">复制全部</button>
<button @click="downloadStagedBatch()" class="btn btn-green">导出 TXT</button>
<button @click="restoreStagedBatch()" :disabled="isRunning" class="btn btn-gray"
title="恢复后自动创建或复用比特浏览器窗口">恢复到主列表并创建窗口</button>
title="恢复只回写账号,具体任务执行时再创建临时比特窗口">恢复到主列表</button>
<button @click="permanentlyDeleteStagedBatch()" class="btn btn-red">彻底删除文件夹</button>
</div>
</div>
@@ -2355,13 +2357,13 @@
class="w-full" @keydown.enter.prevent="confirmGoogleAccountAgTask()">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">并发(1~30)</label>
<label class="block text-xs font-medium text-gray-600 mb-1">并发参数(兼容保留)</label>
<input type="number" min="1" max="30" step="1" x-model.number="googleAccountAgConcurrency"
class="w-full" @keydown.enter.prevent="confirmGoogleAccountAgTask()">
</div>
</div>
<div class="rounded border border-blue-100 bg-blue-50 p-3 text-xs text-blue-700 leading-5 mt-3">
供应数据中的辅助邮箱及后续字段会被忽略;数据库已有邮箱会跳过且不覆盖。创建浏览器时固定使用直连(无代理),并发同时用于浏览器创建和反重力凭证获取。
供应数据中的辅助邮箱及后续字段会被忽略;数据库已有邮箱会跳过且不覆盖。临时比特浏览器固定使用直连(无代理),并严格按邮箱串行处理:完成一个、删除一个,再开始下一个。
</div>
<div class="flex gap-2 mt-3">
<button @click="showGoogleAccountAgModal=false" class="btn btn-red">取消</button>