mirror of
https://github.com/cnlimiter/codex-register.git
synced 2026-06-25 17:24:06 +08:00
feat(registration): 新增Outlook批量注册功能
- 前端界面添加Outlook批量注册选项和账户选择面板 - 后端API新增/registration/outlook-accounts和/registration/outlook-batch端点 - 支持批量选择Outlook账户、自动跳过已注册邮箱、随机间隔控制 - 更新requirements.txt依赖版本
This commit is contained in:
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
@@ -112,6 +112,44 @@ class TaskListResponse(BaseModel):
|
||||
tasks: List[RegistrationTaskResponse]
|
||||
|
||||
|
||||
# ============== Outlook 批量注册模型 ==============
|
||||
|
||||
class OutlookAccountForRegistration(BaseModel):
|
||||
"""可用于注册的 Outlook 账户"""
|
||||
id: int # EmailService 表的 ID
|
||||
email: str
|
||||
name: str
|
||||
has_oauth: bool # 是否有 OAuth 配置
|
||||
is_registered: bool # 是否已注册
|
||||
registered_account_id: Optional[int] = None
|
||||
|
||||
|
||||
class OutlookAccountsListResponse(BaseModel):
|
||||
"""Outlook 账户列表响应"""
|
||||
total: int
|
||||
registered_count: int # 已注册数量
|
||||
unregistered_count: int # 未注册数量
|
||||
accounts: List[OutlookAccountForRegistration]
|
||||
|
||||
|
||||
class OutlookBatchRegistrationRequest(BaseModel):
|
||||
"""Outlook 批量注册请求"""
|
||||
service_ids: List[int] # 选中的 EmailService ID
|
||||
skip_registered: bool = True # 自动跳过已注册邮箱
|
||||
proxy: Optional[str] = None
|
||||
interval_min: int = 5
|
||||
interval_max: int = 30
|
||||
|
||||
|
||||
class OutlookBatchRegistrationResponse(BaseModel):
|
||||
"""Outlook 批量注册响应"""
|
||||
batch_id: str
|
||||
total: int # 总数
|
||||
skipped: int # 跳过数(已注册)
|
||||
to_register: int # 待注册数
|
||||
service_ids: List[int] # 实际要注册的服务 ID
|
||||
|
||||
|
||||
# ============== Helper Functions ==============
|
||||
|
||||
def task_to_response(task: RegistrationTask) -> RegistrationTaskResponse:
|
||||
@@ -688,3 +726,285 @@ async def get_available_email_services():
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# ============== Outlook 批量注册 API ==============
|
||||
|
||||
@router.get("/outlook-accounts", response_model=OutlookAccountsListResponse)
|
||||
async def get_outlook_accounts_for_registration():
|
||||
"""
|
||||
获取可用于注册的 Outlook 账户列表
|
||||
|
||||
返回所有已启用的 Outlook 服务,并检查每个邮箱是否已在 accounts 表中注册
|
||||
"""
|
||||
from ...database.models import EmailService as EmailServiceModel
|
||||
from ...database.models import Account
|
||||
|
||||
with get_db() as db:
|
||||
# 获取所有启用的 Outlook 服务
|
||||
outlook_services = db.query(EmailServiceModel).filter(
|
||||
EmailServiceModel.service_type == "outlook",
|
||||
EmailServiceModel.enabled == True
|
||||
).order_by(EmailServiceModel.priority.asc()).all()
|
||||
|
||||
accounts = []
|
||||
registered_count = 0
|
||||
unregistered_count = 0
|
||||
|
||||
for service in outlook_services:
|
||||
config = service.config or {}
|
||||
email = config.get("email") or service.name
|
||||
|
||||
# 检查是否已注册(查询 accounts 表)
|
||||
existing_account = db.query(Account).filter(
|
||||
Account.email == email
|
||||
).first()
|
||||
|
||||
is_registered = existing_account is not None
|
||||
if is_registered:
|
||||
registered_count += 1
|
||||
else:
|
||||
unregistered_count += 1
|
||||
|
||||
accounts.append(OutlookAccountForRegistration(
|
||||
id=service.id,
|
||||
email=email,
|
||||
name=service.name,
|
||||
has_oauth=bool(config.get("client_id") and config.get("refresh_token")),
|
||||
is_registered=is_registered,
|
||||
registered_account_id=existing_account.id if existing_account else None
|
||||
))
|
||||
|
||||
return OutlookAccountsListResponse(
|
||||
total=len(accounts),
|
||||
registered_count=registered_count,
|
||||
unregistered_count=unregistered_count,
|
||||
accounts=accounts
|
||||
)
|
||||
|
||||
|
||||
async def run_outlook_batch_registration(
|
||||
batch_id: str,
|
||||
service_ids: List[int],
|
||||
skip_registered: bool,
|
||||
proxy: Optional[str],
|
||||
interval_min: int,
|
||||
interval_max: int
|
||||
):
|
||||
"""
|
||||
异步执行 Outlook 批量注册任务
|
||||
|
||||
遍历选中的 Outlook 服务,检查邮箱是否已注册,执行注册任务
|
||||
"""
|
||||
from ...database.models import EmailService as EmailServiceModel
|
||||
from ...database.models import Account
|
||||
|
||||
batch_tasks[batch_id] = {
|
||||
"total": len(service_ids),
|
||||
"completed": 0,
|
||||
"success": 0,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"cancelled": False,
|
||||
"service_ids": service_ids,
|
||||
"current_index": 0,
|
||||
"logs": []
|
||||
}
|
||||
|
||||
try:
|
||||
for i, service_id in enumerate(service_ids):
|
||||
# 检查是否已取消
|
||||
if batch_tasks[batch_id]["cancelled"]:
|
||||
logger.info(f"Outlook 批量任务 {batch_id} 已取消")
|
||||
break
|
||||
|
||||
batch_tasks[batch_id]["current_index"] = i
|
||||
|
||||
with get_db() as db:
|
||||
# 获取邮箱服务
|
||||
service = db.query(EmailServiceModel).filter(
|
||||
EmailServiceModel.id == service_id
|
||||
).first()
|
||||
|
||||
if not service:
|
||||
batch_tasks[batch_id]["logs"].append(f"[跳过] 服务 ID {service_id} 不存在")
|
||||
batch_tasks[batch_id]["skipped"] += 1
|
||||
batch_tasks[batch_id]["completed"] += 1
|
||||
continue
|
||||
|
||||
config = service.config or {}
|
||||
email = config.get("email") or service.name
|
||||
|
||||
# 检查是否已注册
|
||||
if skip_registered:
|
||||
existing_account = db.query(Account).filter(
|
||||
Account.email == email
|
||||
).first()
|
||||
|
||||
if existing_account:
|
||||
batch_tasks[batch_id]["logs"].append(f"[跳过] {email} 已注册 (账号 ID: {existing_account.id})")
|
||||
batch_tasks[batch_id]["skipped"] += 1
|
||||
batch_tasks[batch_id]["completed"] += 1
|
||||
continue
|
||||
|
||||
# 创建注册任务
|
||||
task_uuid = str(uuid.uuid4())
|
||||
task = crud.create_registration_task(
|
||||
db,
|
||||
task_uuid=task_uuid,
|
||||
proxy=proxy,
|
||||
email_service_id=service_id
|
||||
)
|
||||
|
||||
batch_tasks[batch_id]["logs"].append(f"[注册] 开始注册 {email}...")
|
||||
|
||||
# 运行单个注册任务
|
||||
await run_registration_task(
|
||||
task_uuid, "outlook", proxy, None, service_id
|
||||
)
|
||||
|
||||
# 更新统计
|
||||
with get_db() as db:
|
||||
task = crud.get_registration_task(db, task_uuid)
|
||||
if task:
|
||||
batch_tasks[batch_id]["completed"] += 1
|
||||
if task.status == "completed":
|
||||
batch_tasks[batch_id]["success"] += 1
|
||||
batch_tasks[batch_id]["logs"].append(f"[成功] {email} 注册成功")
|
||||
elif task.status == "failed":
|
||||
batch_tasks[batch_id]["failed"] += 1
|
||||
batch_tasks[batch_id]["logs"].append(f"[失败] {email} 注册失败: {task.error_message}")
|
||||
|
||||
# 如果不是最后一个任务,等待随机间隔
|
||||
if i < len(service_ids) - 1 and not batch_tasks[batch_id]["cancelled"]:
|
||||
wait_time = random.randint(interval_min, interval_max)
|
||||
logger.info(f"Outlook 批量任务 {batch_id}: 等待 {wait_time} 秒后继续下一个任务")
|
||||
await asyncio.sleep(wait_time)
|
||||
|
||||
logger.info(f"Outlook 批量任务 {batch_id} 完成: 成功 {batch_tasks[batch_id]['success']}, 失败 {batch_tasks[batch_id]['failed']}, 跳过 {batch_tasks[batch_id]['skipped']}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Outlook 批量任务 {batch_id} 异常: {e}")
|
||||
batch_tasks[batch_id]["logs"].append(f"[错误] 批量任务异常: {str(e)}")
|
||||
finally:
|
||||
batch_tasks[batch_id]["finished"] = True
|
||||
|
||||
|
||||
@router.post("/outlook-batch", response_model=OutlookBatchRegistrationResponse)
|
||||
async def start_outlook_batch_registration(
|
||||
request: OutlookBatchRegistrationRequest,
|
||||
background_tasks: BackgroundTasks
|
||||
):
|
||||
"""
|
||||
启动 Outlook 批量注册任务
|
||||
|
||||
- service_ids: 选中的 EmailService ID 列表
|
||||
- skip_registered: 是否自动跳过已注册邮箱(默认 True)
|
||||
- proxy: 代理地址
|
||||
- interval_min: 最小间隔秒数
|
||||
- interval_max: 最大间隔秒数
|
||||
"""
|
||||
from ...database.models import EmailService as EmailServiceModel
|
||||
from ...database.models import Account
|
||||
|
||||
# 验证参数
|
||||
if not request.service_ids:
|
||||
raise HTTPException(status_code=400, detail="请选择至少一个 Outlook 账户")
|
||||
|
||||
if request.interval_min < 0 or request.interval_max < request.interval_min:
|
||||
raise HTTPException(status_code=400, detail="间隔时间参数无效")
|
||||
|
||||
# 过滤掉已注册的邮箱
|
||||
actual_service_ids = request.service_ids
|
||||
skipped_count = 0
|
||||
|
||||
if request.skip_registered:
|
||||
actual_service_ids = []
|
||||
with get_db() as db:
|
||||
for service_id in request.service_ids:
|
||||
service = db.query(EmailServiceModel).filter(
|
||||
EmailServiceModel.id == service_id
|
||||
).first()
|
||||
|
||||
if not service:
|
||||
continue
|
||||
|
||||
config = service.config or {}
|
||||
email = config.get("email") or service.name
|
||||
|
||||
# 检查是否已注册
|
||||
existing_account = db.query(Account).filter(
|
||||
Account.email == email
|
||||
).first()
|
||||
|
||||
if existing_account:
|
||||
skipped_count += 1
|
||||
else:
|
||||
actual_service_ids.append(service_id)
|
||||
|
||||
if not actual_service_ids:
|
||||
return OutlookBatchRegistrationResponse(
|
||||
batch_id="",
|
||||
total=len(request.service_ids),
|
||||
skipped=skipped_count,
|
||||
to_register=0,
|
||||
service_ids=[]
|
||||
)
|
||||
|
||||
# 创建批量任务
|
||||
batch_id = str(uuid.uuid4())
|
||||
|
||||
# 初始化批量任务状态
|
||||
batch_tasks[batch_id] = {
|
||||
"total": len(actual_service_ids),
|
||||
"completed": 0,
|
||||
"success": 0,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"cancelled": False,
|
||||
"service_ids": actual_service_ids,
|
||||
"current_index": 0,
|
||||
"logs": [],
|
||||
"finished": False
|
||||
}
|
||||
|
||||
# 在后台运行批量注册
|
||||
background_tasks.add_task(
|
||||
run_outlook_batch_registration,
|
||||
batch_id,
|
||||
actual_service_ids,
|
||||
request.skip_registered,
|
||||
request.proxy,
|
||||
request.interval_min,
|
||||
request.interval_max
|
||||
)
|
||||
|
||||
return OutlookBatchRegistrationResponse(
|
||||
batch_id=batch_id,
|
||||
total=len(request.service_ids),
|
||||
skipped=skipped_count,
|
||||
to_register=len(actual_service_ids),
|
||||
service_ids=actual_service_ids
|
||||
)
|
||||
|
||||
|
||||
@router.get("/outlook-batch/{batch_id}")
|
||||
async def get_outlook_batch_status(batch_id: str):
|
||||
"""获取 Outlook 批量任务状态"""
|
||||
if batch_id not in batch_tasks:
|
||||
raise HTTPException(status_code=404, detail="批量任务不存在")
|
||||
|
||||
batch = batch_tasks[batch_id]
|
||||
return {
|
||||
"batch_id": batch_id,
|
||||
"total": batch["total"],
|
||||
"completed": batch["completed"],
|
||||
"success": batch["success"],
|
||||
"failed": batch["failed"],
|
||||
"skipped": batch.get("skipped", 0),
|
||||
"current_index": batch["current_index"],
|
||||
"cancelled": batch["cancelled"],
|
||||
"finished": batch.get("finished", False),
|
||||
"logs": batch.get("logs", []),
|
||||
"progress": f"{batch['completed']}/{batch['total']}"
|
||||
}
|
||||
|
||||
218
static/js/app.js
218
static/js/app.js
@@ -10,6 +10,8 @@ let logPollingInterval = null;
|
||||
let batchPollingInterval = null;
|
||||
let accountsPollingInterval = null;
|
||||
let isBatchMode = false;
|
||||
let isOutlookBatchMode = false;
|
||||
let outlookAccounts = [];
|
||||
let availableServices = {
|
||||
tempmail: { available: true, services: [] },
|
||||
outlook: { available: false, services: [] },
|
||||
@@ -21,6 +23,7 @@ const elements = {
|
||||
form: document.getElementById('registration-form'),
|
||||
emailService: document.getElementById('email-service'),
|
||||
regMode: document.getElementById('reg-mode'),
|
||||
regModeGroup: document.getElementById('reg-mode-group'),
|
||||
batchCountGroup: document.getElementById('batch-count-group'),
|
||||
batchCount: document.getElementById('batch-count'),
|
||||
batchOptions: document.getElementById('batch-options'),
|
||||
@@ -47,7 +50,13 @@ const elements = {
|
||||
batchRemaining: document.getElementById('batch-remaining'),
|
||||
// 已注册账号
|
||||
recentAccountsTable: document.getElementById('recent-accounts-table'),
|
||||
refreshAccountsBtn: document.getElementById('refresh-accounts-btn')
|
||||
refreshAccountsBtn: document.getElementById('refresh-accounts-btn'),
|
||||
// Outlook 批量注册
|
||||
outlookBatchSection: document.getElementById('outlook-batch-section'),
|
||||
outlookAccountsContainer: document.getElementById('outlook-accounts-container'),
|
||||
outlookIntervalMin: document.getElementById('outlook-interval-min'),
|
||||
outlookIntervalMax: document.getElementById('outlook-interval-max'),
|
||||
outlookSkipRegistered: document.getElementById('outlook-skip-registered')
|
||||
};
|
||||
|
||||
// 初始化
|
||||
@@ -136,6 +145,13 @@ function updateEmailServiceOptions() {
|
||||
});
|
||||
|
||||
select.appendChild(optgroup);
|
||||
|
||||
// Outlook 批量注册选项
|
||||
const batchOption = document.createElement('option');
|
||||
batchOption.value = 'outlook_batch:all';
|
||||
batchOption.textContent = `📋 Outlook 批量注册 (${availableServices.outlook.count} 个账户)`;
|
||||
batchOption.dataset.type = 'outlook_batch';
|
||||
optgroup.appendChild(batchOption);
|
||||
} else {
|
||||
const optgroup = document.createElement('optgroup');
|
||||
optgroup.label = '📧 Outlook (未配置)';
|
||||
@@ -188,6 +204,22 @@ function handleServiceChange(e) {
|
||||
const [type, id] = value.split(':');
|
||||
const selectedOption = e.target.options[e.target.selectedIndex];
|
||||
|
||||
// 处理 Outlook 批量注册模式
|
||||
if (type === 'outlook_batch') {
|
||||
isOutlookBatchMode = true;
|
||||
elements.outlookBatchSection.style.display = 'block';
|
||||
elements.regModeGroup.style.display = 'none';
|
||||
elements.batchCountGroup.style.display = 'none';
|
||||
elements.batchOptions.style.display = 'none';
|
||||
loadOutlookAccounts();
|
||||
addLog('info', '[系统] 已切换到 Outlook 批量注册模式');
|
||||
return;
|
||||
} else {
|
||||
isOutlookBatchMode = false;
|
||||
elements.outlookBatchSection.style.display = 'none';
|
||||
elements.regModeGroup.style.display = 'block';
|
||||
}
|
||||
|
||||
// 显示服务信息
|
||||
if (type === 'outlook') {
|
||||
const service = availableServices.outlook.services.find(s => s.id == id);
|
||||
@@ -221,6 +253,12 @@ async function handleStartRegistration(e) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理 Outlook 批量注册模式
|
||||
if (isOutlookBatchMode) {
|
||||
await handleOutlookBatchRegistration();
|
||||
return;
|
||||
}
|
||||
|
||||
const [emailServiceType, serviceId] = selectedValue.split(':');
|
||||
|
||||
// 禁用开始按钮
|
||||
@@ -595,6 +633,8 @@ function resetButtons() {
|
||||
elements.cancelBtn.disabled = true;
|
||||
currentTask = null;
|
||||
currentBatch = null;
|
||||
isBatchMode = false;
|
||||
// 注意:不重置 isOutlookBatchMode,因为用户可能想继续使用 Outlook 批量模式
|
||||
}
|
||||
|
||||
// HTML 转义
|
||||
@@ -604,3 +644,179 @@ function escapeHtml(text) {
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
|
||||
// ============== Outlook 批量注册功能 ==============
|
||||
|
||||
// 加载 Outlook 账户列表
|
||||
async function loadOutlookAccounts() {
|
||||
try {
|
||||
elements.outlookAccountsContainer.innerHTML = '<div class="loading-placeholder" style="text-align: center; padding: var(--spacing-md); color: var(--text-muted);">加载中...</div>';
|
||||
|
||||
const data = await api.get('/registration/outlook-accounts');
|
||||
outlookAccounts = data.accounts || [];
|
||||
|
||||
renderOutlookAccountsList();
|
||||
|
||||
addLog('info', `[系统] 已加载 ${data.total} 个 Outlook 账户 (已注册: ${data.registered_count}, 未注册: ${data.unregistered_count})`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载 Outlook 账户列表失败:', error);
|
||||
elements.outlookAccountsContainer.innerHTML = `<div style="text-align: center; padding: var(--spacing-md); color: var(--text-muted);">加载失败: ${error.message}</div>`;
|
||||
addLog('error', `[错误] 加载 Outlook 账户列表失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染 Outlook 账户列表
|
||||
function renderOutlookAccountsList() {
|
||||
if (outlookAccounts.length === 0) {
|
||||
elements.outlookAccountsContainer.innerHTML = '<div style="text-align: center; padding: var(--spacing-md); color: var(--text-muted);">没有可用的 Outlook 账户</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
const html = outlookAccounts.map(account => `
|
||||
<label class="outlook-account-item" style="display: flex; align-items: center; padding: var(--spacing-sm); border-bottom: 1px solid var(--border-light); cursor: pointer; ${account.is_registered ? 'opacity: 0.6;' : ''}" data-id="${account.id}" data-registered="${account.is_registered}">
|
||||
<input type="checkbox" class="outlook-account-checkbox" value="${account.id}" ${account.is_registered ? '' : 'checked'} style="margin-right: var(--spacing-sm);">
|
||||
<div style="flex: 1;">
|
||||
<div style="font-weight: 500;">${escapeHtml(account.email)}</div>
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted);">
|
||||
${account.is_registered
|
||||
? `<span style="color: var(--success-color);">✓ 已注册</span>`
|
||||
: '<span style="color: var(--primary-color);">未注册</span>'
|
||||
}
|
||||
${account.has_oauth ? ' | OAuth' : ''}
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
`).join('');
|
||||
|
||||
elements.outlookAccountsContainer.innerHTML = html;
|
||||
}
|
||||
|
||||
// 全选
|
||||
function selectAllOutlookAccounts() {
|
||||
const checkboxes = document.querySelectorAll('.outlook-account-checkbox');
|
||||
checkboxes.forEach(cb => cb.checked = true);
|
||||
}
|
||||
|
||||
// 只选未注册
|
||||
function selectUnregisteredOutlook() {
|
||||
const items = document.querySelectorAll('.outlook-account-item');
|
||||
items.forEach(item => {
|
||||
const checkbox = item.querySelector('.outlook-account-checkbox');
|
||||
const isRegistered = item.dataset.registered === 'true';
|
||||
checkbox.checked = !isRegistered;
|
||||
});
|
||||
}
|
||||
|
||||
// 取消全选
|
||||
function deselectAllOutlookAccounts() {
|
||||
const checkboxes = document.querySelectorAll('.outlook-account-checkbox');
|
||||
checkboxes.forEach(cb => cb.checked = false);
|
||||
}
|
||||
|
||||
// 处理 Outlook 批量注册
|
||||
async function handleOutlookBatchRegistration() {
|
||||
// 获取选中的账户
|
||||
const selectedIds = [];
|
||||
document.querySelectorAll('.outlook-account-checkbox:checked').forEach(cb => {
|
||||
selectedIds.push(parseInt(cb.value));
|
||||
});
|
||||
|
||||
if (selectedIds.length === 0) {
|
||||
toast.error('请选择至少一个 Outlook 账户');
|
||||
return;
|
||||
}
|
||||
|
||||
const intervalMin = parseInt(elements.outlookIntervalMin.value) || 5;
|
||||
const intervalMax = parseInt(elements.outlookIntervalMax.value) || 30;
|
||||
const skipRegistered = elements.outlookSkipRegistered.checked;
|
||||
|
||||
// 禁用开始按钮
|
||||
elements.startBtn.disabled = true;
|
||||
elements.cancelBtn.disabled = false;
|
||||
|
||||
// 清空日志
|
||||
elements.consoleLog.innerHTML = '';
|
||||
|
||||
const requestData = {
|
||||
service_ids: selectedIds,
|
||||
skip_registered: skipRegistered,
|
||||
interval_min: intervalMin,
|
||||
interval_max: intervalMax
|
||||
};
|
||||
|
||||
addLog('info', `[系统] 正在启动 Outlook 批量注册 (${selectedIds.length} 个账户)...`);
|
||||
|
||||
try {
|
||||
const data = await api.post('/registration/outlook-batch', requestData);
|
||||
|
||||
if (data.to_register === 0) {
|
||||
addLog('warning', '[警告] 所有选中的邮箱都已注册,无需重复注册');
|
||||
toast.warning('所有选中的邮箱都已注册');
|
||||
resetButtons();
|
||||
return;
|
||||
}
|
||||
|
||||
currentBatch = { batch_id: data.batch_id, ...data };
|
||||
addLog('info', `[系统] 批量任务已创建: ${data.batch_id}`);
|
||||
addLog('info', `[系统] 总数: ${data.total}, 跳过已注册: ${data.skipped}, 待注册: ${data.to_register}`);
|
||||
|
||||
// 初始化批量状态显示
|
||||
showBatchStatus({ count: data.to_register });
|
||||
|
||||
// 开始轮询批量状态
|
||||
startOutlookBatchPolling(data.batch_id);
|
||||
|
||||
} catch (error) {
|
||||
addLog('error', `[错误] 启动失败: ${error.message}`);
|
||||
toast.error(error.message);
|
||||
resetButtons();
|
||||
}
|
||||
}
|
||||
|
||||
// 开始轮询 Outlook 批量状态
|
||||
function startOutlookBatchPolling(batchId) {
|
||||
batchPollingInterval = setInterval(async () => {
|
||||
try {
|
||||
const data = await api.get(`/registration/outlook-batch/${batchId}`);
|
||||
|
||||
// 更新进度
|
||||
updateBatchProgress({
|
||||
total: data.total,
|
||||
completed: data.completed,
|
||||
success: data.success,
|
||||
failed: data.failed
|
||||
});
|
||||
|
||||
// 输出日志
|
||||
if (data.logs && data.logs.length > 0) {
|
||||
const lastLogIndex = batchPollingInterval.lastLogIndex || 0;
|
||||
for (let i = lastLogIndex; i < data.logs.length; i++) {
|
||||
const log = data.logs[i];
|
||||
const logType = getLogType(log);
|
||||
addLog(logType, log);
|
||||
}
|
||||
batchPollingInterval.lastLogIndex = data.logs.length;
|
||||
}
|
||||
|
||||
// 检查是否完成
|
||||
if (data.finished) {
|
||||
stopBatchPolling();
|
||||
resetButtons();
|
||||
|
||||
addLog('info', `[完成] Outlook 批量任务完成!成功: ${data.success}, 失败: ${data.failed}, 跳过: ${data.skipped || 0}`);
|
||||
if (data.success > 0) {
|
||||
toast.success(`Outlook 批量注册完成,成功 ${data.success} 个`);
|
||||
loadRecentAccounts();
|
||||
} else {
|
||||
toast.warning('Outlook 批量注册完成,但没有成功注册任何账号');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('轮询 Outlook 批量状态失败:', error);
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
batchPollingInterval.lastLogIndex = 0;
|
||||
}
|
||||
|
||||
@@ -130,10 +130,42 @@
|
||||
<option value="tempmail">Tempmail.lol (临时邮箱)</option>
|
||||
<option value="outlook">Outlook</option>
|
||||
<option value="custom_domain">自定义域名</option>
|
||||
<option value="outlook_batch">Outlook 批量注册</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<!-- Outlook 批量注册区域 -->
|
||||
<div id="outlook-batch-section" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label>选择账户</label>
|
||||
<div id="outlook-accounts-container" style="max-height: 200px; overflow-y: auto; border: 1px solid var(--border-light); border-radius: var(--radius); padding: var(--spacing-sm);">
|
||||
<div class="loading-placeholder" style="text-align: center; padding: var(--spacing-md); color: var(--text-muted);">
|
||||
加载中...
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: var(--spacing-sm); display: flex; gap: var(--spacing-xs); flex-wrap: wrap;">
|
||||
<button type="button" class="btn btn-ghost btn-sm" onclick="selectAllOutlookAccounts()">全选</button>
|
||||
<button type="button" class="btn btn-ghost btn-sm" onclick="selectUnregisteredOutlook()">只选未注册</button>
|
||||
<button type="button" class="btn btn-ghost btn-sm" onclick="deselectAllOutlookAccounts()">取消全选</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="outlook-interval-min">最小间隔 (秒)</label>
|
||||
<input type="number" id="outlook-interval-min" name="outlook_interval_min" min="0" max="300" value="5">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="outlook-interval-max">最大间隔 (秒)</label>
|
||||
<input type="number" id="outlook-interval-max" name="outlook_interval_max" min="1" max="600" value="30">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label style="display: flex; align-items: center; gap: var(--spacing-sm); cursor: pointer;">
|
||||
<input type="checkbox" id="outlook-skip-registered" checked>
|
||||
<span>自动跳过已注册的邮箱</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="reg-mode-group">
|
||||
<label for="reg-mode">注册模式</label>
|
||||
<select id="reg-mode" name="reg_mode">
|
||||
<option value="single">单次注册</option>
|
||||
|
||||
Reference in New Issue
Block a user