feat: 添加自定义邮箱注册功能,支持手动输入验证码并优化相关逻辑;更新前端界面以支持新功能。

This commit is contained in:
real-jacket
2025-03-30 18:43:47 +08:00
parent 9dd112f468
commit bb725d6d32
7 changed files with 3141 additions and 1850 deletions

1
.gitignore vendored
View File

@@ -52,3 +52,4 @@ temp/
*.pem
*.key
credentials.json
.history

151
api.py
View File

@@ -1,6 +1,6 @@
from fastapi import FastAPI, HTTPException, status, UploadFile, Request
from pydantic import BaseModel
from typing import Optional, List
from typing import Optional, List, Dict
from sqlalchemy import select, func, delete, desc
from pathlib import Path
from database import get_session, AccountModel, AccountUsageRecordModel, init_db
@@ -29,6 +29,12 @@ from fastapi.staticfiles import StaticFiles
from dotenv import load_dotenv
import json
import time
import uuid
# 从get_email_code.py导入验证码请求字典
from get_email_code import EmailVerificationHandler
# 修改为直接访问get_email_code模块
import get_email_code
# 全局状态追踪
registration_status = {
@@ -48,6 +54,9 @@ static_path.mkdir(exist_ok=True) # 确保目录存在
# 全局任务存储
background_tasks = {"registration_task": None}
# 添加用于存储等待验证码的邮箱信息的全局字典
# pending_verification_codes = {}
# 添加lifespan管理器在应用启动时初始化数据库
@asynccontextmanager
@@ -168,9 +177,9 @@ async def run_registration():
info("注册失败")
except SystemExit:
# 捕获 SystemExit 异常,这是注册脚本正常退出的方式
info("注册脚本正常退出")
if registration_status["last_status"] != "error":
registration_status["last_status"] = "completed"
info("注册脚本通过sys.exit退出")
registration_status["successful_runs"] += 1
registration_status["last_status"] = "completed"
except Exception as e:
error(f"注册过程执行出错: {str(e)}")
error(traceback.format_exc())
@@ -1423,7 +1432,141 @@ async def restart_service():
return {"success": False, "message": f"重启服务失败: {str(e)}"}
class CustomRegistrationRequest(BaseModel):
email: str
@app.post("/registration/custom", tags=["Registration"])
async def register_with_custom_email(request: CustomRegistrationRequest):
"""使用自定义邮箱注册Cursor账号"""
global registration_status
if registration_status["is_running"]:
return JSONResponse(
status_code=400,
content={
"success": False,
"message": "当前有注册任务正在运行,请先停止当前任务"
}
)
count = await get_active_account_count()
if count >= MAX_ACCOUNTS:
return JSONResponse(
status_code=400,
content={
"success": False,
"message": f"已达到最大账号数量 ({count}/{MAX_ACCOUNTS})"
}
)
# 验证邮箱格式
if "@" not in request.email:
return JSONResponse(
status_code=400,
content={
"success": False,
"message": "邮箱格式不正确,请提供正确的邮箱地址"
}
)
try:
info(f"开始使用自定义邮箱注册: {request.email}")
# 调用注册函数,传入自定义邮箱
try:
success = await asyncio.get_event_loop().run_in_executor(
None, lambda: register_account(custom_email=request.email)
)
if success:
return JSONResponse(
content={
"success": True,
"message": f"使用邮箱 {request.email} 注册成功"
}
)
else:
return JSONResponse(
status_code=500,
content={
"success": False,
"message": f"使用邮箱 {request.email} 注册失败"
}
)
except SystemExit:
# 处理注册函数通过sys.exit退出的情况
info("注册函数通过sys.exit退出可能已成功注册")
return JSONResponse(
content={
"success": True,
"message": f"使用邮箱 {request.email} 注册过程完成,请检查账号列表"
}
)
except Exception as e:
error(f"使用自定义邮箱注册过程出错: {str(e)}")
error(traceback.format_exc())
return JSONResponse(
status_code=500,
content={
"success": False,
"message": f"注册过程出错: {str(e)}"
}
)
@app.get("/verification/pending")
async def check_pending_verification():
"""检查是否有等待验证码输入的请求"""
# 返回所有等待验证的邮箱ID及邮箱地址
result = []
for email_id, email_info in get_email_code.pending_verification_codes.items():
if email_info.get("status") == "pending":
result.append({
"id": email_id,
"email": email_info.get("email"),
"created_at": email_info.get("created_at")
})
return {
"success": True,
"data": result
}
@app.post("/verification/submit")
async def submit_verification_code(code_data: Dict):
"""提交验证码"""
email_id = code_data.get("id")
code = code_data.get("code")
if not email_id or not code:
return {
"success": False,
"message": "缺少必要参数"
}
if email_id not in get_email_code.pending_verification_codes:
return {
"success": False,
"message": "未找到对应的验证请求"
}
# 更新状态和验证码
get_email_code.pending_verification_codes[email_id]["status"] = "submitted"
get_email_code.pending_verification_codes[email_id]["code"] = code
return {
"success": True,
"message": "验证码已提交"
}
if __name__ == "__main__":
# 设置Web模式环境变量
os.environ["CURSOR_AUTO_REGISTER_WEB"] = "true"
# 启动服务器
import uvicorn
uvicorn.run(
"api:app",
host=API_HOST,

View File

@@ -11,7 +11,9 @@ from config import (
EMAIL_DOMAINS,
REGISTRATION_MAX_RETRIES,
EMAIL_TYPE,
EMAIL_CODE_TYPE
EMAIL_CODE_TYPE,
EMAIL_USERNAME,
EMAIL_DOMAIN
)
@@ -182,7 +184,7 @@ def sign_up_account(browser, tab, account_info):
if (
tab.ele("verify the user is human. Please try again.")
or tab.ele("Can't verify the user is human. Please try again.")
or tab.ele("Cant verify the user is human. Please try again.")
or tab.ele("Can't verify the user is human. Please try again.")
):
info("检测到turnstile验证失败IP问题、UA问题、域名问题...正在重试...")
return "EMAIL_USED"
@@ -223,8 +225,8 @@ def sign_up_account(browser, tab, account_info):
info("注册限制")
return "SIGNUP_RESTRICTED"
# 创建邮件处理器
email_handler = EmailVerificationHandler()
# 创建邮件处理器,传入自定义邮箱
email_handler = EmailVerificationHandler(custom_email=account_info["email"])
i = 0
while i < 5:
try:
@@ -234,10 +236,26 @@ def sign_up_account(browser, tab, account_info):
break
if tab.ele("@data-index=0"):
info("等待输入验证码...")
# 切换到邮箱标签页
# 声明全局变量
global EMAIL_CODE_TYPE
# 获取当前的EMAIL_CODE_TYPE值
local_email_code_type = EMAIL_CODE_TYPE
if account_info["email"] != f"{EMAIL_USERNAME}@{EMAIL_DOMAIN}":
info(f"检测到使用自定义邮箱 {account_info['email']},确保使用手动输入验证码")
# 使用自定义邮箱时确保使用手动输入
if EMAIL_CODE_TYPE != "INPUT":
EMAIL_CODE_TYPE = "INPUT"
# 切换到邮箱标签页获取验证码
code = email_handler.get_verification_code(
source_email=account_info["email"]
)
# 如果临时修改了EMAIL_CODE_TYPE恢复原值
if EMAIL_CODE_TYPE != local_email_code_type:
EMAIL_CODE_TYPE = local_email_code_type
if code is None:
info("未获取到验证码...系统异常,正在退出....")
return "EMAIL_GET_CODE_FAILED"
@@ -329,9 +347,9 @@ class EmailGenerator:
domain = random.choice(self.domains)
return f"{random_str}@{domain}"
def get_account_info(self):
"""获取账号信息,确保每次调用都生成新的邮箱和密码"""
self.email = self.generate_email()
def get_account_info(self, email=None):
"""获取账号信息,确保每次调用都生成新的邮箱和密码,或使用提供的邮箱"""
self.email = email if email else self.generate_email()
self.password = self.generate_random_password()
return {
"email": self.email,
@@ -417,19 +435,29 @@ def cleanup_and_exit(browser_manager=None, exit_code=0):
sys.exit(1)
def main():
def main(custom_email=None):
browser_manager = None
max_retries = REGISTRATION_MAX_RETRIES # 从配置文件获取
current_retry = 0
# 先声明全局变量并保存原始值
global EMAIL_CODE_TYPE
original_email_code_type = EMAIL_CODE_TYPE
try:
email_handler = EmailVerificationHandler()
# 如果使用自定义邮箱,切换验证码获取模式为手动输入
if custom_email:
info(f"使用自定义邮箱 {custom_email},切换为手动输入验证码模式")
EMAIL_CODE_TYPE = "INPUT"
# 初始化邮箱验证处理器时传入自定义邮箱
email_handler = EmailVerificationHandler(custom_email=custom_email)
if email_handler.check():
info('邮箱服务连接正常,开始注册!')
else:
if EMAIL_CODE_TYPE == "API":
error('邮箱服务连接失败并且验证码为API获取结束注册!')
return
return False
else:
info('邮箱服务连接失败,并且验证码为手动输入,等待输入验证码...')
@@ -438,7 +466,8 @@ def main():
browser = browser_manager.init_browser()
while current_retry < max_retries:
try:
account_info = email_generator.get_account_info()
# 使用自定义邮箱或生成新邮箱
account_info = email_generator.get_account_info(email=custom_email)
info(
f"初始化账号信息成功 => 邮箱: {account_info['email']}, 用户名: {account_info['first_name']}, 密码: {account_info['password']}"
)
@@ -455,7 +484,10 @@ def main():
if token:
email_generator._save_account_info(user, token, TOTAL_USAGE)
info("注册流程完成")
cleanup_and_exit(browser_manager, 0)
# 关闭资源但不退出程序,只返回成功状态
if browser_manager and hasattr(browser_manager, "browser"):
browser_manager.browser.quit()
return True
else:
info("获取Cursor会话Token失败")
current_retry += 1
@@ -487,9 +519,19 @@ def main():
pass
info(f"达到最大重试次数 {max_retries},注册失败")
return False
except Exception as e:
info(f"主程序错误: {str(e)}")
info(f"错误详情: {traceback.format_exc()}")
cleanup_and_exit(browser_manager, 1)
return False
finally:
cleanup_and_exit(browser_manager, 1)
# 恢复原始的EMAIL_CODE_TYPE
EMAIL_CODE_TYPE = original_email_code_type
# 清理资源
if browser_manager:
try:
if hasattr(browser_manager, "browser"):
browser_manager.browser.quit()
except Exception as e:
error(f"关闭浏览器时发生错误: {str(e)}")

View File

@@ -7,6 +7,9 @@ def warn(message):
import time
import re
import requests
import os
import uuid
from datetime import datetime
from config import (
EMAIL_USERNAME,
EMAIL_DOMAIN,
@@ -17,13 +20,22 @@ from config import (
EMAIL_PROXY_ADDRESS,
EMAIL_PROXY_ENABLED,
EMAIL_API,
EMAIL_CODE_TYPE
EMAIL_CODE_TYPE,
EMAIL_DOMAINS
)
# 声明全局变量用于存储验证码请求
pending_verification_codes = {}
class EmailVerificationHandler:
def __init__(self, username=None, domain=None, pin=None, use_proxy=False):
def __init__(self, username=None, domain=None, pin=None, use_proxy=False, custom_email=None):
self.email = EMAIL_TYPE
self.custom_email = custom_email
# 如果提供了自定义邮箱,则解析它
if custom_email and '@' in custom_email:
username, domain = custom_email.split('@', 1)
self.username = username or EMAIL_USERNAME
self.domain = domain or EMAIL_DOMAIN
self.session = requests.Session()
@@ -51,7 +63,14 @@ class EmailVerificationHandler:
info(f"已启用代理: {EMAIL_PROXY_ADDRESS}")
def check(self):
mail_list_url = f"https://tempmail.plus/api/mails?email={self.username}%40{self.domain}&limit=20&epin={self.pin}"
# 如果有自定义邮箱,优先使用它
username = self.username
domain = self.domain
if self.custom_email and '@' in self.custom_email:
username, domain = self.custom_email.split('@', 1)
info(f"使用自定义邮箱进行连接检查: {username}@{domain}")
mail_list_url = f"https://tempmail.plus/api/mails?email={username}%40{domain}&limit=20&epin={self.pin}"
try:
# 增加超时时间并添加错误重试
for retry in range(3):
@@ -97,11 +116,22 @@ class EmailVerificationHandler:
Returns:
str: 验证码或None
"""
# 如果邮箱验证码获取方式为输入,则直接返回输入的验证码
# 记录当前的验证码获取模式和邮箱信息
info(f"验证码获取模式: {EMAIL_CODE_TYPE}, 使用邮箱: {source_email}")
# 首先检查是否是自定义邮箱(非系统配置的邮箱)
if source_email and '@' in source_email:
username, domain = source_email.split('@', 1)
if username != EMAIL_USERNAME or domain != EMAIL_DOMAIN:
info(f"检测到使用非系统配置邮箱: {source_email},强制使用手动输入模式")
return self.prompt_manual_code(source_email)
# 如果是INPUT模式始终直接进入手动输入
if EMAIL_CODE_TYPE == "INPUT":
info("EMAIL_CODE_TYPE设为INPUT跳过自动获取直接手动输入")
return self.prompt_manual_code()
return self.prompt_manual_code(source_email)
# 以下是自动获取验证码的逻辑只有在EMAIL_CODE_TYPE不是INPUT且不是自定义邮箱时才会执行
max_retries = max_retries or EMAIL_VERIFICATION_RETRIES
wait_time = wait_time or EMAIL_VERIFICATION_WAIT
info(f"开始获取邮箱验证码=>最大重试次数:{max_retries}, 等待时间:{wait_time}")
@@ -110,7 +140,7 @@ class EmailVerificationHandler:
if self.email not in ["tempemail", "zmail"]:
error(f"不支持的邮箱类型: {self.email},支持的类型为: tempemail, zmail")
warn("自动切换到手动输入模式")
return self.prompt_manual_code()
return self.prompt_manual_code(source_email)
for attempt in range(max_retries):
try:
@@ -142,20 +172,77 @@ class EmailVerificationHandler:
# 所有自动尝试都失败后,询问是否手动输入
response = input("自动获取验证码失败,是否手动输入? (y/n): ").lower()
if response == 'y':
return self.prompt_manual_code()
return self.prompt_manual_code(source_email)
return None
# 手动输入验证码
def prompt_manual_code(self):
"""手动输入验证码"""
info("自动获取验证码失败,开始手动输入验证码。")
code = input("输入6位数字验证码: ").strip()
return code
# 手动输入验证码 - 添加前端输入支持
def prompt_manual_code(self, source_email=None):
"""手动输入验证码,支持前端输入"""
email_display = source_email if source_email else f"{self.username}@{self.domain}"
info("=============手动输入验证码模式=============")
info(f"请查看邮箱 [{email_display}] 中的验证码")
# 检查是否有CURSOR_AUTO_REGISTER_WEB环境变量表示是否通过Web界面运行
web_mode = os.environ.get("CURSOR_AUTO_REGISTER_WEB", "").lower() == "true"
if web_mode:
info("检测到Web模式使用前端验证码输入")
return self.prompt_manual_code_web(email_display)
else:
info("命令行模式,使用控制台输入验证码")
info("通常验证码为6位数字在邮件正文中")
code = input("请输入收到的验证码: ").strip()
info(f"已输入验证码: {code}")
return code
# 前端验证码输入方法
def prompt_manual_code_web(self, source_email):
"""在Web界面请求验证码输入"""
# 生成唯一ID
email_id = str(uuid.uuid4())
# 存储到等待字典中
global pending_verification_codes
pending_verification_codes[email_id] = {
"email": source_email,
"status": "pending",
"created_at": datetime.now().isoformat(),
"code": None
}
info(f"已创建验证码请求 ID: {email_id},等待前端输入验证码")
# 循环等待验证码输入最多等待180秒
start_time = time.time()
while time.time() - start_time < 180:
# 检查是否已提交验证码
if email_id in pending_verification_codes and pending_verification_codes[email_id]["status"] == "submitted":
code = pending_verification_codes[email_id]["code"]
info(f"前端已提交验证码: {code}")
# 删除已使用的记录
pending_verification_codes.pop(email_id, None)
return code
# 等待1秒再检查
time.sleep(1)
# 超时,从等待字典中移除
pending_verification_codes.pop(email_id, None)
info("验证码输入超时")
return None
def get_tempmail_email_code(self, source_email=None):
info("开始获取邮件列表")
# 获取邮件列表
mail_list_url = f"https://tempmail.plus/api/mails?email={self.username}%40{self.domain}&limit=20&epin={self.pin}"
# 如果提供了source_email且当前不是使用custom_email则尝试解析它
if source_email and source_email != f"{self.username}@{self.domain}" and '@' in source_email:
username, domain = source_email.split('@', 1)
mail_list_url = f"https://tempmail.plus/api/mails?email={username}%40{domain}&limit=20&epin={self.pin}"
info(f"使用自定义邮箱获取验证码: {source_email}")
else:
mail_list_url = f"https://tempmail.plus/api/mails?email={self.username}%40{self.domain}&limit=20&epin={self.pin}"
info(f"使用配置邮箱获取验证码: {self.username}@{self.domain}")
try:
# 增加错误重试和超时时间
for retry in range(3):
@@ -188,8 +275,14 @@ class EmailVerificationHandler:
if not first_id:
return None, None
info(f"开始获取邮件详情: {first_id}")
# 获取具体邮件内容
mail_detail_url = f"https://tempmail.plus/api/mails/{first_id}?email={self.username}%40{self.domain}&epin={self.pin}"
# 使用相同的用户名和域名获取邮件详情
if source_email and source_email != f"{self.username}@{self.domain}" and '@' in source_email:
username, domain = source_email.split('@', 1)
mail_detail_url = f"https://tempmail.plus/api/mails/{first_id}?email={username}%40{domain}&epin={self.pin}"
else:
mail_detail_url = f"https://tempmail.plus/api/mails/{first_id}?email={self.username}%40{self.domain}&epin={self.pin}"
try:
mail_detail_response = self.session.get(
mail_detail_url, timeout=10
@@ -222,7 +315,7 @@ class EmailVerificationHandler:
if code_match:
# 清理邮件
self._cleanup_mail(first_id)
self._cleanup_mail(first_id, source_email)
return code_match.group(), first_id
return None, None
except requests.exceptions.Timeout:
@@ -235,11 +328,18 @@ class EmailVerificationHandler:
error(f"获取邮件列表发生错误: {str(e)}")
return None, None
def _cleanup_mail(self, first_id):
def _cleanup_mail(self, first_id, source_email=None):
# 如果提供了source_email优先使用它
username = self.username
domain = self.domain
if source_email and '@' in source_email:
username, domain = source_email.split('@', 1)
info(f"使用自定义邮箱清理邮件: {username}@{domain}")
# 构造删除请求的URL和数据
delete_url = "https://tempmail.plus/api/mails/"
payload = {
"email": f"{self.username}@{self.domain}",
"email": f"{username}@{domain}",
"first_id": first_id,
"epin": self.pin,
}
@@ -301,13 +401,24 @@ class EmailVerificationHandler:
def get_zmail_email_code(self, source_email=None):
info("开始获取邮件列表")
# 获取邮件列表
username = source_email.split("@")[0]
# 优先使用传入的source_email其次是自定义邮箱最后才是配置中的邮箱
email_to_use = source_email if source_email else (self.custom_email if self.custom_email else f"{self.username}@{self.domain}")
if '@' not in email_to_use:
error(f"邮箱格式错误: {email_to_use}")
return None, None
username = email_to_use.split("@")[0]
info(f"使用邮箱获取验证码: {email_to_use}, 用户名: {username}")
mail_list_url = f"{EMAIL_API}/api/mailboxes/{username}/emails"
proxy = {
if EMAIL_PROXY_ENABLED:
proxy = {
"http": f"{EMAIL_PROXY_ADDRESS}",
"https": f"{EMAIL_PROXY_ADDRESS}",
}
self.session.proxies.update(proxy)
self.session.proxies.update(proxy)
try:
mail_list_response = self.session.get(
mail_list_url, timeout=10000

View File

@@ -24,6 +24,9 @@
<!-- 加载中遮罩 -->
<div class="loading-overlay" id="loading-overlay">
<button type="button" class="close-overlay" aria-label="关闭">
<i class="fas fa-times fa-lg"></i>
</button>
<div class="spinner-container">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">加载中...</span>
@@ -170,6 +173,43 @@
</div>
</div>
<!-- 自定义邮箱注册卡片 - 移到下方 -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-header bg-white">
<h5 class="mb-0">自定义邮箱注册</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-8">
<div class="mb-3">
<label for="custom-email" class="form-label">输入邮箱地址</label>
<div class="input-group">
<input type="email" class="form-control" id="custom-email"
placeholder="例如: your.email@example.com">
<button class="btn btn-primary" type="button" id="custom-registration">
<i class="fas fa-user-plus me-1"></i> 使用此邮箱注册
</button>
</div>
<small class="text-muted">使用自定义邮箱注册时,需要手动获取验证码</small>
</div>
</div>
<div class="col-md-4">
<div class="alert alert-info" id="custom-registration-status"
style="display: none;">
<div class="d-flex align-items-center">
<i class="fas fa-info-circle me-2"></i>
<span id="custom-registration-message">准备就绪</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 在搜索栏旁边添加排序控件 -->
<div class="row mb-3 align-items-center">
<div class="col-md-6">
@@ -332,7 +372,8 @@
<small class="text-muted">True=无界面运行浏览器False=显示浏览器界面</small>
</div>
<div class="mb-3">
<label for="dynamic-useragent" class="form-label">动态User-Agent先不要配置</label>
<label for="dynamic-useragent"
class="form-label">动态User-Agent先不要配置</label>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch"
id="dynamic-useragent" disabled>
@@ -349,7 +390,8 @@
<div class="mb-3">
<label for="browser-path" class="form-label">浏览器路径 (可选)</label>
<input type="text" id="browser-path" class="form-control" disabled>
<small class="text-muted">Windows下浏览器可执行文件的完整路径(示例C:\Users\Administrator\AppData\Local\Google\Chrome\Bin\chrome.exe)</small>
<small
class="text-muted">Windows下浏览器可执行文件的完整路径(示例C:\Users\Administrator\AppData\Local\Google\Chrome\Bin\chrome.exe)</small>
</div>
<div class="mb-3">
<label for="accounts-limit" class="form-label">最大账号数量</label>
@@ -357,7 +399,7 @@
disabled>
<small class="text-muted">系统允许创建的最大账号数量</small>
</div>
<!-- 验证码获取方式 -->
<div class="mb-3">
<label for="captcha-method" class="form-label">验证码获取方式</label>
@@ -549,6 +591,7 @@
<p>确定要删除此账号吗?此操作不可恢复。</p>
<p class="text-danger fw-bold">邮箱: <span id="deleteEmailConfirm"></span></p>
<p class="text-muted">ID: <span id="deleteIdConfirm"></span></p>
<input type="hidden" id="deleteAccountId" value="">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
@@ -590,7 +633,8 @@
</div>
<!-- 账号使用记录模态框 -->
<div class="modal fade" id="usageRecordModal" tabindex="-1" aria-labelledby="usageRecordModalLabel" aria-hidden="true">
<div class="modal fade" id="usageRecordModal" tabindex="-1" aria-labelledby="usageRecordModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
@@ -638,6 +682,35 @@
</div>
</div>
<!-- 验证码输入模态框 -->
<div class="modal fade" id="codeInputModal" tabindex="-1" aria-labelledby="codeInputModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="codeInputModalLabel">输入验证码</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>请检查以下邮箱中收到的验证码:</p>
<p class="fw-bold text-primary" id="verificationEmailDisplay"></p>
<div class="alert alert-info">
<i class="fas fa-info-circle me-2"></i>
<span>通常验证码为6位数字在邮件正文中</span>
</div>
<div class="mb-3">
<label for="verificationCode" class="form-label">验证码</label>
<input type="text" class="form-control" id="verificationCode" placeholder="输入验证码" maxlength="6">
</div>
<input type="hidden" id="pendingEmailId" value="">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" id="submitCodeBtn">提交验证码</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
</div>
</div>
</div>
</div>
<!-- Bootstrap JS -->
<script src="static/js/bootstrap.bundle.min.js"></script>
<!-- jQuery -->

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff