# -*- coding: UTF-8 -*- ''' @Project :domainScanDemo @File :system_settings.py @IDE :PyCharm @Author :梦伴 @Date :2026/4/10 15:00 @explain : 系统设置页面 ''' from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QLineEdit, QGroupBox, QCheckBox from PySide6.QtCore import QTimer, QThreadPool, QRunnable, Slot from PySide6.QtCore import Qt, QThread, Signal from loguru import logger import os import json import redis from detect.juming import JM from detect.juziseo import Juziseo from detect.jucha import JC from app.config import config class RedisTask(QRunnable): """ Redis操作后台任务 """ def __init__(self, func, *args, **kwargs): """ 初始化Redis任务 :param func: 要执行的函数 :param args: 函数参数 :param kwargs: 函数关键字参数 """ super().__init__() self.func = func self.args = args self.kwargs = kwargs @Slot() def run(self): """ 执行Redis操作 """ try: self.func(*self.args, **self.kwargs) except Exception as e: logger.error(f"Redis操作失败: {e}") class LoginThread(QThread): """ 登录线程 """ finished = Signal(bool, str) def __init__(self, email, password, platform): """ 初始化登录线程 :param email: 账号 :param password: 密码 :param platform: 平台 (juming: 聚名, juziseo: 桔子SEO) """ super().__init__() self.email = email self.password = password self.platform = platform def run(self): """ 运行登录线程 """ try: if self.platform == "juming": # 初始化聚名客户端 jm = JM() # 加载 Cookie jm.load_cookies() logger.info("已加载聚名 Cookie") # 登录 logger.info(f"开始登录聚名网: {self.email}") login_result = jm.user_zh_p_login(self.email, self.password) if not login_result[0]: self.finished.emit(False, f"登录失败: {login_result[1]}") return logger.info("登录成功") # 保存cookies jm.save_cookies() logger.info("已保存聚名 Cookie") self.finished.emit(True, "登录成功") elif self.platform == "juziseo": # 初始化桔子SEO客户端 juziseo = Juziseo() # 加载 Cookie juziseo.load_cookies() logger.info("已加载桔子SEO Cookie") # 登录 logger.info(f"开始登录桔子SEO: {self.email}") login_result = juziseo.login(self.email, self.password) if not login_result[0]: self.finished.emit(False, f"登录失败: {login_result[1]}") return logger.info("登录成功") # 保存cookies juziseo.save_cookies() logger.info("已保存桔子SEO Cookie") self.finished.emit(True, "登录成功") elif self.platform == "jucha": # 初始化聚查客户端 jc = JC() # 加载聚名 Cookie jc.load_juming_cookies() logger.info("已加载聚名 Cookie") # 登录 logger.info("开始登录聚查网") login_result = jc.auth_login() if not login_result[0]: self.finished.emit(False, f"登录失败: {login_result[1]}") return logger.info("登录成功") # 保存cookies jc.save_cookies() logger.info("已保存聚查 Cookie") self.finished.emit(True, "登录成功") except Exception as e: logger.error(f"登录失败: {e}") self.finished.emit(False, f"登录失败: {str(e)}") class SystemSettingsWidget(QWidget): """ 系统设置页面 """ def __init__(self): """ 初始化系统设置页面 """ super().__init__() # 初始化Redis客户端 self.redis_client = None self.use_redis = False self.thread_pool = QThreadPool() self.thread_pool.setMaxThreadCount(5) # 最大线程数 self.init_redis() # 创建布局 layout = QVBoxLayout(self) # 创建登录区域容器 login_container = QGroupBox("登录设置") login_container.setStyleSheet(""" QGroupBox { font-size: 14px; font-weight: bold; color: #333; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 20px; padding: 15px; } """) login_layout = QVBoxLayout(login_container) # 聚名登录区域 juming_subgroup = QGroupBox("聚名网登录") juming_subgroup.setStyleSheet(""" QGroupBox { font-size: 13px; font-weight: bold; color: #333; border: 1px solid #eee; border-radius: 4px; margin-bottom: 15px; padding: 10px; } """) juming_layout = QVBoxLayout(juming_subgroup) # 聚名输入区域(两列布局) juming_input_layout = QHBoxLayout() juming_input_layout.setSpacing(20) # 邮箱输入 email_layout = QVBoxLayout() email_label = QLabel("邮箱:") email_label.setStyleSheet("font-size: 14px; color: #666; margin-bottom: 8px;") self.juming_email_input = QLineEdit() self.juming_email_input.setPlaceholderText("请输入聚名网账号") self.juming_email_input.setStyleSheet(""" QLineEdit { font-size: 14px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; min-width: 250px; min-height: 22px; } QLineEdit:focus { border-color: #4CAF50; outline: none; } """) email_layout.addWidget(email_label) email_layout.addWidget(self.juming_email_input) juming_input_layout.addLayout(email_layout) # 密码输入 password_layout = QVBoxLayout() password_label = QLabel("密码:") password_label.setStyleSheet("font-size: 14px; color: #666; margin-bottom: 8px;") self.juming_password_input = QLineEdit() self.juming_password_input.setPlaceholderText("请输入聚名网密码") self.juming_password_input.setEchoMode(QLineEdit.Password) self.juming_password_input.setStyleSheet(""" QLineEdit { font-size: 14px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; min-width: 250px; min-height: 22px; } QLineEdit:focus { border-color: #4CAF50; outline: none; } """) password_layout.addWidget(password_label) password_layout.addWidget(self.juming_password_input) juming_input_layout.addLayout(password_layout) juming_layout.addLayout(juming_input_layout) # 登录说明 juming_note = QLabel("聚名聚查联名登录:登录聚名后会自动登录聚查") juming_note.setStyleSheet("font-size: 12px; color: #666; margin-top: 12px; margin-bottom: 12px;") juming_layout.addWidget(juming_note) # 登录按钮布局 juming_btn_layout = QHBoxLayout() juming_btn_layout.addStretch() # 添加弹性空间,将按钮推到右侧 juming_login_btn = QPushButton("登录聚名网") juming_login_btn.clicked.connect(self.login_juming) juming_login_btn.setStyleSheet(""" QPushButton { font-size: 14px; padding: 8px 16px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; } QPushButton:hover { background-color: #45a049; } QPushButton:disabled { background-color: #cccccc; } """) juming_btn_layout.addWidget(juming_login_btn) juming_layout.addLayout(juming_btn_layout) login_layout.addWidget(juming_subgroup) # 桔子SEO登录区域 juziseo_subgroup = QGroupBox("桔子SEO登录") juziseo_subgroup.setStyleSheet(""" QGroupBox { font-size: 13px; font-weight: bold; color: #333; border: 1px solid #eee; border-radius: 4px; margin-bottom: 15px; padding: 10px; } """) juziseo_layout = QVBoxLayout(juziseo_subgroup) # 桔子SEO输入区域(两列布局) juziseo_input_layout = QHBoxLayout() juziseo_input_layout.setSpacing(20) # 账号输入 juziseo_email_layout = QVBoxLayout() juziseo_email_label = QLabel("账号:") juziseo_email_label.setStyleSheet("font-size: 14px; color: #666; margin-bottom: 8px;") self.juziseo_email_input = QLineEdit() self.juziseo_email_input.setPlaceholderText("请输入桔子SEO账号") self.juziseo_email_input.setStyleSheet(""" QLineEdit { font-size: 14px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; min-width: 250px; min-height: 22px; } QLineEdit:focus { border-color: #2196F3; outline: none; } """) juziseo_email_layout.addWidget(juziseo_email_label) juziseo_email_layout.addWidget(self.juziseo_email_input) juziseo_input_layout.addLayout(juziseo_email_layout) # 密码输入 juziseo_password_layout = QVBoxLayout() juziseo_password_label = QLabel("密码:") juziseo_password_label.setStyleSheet("font-size: 14px; color: #666; margin-bottom: 8px;") self.juziseo_password_input = QLineEdit() self.juziseo_password_input.setPlaceholderText("请输入桔子SEO密码") self.juziseo_password_input.setEchoMode(QLineEdit.Password) self.juziseo_password_input.setStyleSheet(""" QLineEdit { font-size: 14px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; min-width: 250px; min-height: 22px; } QLineEdit:focus { border-color: #2196F3; outline: none; } """) juziseo_password_layout.addWidget(juziseo_password_label) juziseo_password_layout.addWidget(self.juziseo_password_input) juziseo_input_layout.addLayout(juziseo_password_layout) juziseo_layout.addLayout(juziseo_input_layout) # 登录按钮布局 juziseo_btn_layout = QHBoxLayout() juziseo_btn_layout.addStretch() # 添加弹性空间,将按钮推到右侧 juziseo_login_btn = QPushButton("登录桔子SEO") juziseo_login_btn.clicked.connect(self.login_juziseo) juziseo_login_btn.setStyleSheet(""" QPushButton { font-size: 14px; padding: 8px 16px; background-color: #2196F3; color: white; border: none; border-radius: 4px; } QPushButton:hover { background-color: #0b7dda; } QPushButton:disabled { background-color: #cccccc; } """) juziseo_btn_layout.addWidget(juziseo_login_btn) juziseo_layout.addLayout(juziseo_btn_layout) login_layout.addWidget(juziseo_subgroup) layout.addWidget(login_container) # 创建代理IP配置区域 proxy_group = QGroupBox("代理IP配置") proxy_group.setStyleSheet(""" QGroupBox { font-size: 14px; font-weight: bold; color: #333; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 20px; padding: 15px; } """) proxy_layout = QVBoxLayout(proxy_group) # 启用代理IP复选框 proxy_enable_layout = QHBoxLayout() proxy_enable_label = QLabel("启用代理IP:") proxy_enable_label.setStyleSheet("font-size: 14px; color: #333; min-width: 100px; font-weight: bold;") self.proxy_enable_checkbox = QCheckBox() self.proxy_enable_checkbox.setStyleSheet(""" QCheckBox { font-size: 14px; spacing: 8px; } QCheckBox::indicator { width: 20px; height: 20px; } QCheckBox::indicator:unchecked { border: 2px solid #999; background-color: white; border-radius: 4px; } QCheckBox::indicator:checked { border: 2px solid #9c27b0; background-color: #9c27b0; border-radius: 4px; } QCheckBox::indicator:checked::after { content: '✓'; color: white; font-size: 14px; font-weight: bold; position: absolute; top: 0px; left: 3px; } """) self.proxy_enable_checkbox.stateChanged.connect(self.save_proxy_config) proxy_enable_layout.addWidget(proxy_enable_label) proxy_enable_layout.addWidget(self.proxy_enable_checkbox) proxy_enable_layout.setContentsMargins(0, 0, 0, 10) proxy_layout.addLayout(proxy_enable_layout) # 代理IP链接输入 proxy_url_layout = QHBoxLayout() proxy_url_label = QLabel("代理IP链接:") proxy_url_label.setStyleSheet("font-size: 14px; color: #666; min-width: 100px;") self.proxy_url_input = QLineEdit() self.proxy_url_input.setPlaceholderText("请输入获取代理IP的链接") self.proxy_url_input.setStyleSheet(""" QLineEdit { font-size: 14px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; } QLineEdit:focus { border-color: #9c27b0; outline: none; } """) # 输入时自动保存 self.proxy_url_input.textChanged.connect(self.save_proxy_config) proxy_url_layout.addWidget(proxy_url_label) proxy_url_layout.addWidget(self.proxy_url_input) proxy_url_layout.setContentsMargins(0, 0, 0, 15) proxy_layout.addLayout(proxy_url_layout) layout.addWidget(proxy_group) # 创建域名后缀配置区域 domain_suffix_group = QGroupBox("域名后缀配置") domain_suffix_group.setStyleSheet(""" QGroupBox { font-size: 14px; font-weight: bold; color: #333; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 20px; padding: 15px; } """) domain_suffix_layout = QVBoxLayout(domain_suffix_group) # 域名后缀输入 suffix_layout = QHBoxLayout() suffix_label = QLabel("保留后缀:") suffix_label.setStyleSheet("font-size: 14px; color: #666; min-width: 80px;") self.suffix_input = QLineEdit() self.suffix_input.setPlaceholderText("请输入需要保留的域名后缀,多个用逗号分隔,如:.com,.net") self.suffix_input.setStyleSheet(""" QLineEdit { font-size: 14px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; } QLineEdit:focus { border-color: #ff9800; outline: none; } """) # 输入时自动保存 self.suffix_input.textChanged.connect(self.save_suffixes) suffix_layout.addWidget(suffix_label) suffix_layout.addWidget(self.suffix_input) suffix_layout.setContentsMargins(0, 0, 0, 5) domain_suffix_layout.addLayout(suffix_layout) # 添加分隔符提示 suffix_note = QLabel("提示:多个域名后缀请用英文逗号分割") suffix_note.setStyleSheet("font-size: 12px; color: #999; margin-bottom: 10px;") domain_suffix_layout.addWidget(suffix_note) layout.addWidget(domain_suffix_group) # 创建检测选项配置区域 detect_group = QGroupBox("检测选项配置") detect_group.setStyleSheet(""" QGroupBox { font-size: 14px; font-weight: bold; color: #333; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 20px; padding: 15px; } """) detect_layout = QVBoxLayout(detect_group) # 检测选项列表 self.detect_checkboxes = {} detect_options = [ ("detect_register", "1. 检测注册"), ("detect_chinaz", "2. 站长之家查询"), ("detect_aizhan", "3. 爱站网查询"), ("detect_baidu_site", "4. 百度site查询"), ("detect_360_site", "5. 360的site查询"), ("detect_baidu_security", "6. 百度网址安全中心查询"), ("detect_whois", "7. 聚查中的WHOIS 查询"), ("detect_beian", "8. 聚查中的备案相关查询"), ("detect_intercept", "9. 聚查中的拦截检测相关查询"), ("detect_juziseo", "10. 桔子历史"), ("detect_juziseo_outlink", "11. 桔子外链") ] # 创建横向布局容器 detect_checkbox_container = QHBoxLayout() detect_checkbox_container.setSpacing(20) detect_checkbox_container.setContentsMargins(0, 0, 0, 0) # 创建两列布局 left_column = QVBoxLayout() right_column = QVBoxLayout() # 将检测选项分为两列 for i, (key, label_text) in enumerate(detect_options): checkbox = QCheckBox(label_text) checkbox.setStyleSheet("font-size: 14px;") checkbox.stateChanged.connect(self.save_detect_options) self.detect_checkboxes[key] = checkbox # 前5个选项放在左列,后5个放在右列 if i < 5: left_column.addWidget(checkbox) else: right_column.addWidget(checkbox) # 添加列到容器 detect_checkbox_container.addLayout(left_column) detect_checkbox_container.addLayout(right_column) # 添加容器到检测布局 detect_layout.addLayout(detect_checkbox_container) # 创建检测配置容器 detect_config_container = QHBoxLayout() detect_config_container.setSpacing(20) detect_config_container.setContentsMargins(0, 0, 0, 20) # 添加检测选项配置 detect_config_container.addWidget(detect_group, 2) # 占2份空间 # 创建检测线程配置区域 thread_group = QGroupBox("检测线程配置") thread_group.setStyleSheet(""" QGroupBox { font-size: 14px; font-weight: bold; color: #333; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 20px; padding: 15px; } """) thread_layout = QVBoxLayout(thread_group) # 检测线程数输入 thread_count_layout = QHBoxLayout() thread_count_label = QLabel("线程数量:") thread_count_label.setStyleSheet("font-size: 14px; color: #666; min-width: 80px;") self.thread_count_input = QLineEdit() self.thread_count_input.setPlaceholderText("请输入检测线程数量,默认为100") self.thread_count_input.setStyleSheet(""" QLineEdit { font-size: 14px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; } QLineEdit:focus { border-color: #2196F3; outline: none; } """) # 输入时自动保存 self.thread_count_input.textChanged.connect(self.save_thread_count) thread_count_layout.addWidget(thread_count_label) thread_count_layout.addWidget(self.thread_count_input) thread_count_layout.setContentsMargins(0, 0, 0, 5) thread_layout.addLayout(thread_count_layout) # 添加线程数提示 thread_note = QLabel("提示:线程数量不宜设置过大,建议根据服务器性能调整") thread_note.setStyleSheet("font-size: 12px; color: #999; margin-bottom: 10px;") thread_layout.addWidget(thread_note) # 添加检测线程配置到容器 detect_config_container.addWidget(thread_group, 1) # 占1份空间 # 将容器添加到主布局 layout.addLayout(detect_config_container) # 创建状态标签 self.status_label = QLabel("") self.status_label.setAlignment(Qt.AlignCenter) self.status_label.setStyleSheet("font-size: 14px; color: #333; margin-top: 10px; padding: 10px; background-color: #f0f8ff; border-radius: 4px;") layout.addWidget(self.status_label) # 加载保存的账号密码 self.load_credentials() # 加载域名后缀 self.load_suffixes() # 加载检测线程数 self.load_thread_count() # 加载cookie self.load_cookies() # 加载检测选项 self.load_detect_options() # 加载代理IP配置 self.load_proxy_config() logger.info("系统设置页面创建完成") def init_redis(self): """ 初始化Redis客户端连接 """ try: # 使用连接池 pool = redis.ConnectionPool( host=config.REDIS_HOST, port=config.REDIS_PORT, password=config.REDIS_PASSWORD, db=config.REDIS_DB, decode_responses=True, socket_connect_timeout=3, # 减少连接超时时间 socket_timeout=3, # 减少操作超时时间 max_connections=10 # 连接池大小 ) self.redis_client = redis.Redis(connection_pool=pool) # 测试连接 self.redis_client.ping() logger.info(f"Redis 连接成功: {config.REDIS_HOST}:{config.REDIS_PORT}") self.use_redis = True except Exception as e: logger.warning(f"Redis 连接失败: {e},将只保存到本地文件") self.redis_client = None self.use_redis = False def check_redis_connection(self): """ 检查Redis连接状态,如果连接已断开则重新连接 """ if not self.use_redis or self.redis_client is None: return False try: # 测试连接 self.redis_client.ping() return True except Exception as e: logger.warning(f"Redis 连接已断开,尝试重新连接: {e}") # 重新连接 self.init_redis() return self.use_redis def save_credentials(self): """ 保存账号密码到本地文件和Redis """ credentials = { "juming": { "email": self.juming_email_input.text().strip(), "password": self.juming_password_input.text().strip() }, "juziseo": { "email": self.juziseo_email_input.text().strip(), "password": self.juziseo_password_input.text().strip() } } try: # 保存到本地文件(UI线程执行) with open('credentials.json', 'w', encoding='utf-8') as f: json.dump(credentials, f, indent=2, ensure_ascii=False) logger.info("账号密码保存成功") # 保存到Redis(后台线程执行) def save_to_redis(): if self.check_redis_connection(): self.redis_client.set('domain_tool:credentials', json.dumps(credentials)) logger.info("账号密码已同步到Redis") # 发布配置更新消息 self.redis_client.publish('domain_tool:config_update', 'credentials') # 提交到线程池执行 task = RedisTask(save_to_redis) self.thread_pool.start(task) except Exception as e: logger.error(f"保存账号密码失败: {e}") def save_suffixes(self): """ 保存域名后缀到本地文件和Redis """ suffixes = self.suffix_input.text().strip() try: # 保存到本地文件(UI线程执行) with open('domain_suffixes.json', 'w', encoding='utf-8') as f: json.dump({"suffixes": suffixes}, f, indent=2, ensure_ascii=False) logger.info("域名后缀保存成功") # 保存到Redis(后台线程执行) def save_to_redis(): if self.check_redis_connection(): self.redis_client.set('domain_tool:domain_suffixes', suffixes) logger.info("域名后缀已同步到Redis") # 发布配置更新消息 self.redis_client.publish('domain_tool:config_update', 'domain_suffixes') # 提交到线程池执行 task = RedisTask(save_to_redis) self.thread_pool.start(task) except Exception as e: logger.error(f"保存域名后缀失败: {e}") def load_suffixes(self): """ 从本地文件加载域名后缀 """ try: if os.path.exists('domain_suffixes.json'): with open('domain_suffixes.json', 'r', encoding='utf-8') as f: data = json.load(f) suffixes = data.get('suffixes', '.com,.net') self.suffix_input.setText(suffixes) logger.info("域名后缀加载成功") else: # 默认值 self.suffix_input.setText('.com,.net') self.save_suffixes() logger.info("使用默认域名后缀") except Exception as e: logger.error(f"加载域名后缀失败: {e}") # 使用默认值 self.suffix_input.setText('.com,.net') def load_credentials(self): """ 从本地文件加载账号密码 """ try: if os.path.exists('credentials.json'): with open('credentials.json', 'r', encoding='utf-8') as f: credentials = json.load(f) # 加载聚名账号密码 if 'juming' in credentials: self.juming_email_input.setText(credentials['juming'].get('email', '')) self.juming_password_input.setText(credentials['juming'].get('password', '')) # 加载桔子SEO账号密码 if 'juziseo' in credentials: self.juziseo_email_input.setText(credentials['juziseo'].get('email', '')) self.juziseo_password_input.setText(credentials['juziseo'].get('password', '')) logger.info("账号密码加载成功") except Exception as e: logger.error(f"加载账号密码失败: {e}") def load_cookies(self): """ 加载cookie """ try: # 加载聚名cookie jm = JM() jm.load_cookies() logger.info("聚名cookie加载成功") # 加载桔子SEO cookie juziseo = Juziseo() juziseo.load_cookies() logger.info("桔子SEO cookie加载成功") # 加载聚查cookie jc = JC() jc.load_cookies() logger.info("聚查cookie加载成功") except Exception as e: logger.error(f"加载cookie失败: {e}") def login_juming(self): """ 登录聚名网 """ email = self.juming_email_input.text().strip() password = self.juming_password_input.text().strip() if not email or not password: self.status_label.setText("请输入账号和密码") return self.status_label.setText("正在登录聚名网...") # 创建并启动登录线程 self.login_thread = LoginThread(email, password, "juming") self.login_thread.finished.connect(self.login_finished) self.login_thread.start() logger.info(f"开始登录聚名网: {email}") def login_juziseo(self): """ 登录桔子SEO """ email = self.juziseo_email_input.text().strip() password = self.juziseo_password_input.text().strip() if not email or not password: self.status_label.setText("请输入账号和密码") return self.status_label.setText("正在登录桔子SEO...") # 创建并启动登录线程 self.login_thread = LoginThread(email, password, "juziseo") self.login_thread.finished.connect(self.login_finished) self.login_thread.start() logger.info(f"开始登录桔子SEO: {email}") def login_jucha(self): """ 登录聚查网 """ # 检查聚名Cookie是否存在 if not os.path.exists('juming_cookies.pkl'): self.status_label.setText("请先登录聚名网") return self.status_label.setText("正在登录聚查网...") # 创建并启动登录线程 self.login_thread = LoginThread("", "", "jucha") self.login_thread.finished.connect(self.login_finished) self.login_thread.start() logger.info("开始登录聚查网") def save_detect_options(self): """ 保存检测选项到本地文件和Redis """ detect_options = {} for key, checkbox in self.detect_checkboxes.items(): detect_options[key] = checkbox.isChecked() try: # 保存到本地文件(UI线程执行) with open('detect_options.json', 'w', encoding='utf-8') as f: json.dump(detect_options, f, indent=2, ensure_ascii=False) logger.info("检测选项保存成功") # 保存到Redis(后台线程执行) def save_to_redis(): if self.check_redis_connection(): self.redis_client.set('domain_tool:detect_options', json.dumps(detect_options)) logger.info("检测选项已同步到Redis") # 发布配置更新消息 self.redis_client.publish('domain_tool:config_update', 'detect_options') # 提交到线程池执行 task = RedisTask(save_to_redis) self.thread_pool.start(task) except Exception as e: logger.error(f"保存检测选项失败: {e}") def load_detect_options(self): """ 从本地文件加载检测选项 """ try: if os.path.exists('detect_options.json'): with open('detect_options.json', 'r', encoding='utf-8') as f: detect_options = json.load(f) for key, checked in detect_options.items(): if key in self.detect_checkboxes: self.detect_checkboxes[key].setChecked(checked) logger.info("检测选项加载成功") else: # 默认值:全部勾选 for checkbox in self.detect_checkboxes.values(): checkbox.setChecked(True) self.save_detect_options() logger.info("使用默认检测选项") except Exception as e: logger.error(f"加载检测选项失败: {e}") # 使用默认值 for checkbox in self.detect_checkboxes.values(): checkbox.setChecked(True) def save_proxy_config(self): """ 保存代理IP配置到本地文件和Redis """ proxy_enable = self.proxy_enable_checkbox.isChecked() proxy_url = self.proxy_url_input.text().strip() try: # 保存到本地文件(UI线程执行) with open('proxy_config.json', 'w', encoding='utf-8') as f: json.dump({"proxy_enable": proxy_enable, "proxy_url": proxy_url}, f, indent=2, ensure_ascii=False) logger.info("代理IP配置保存成功") # 保存到Redis(后台线程执行) def save_to_redis(): if self.check_redis_connection(): self.redis_client.set('domain_tool:proxy_config', json.dumps({"proxy_enable": proxy_enable, "proxy_url": proxy_url})) logger.info("代理IP配置已同步到Redis") # 发布配置更新消息 self.redis_client.publish('domain_tool:config_update', 'proxy_config') # 提交到线程池执行 task = RedisTask(save_to_redis) self.thread_pool.start(task) except Exception as e: logger.error(f"保存代理IP配置失败: {e}") def load_proxy_config(self): """ 从本地文件加载代理IP配置 """ try: if os.path.exists('proxy_config.json'): with open('proxy_config.json', 'r', encoding='utf-8') as f: proxy_config = json.load(f) proxy_enable = proxy_config.get('proxy_enable', False) proxy_url = proxy_config.get('proxy_url', '') self.proxy_enable_checkbox.setChecked(proxy_enable) self.proxy_url_input.setText(proxy_url) logger.info("代理IP配置加载成功") else: # 默认值:未启用,空链接 self.proxy_enable_checkbox.setChecked(False) self.proxy_url_input.setText('') self.save_proxy_config() logger.info("使用默认代理IP配置") except Exception as e: logger.error(f"加载代理IP配置失败: {e}") # 使用默认值 self.proxy_enable_checkbox.setChecked(False) self.proxy_url_input.setText('') def toggle_password_visibility(self, password_input): """ 切换密码输入框的可见性 :param password_input: 密码输入框 """ if password_input.echoMode() == QLineEdit.Password: password_input.setEchoMode(QLineEdit.Normal) # 找到对应的按钮并修改图标 if password_input == self.juming_password_input: self.juming_password_visibility_btn.setText("🙈") elif password_input == self.juziseo_password_input: self.juziseo_password_visibility_btn.setText("🙈") else: password_input.setEchoMode(QLineEdit.Password) # 找到对应的按钮并修改图标 if password_input == self.juming_password_input: self.juming_password_visibility_btn.setText("👁") elif password_input == self.juziseo_password_input: self.juziseo_password_visibility_btn.setText("👁") def login_finished(self, success, message): """ 登录完成 :param success: 是否成功 :param message: 消息 """ self.status_label.setText(message) # 登录成功后保存账号密码 if success: self.save_credentials() # 聚名登录成功后自动登录聚查 if self.login_thread.platform == "juming": self.status_label.setText("聚名登录成功,正在自动登录聚查...") # 延迟一秒后登录聚查,确保聚名cookie已保存 QTimer.singleShot(1000, self.login_jucha) logger.info(f"登录完成: {message}") def save_thread_count(self): """ 保存检测线程数到本地文件和Redis """ thread_count = self.thread_count_input.text().strip() try: # 保存到本地文件(UI线程执行) with open('thread_count.json', 'w', encoding='utf-8') as f: json.dump({"thread_count": thread_count}, f, indent=2, ensure_ascii=False) logger.info("检测线程数配置保存成功") # 保存到Redis(后台线程执行) def save_to_redis(): if self.check_redis_connection(): self.redis_client.set('domain_tool:thread_count', thread_count) logger.info("检测线程数配置已同步到Redis") # 发布配置更新消息 self.redis_client.publish('domain_tool:config_update', 'thread_count') # 提交到线程池执行 task = RedisTask(save_to_redis) self.thread_pool.start(task) except Exception as e: logger.error(f"保存检测线程数配置失败: {e}") def load_thread_count(self): """ 从本地文件加载检测线程数 """ try: if os.path.exists('thread_count.json'): with open('thread_count.json', 'r', encoding='utf-8') as f: thread_config = json.load(f) thread_count = thread_config.get('thread_count', '100') self.thread_count_input.setText(thread_count) logger.info("检测线程数配置加载成功") else: # 默认值:100 self.thread_count_input.setText('100') self.save_thread_count() logger.info("使用默认检测线程数配置") except Exception as e: logger.error(f"加载检测线程数配置失败: {e}") # 使用默认值 self.thread_count_input.setText('100')