Files
zsglpt-pc/ui/dependency_dialog.py
237899745 9743186a9e feat: 添加依赖自动检测与安装、选项记忆、KDocs登录优化
- 新增依赖检测模块:启动时自动检测wkhtmltoimage和Playwright Chromium
- 新增依赖安装对话框:缺失时提示用户一键下载安装
- 修复选项记忆功能:浏览类型、自动截图、自动上传选项现在会保存
- 优化KDocs登录检测:未登录时自动切换到金山文档页面并显示二维码
- 简化日志输出:移除debug信息,保留用户友好的状态提示
- 新增账号变化信号:账号管理页面的修改会自动同步到浏览任务页面

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 01:28:06 +08:00

202 lines
6.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
依赖安装对话框
检测到缺失依赖时显示,让用户选择是否下载安装
"""
from PyQt6.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton,
QProgressBar, QCheckBox, QGroupBox, QMessageBox
)
from PyQt6.QtCore import Qt, QThread, pyqtSignal
class DownloadThread(QThread):
"""下载线程"""
progress = pyqtSignal(int, int) # downloaded, total
log = pyqtSignal(str)
finished = pyqtSignal(bool, str) # success, message
def __init__(self, dep_name: str):
super().__init__()
self.dep_name = dep_name
def run(self):
from utils.dependency_installer import download_and_install_dependency
def on_progress(downloaded, total):
self.progress.emit(downloaded, total)
def on_log(msg):
self.log.emit(msg)
success, message = download_and_install_dependency(
self.dep_name,
progress_callback=on_progress,
log_callback=on_log
)
self.finished.emit(success, message)
class DependencyDialog(QDialog):
"""依赖安装对话框"""
def __init__(self, missing_deps: dict, parent=None):
super().__init__(parent)
self.missing_deps = missing_deps
self.download_threads = []
self.setWindowTitle("环境检测")
self.setMinimumWidth(450)
self.setModal(True)
self._setup_ui()
def _setup_ui(self):
layout = QVBoxLayout(self)
layout.setSpacing(16)
layout.setContentsMargins(20, 20, 20, 20)
# 标题
title = QLabel("⚠️ 检测到缺少必要的运行环境")
title.setStyleSheet("font-size: 16px; font-weight: bold; color: #fa8c16;")
layout.addWidget(title)
# 说明
desc = QLabel("以下组件缺失,部分功能可能无法正常使用:")
desc.setStyleSheet("color: #666;")
layout.addWidget(desc)
# 缺失组件列表
deps_group = QGroupBox("缺失组件")
deps_layout = QVBoxLayout(deps_group)
self.checkboxes = {}
if self.missing_deps.get("wkhtmltoimage"):
cb = QCheckBox("wkhtmltoimage截图功能需要")
cb.setChecked(True)
self.checkboxes["wkhtmltoimage"] = cb
deps_layout.addWidget(cb)
if self.missing_deps.get("chromium"):
cb = QCheckBox("Playwright Chromium金山文档上传需要")
cb.setChecked(True)
self.checkboxes["chromium"] = cb
deps_layout.addWidget(cb)
layout.addWidget(deps_group)
# 进度区域
self.progress_group = QGroupBox("安装进度")
progress_layout = QVBoxLayout(self.progress_group)
self.status_label = QLabel("等待开始...")
self.status_label.setStyleSheet("color: #666;")
progress_layout.addWidget(self.status_label)
self.progress_bar = QProgressBar()
self.progress_bar.setRange(0, 100)
self.progress_bar.setValue(0)
progress_layout.addWidget(self.progress_bar)
self.progress_group.setVisible(False)
layout.addWidget(self.progress_group)
# 按钮
btn_layout = QHBoxLayout()
btn_layout.addStretch()
self.skip_btn = QPushButton("跳过")
self.skip_btn.setMinimumWidth(80)
self.skip_btn.clicked.connect(self.reject)
btn_layout.addWidget(self.skip_btn)
self.install_btn = QPushButton("立即安装")
self.install_btn.setObjectName("primary")
self.install_btn.setMinimumWidth(100)
self.install_btn.clicked.connect(self._start_install)
btn_layout.addWidget(self.install_btn)
layout.addLayout(btn_layout)
def _start_install(self):
"""开始安装"""
# 获取选中的组件
selected = [name for name, cb in self.checkboxes.items() if cb.isChecked()]
if not selected:
QMessageBox.information(self, "提示", "请选择要安装的组件")
return
# 禁用按钮和复选框
self.install_btn.setEnabled(False)
self.skip_btn.setText("取消")
for cb in self.checkboxes.values():
cb.setEnabled(False)
# 显示进度
self.progress_group.setVisible(True)
# 开始安装
self._install_queue = selected.copy()
self._install_next()
def _install_next(self):
"""安装下一个组件"""
if not self._install_queue:
# 全部完成
self.status_label.setText("✅ 安装完成!")
self.status_label.setStyleSheet("color: #52c41a; font-weight: bold;")
self.skip_btn.setText("完成")
self.skip_btn.clicked.disconnect()
self.skip_btn.clicked.connect(self.accept)
return
dep_name = self._install_queue.pop(0)
display_name = "wkhtmltoimage" if dep_name == "wkhtmltoimage" else "Chromium 浏览器"
self.status_label.setText(f"正在下载 {display_name}...")
self.progress_bar.setValue(0)
# 启动下载线程
thread = DownloadThread(dep_name)
thread.progress.connect(self._on_progress)
thread.log.connect(self._on_log)
thread.finished.connect(self._on_finished)
thread.start()
self.download_threads.append(thread)
def _on_progress(self, downloaded: int, total: int):
"""下载进度更新"""
if total > 0:
percent = int(downloaded * 100 / total)
self.progress_bar.setValue(percent)
mb_downloaded = downloaded / 1024 / 1024
mb_total = total / 1024 / 1024
self.status_label.setText(f"下载中... {mb_downloaded:.1f}MB / {mb_total:.1f}MB")
def _on_log(self, msg: str):
"""日志更新"""
self.status_label.setText(msg)
def _on_finished(self, success: bool, message: str):
"""安装完成"""
if success:
if message:
# wkhtmltoimage 需要手动完成安装向导
QMessageBox.information(self, "提示", message)
# 继续安装下一个
self._install_next()
else:
self.status_label.setText(f"❌ 安装失败: {message}")
self.status_label.setStyleSheet("color: #ff4d4f;")
self.install_btn.setEnabled(True)
self.skip_btn.setText("跳过")
def closeEvent(self, event):
"""关闭时停止所有线程"""
for thread in self.download_threads:
if thread.isRunning():
thread.terminate()
thread.wait()
event.accept()