Files
zsglpt-pc/ui/main_window.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

257 lines
8.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 (
QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QPushButton, QStackedWidget, QFrame, QLabel, QSplitter
)
from PyQt6.QtCore import Qt, QTimer
from .styles import get_stylesheet, LIGHT_THEME, DARK_THEME
from .log_widget import LogWidget
from .account_widget import AccountWidget
from .browse_widget import BrowseWidget
from .screenshot_widget import ScreenshotWidget
from .kdocs_widget import KDocsWidget
from .settings_widget import SettingsWidget
class MainWindow(QMainWindow):
"""主窗口"""
def __init__(self):
super().__init__()
self.setWindowTitle("知识管理平台助手 - 精简版")
self.setMinimumSize(1000, 700)
self.resize(1200, 800)
self._current_theme = "light"
self._setup_ui()
self._apply_theme("light")
def _setup_ui(self):
"""设置UI布局"""
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QHBoxLayout(central_widget)
main_layout.setContentsMargins(0, 0, 0, 0)
main_layout.setSpacing(0)
# 侧边栏
sidebar = self._create_sidebar()
main_layout.addWidget(sidebar)
# 右侧区域(内容 + 日志)
right_widget = QWidget()
right_layout = QVBoxLayout(right_widget)
right_layout.setContentsMargins(0, 0, 0, 0)
right_layout.setSpacing(0)
# 使用分割器可以调整日志区域大小
splitter = QSplitter(Qt.Orientation.Vertical)
# 主内容区
self.content_stack = QStackedWidget()
self._create_pages()
splitter.addWidget(self.content_stack)
# 日志区域
self.log_widget = LogWidget()
splitter.addWidget(self.log_widget)
# 设置初始比例
splitter.setSizes([600, 150])
right_layout.addWidget(splitter)
main_layout.addWidget(right_widget, 1)
# 连接日志信号
self._connect_log_signals()
def _create_sidebar(self) -> QWidget:
"""创建侧边栏"""
sidebar = QFrame()
sidebar.setObjectName("sidebar")
sidebar.setFixedWidth(180)
layout = QVBoxLayout(sidebar)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# 标题
title = QLabel("📋 知识管理助手")
title.setObjectName("sidebar_title")
title.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(title)
# 分隔线
line = QFrame()
line.setFrameShape(QFrame.Shape.HLine)
line.setStyleSheet("background-color: rgba(255,255,255,0.1);")
layout.addWidget(line)
# 导航按钮
self._nav_buttons = []
nav_items = [
("📝 账号管理", 0),
("🔄 浏览任务", 1),
("📸 截图管理", 2),
("📤 金山文档", 3),
("⚙️ 系统设置", 4),
]
for text, index in nav_items:
btn = QPushButton(text)
btn.setCheckable(True)
btn.clicked.connect(lambda checked, idx=index: self._switch_page(idx))
layout.addWidget(btn)
self._nav_buttons.append(btn)
layout.addStretch()
# 版本信息
version_label = QLabel("v1.0.0")
version_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
version_label.setStyleSheet("color: rgba(255,255,255,0.5); font-size: 11px; padding: 8px;")
layout.addWidget(version_label)
# 默认选中第一个
self._nav_buttons[0].setChecked(True)
return sidebar
def _create_pages(self):
"""创建各个页面"""
# 账号管理
self.account_widget = AccountWidget()
self.content_stack.addWidget(self.account_widget)
# 浏览任务
self.browse_widget = BrowseWidget()
self.content_stack.addWidget(self.browse_widget)
# 截图管理
self.screenshot_widget = ScreenshotWidget()
self.content_stack.addWidget(self.screenshot_widget)
# 金山文档
self.kdocs_widget = KDocsWidget()
self.content_stack.addWidget(self.kdocs_widget)
# 系统设置
self.settings_widget = SettingsWidget()
self.settings_widget.theme_changed.connect(self._apply_theme)
self.content_stack.addWidget(self.settings_widget)
def _connect_log_signals(self):
"""连接各模块的日志信号到日志面板"""
self.account_widget.log_signal.connect(self.log_widget.append_log)
self.browse_widget.log_signal.connect(self.log_widget.append_log)
self.screenshot_widget.log_signal.connect(self.log_widget.append_log)
self.kdocs_widget.log_signal.connect(self.log_widget.append_log)
self.settings_widget.log_signal.connect(self.log_widget.append_log)
# 账号变化时自动刷新浏览任务页面的账号列表
self.account_widget.accounts_changed.connect(self.browse_widget._refresh_accounts)
def _switch_page(self, index: int):
"""切换页面"""
# 更新导航按钮状态
for i, btn in enumerate(self._nav_buttons):
btn.setChecked(i == index)
# 切换页面
self.content_stack.setCurrentIndex(index)
def _apply_theme(self, theme_name: str):
"""应用主题"""
self._current_theme = theme_name
theme = LIGHT_THEME if theme_name == "light" else DARK_THEME
self.setStyleSheet(get_stylesheet(theme))
def log(self, message: str):
"""记录日志"""
self.log_widget.append_log(message)
def init_kdocs_login_check(self):
"""启动时自动检测金山文档登录状态(后台无头模式)"""
from config import get_config
config = get_config()
# 如果金山文档未启用或未配置链接,直接显示就绪
if not config.kdocs.enabled or not config.kdocs.doc_url.strip():
self.log("✅ 环境准备就绪")
return
self.log("🔄 正在检测金山文档登录状态...")
self._kdocs_init_worker = None
# 延迟100ms执行让UI先显示出来
QTimer.singleShot(100, self._do_kdocs_login_check)
def _do_kdocs_login_check(self):
"""执行金山文档登录检测"""
from utils.worker import Worker
def check_kdocs_login(_signals=None, _should_stop=None):
from core.kdocs_uploader import get_kdocs_uploader
uploader = get_kdocs_uploader()
# 静默模式,不输出详细日志
uploader._log_callback = None
result = uploader.request_qr(force=False)
return result
def on_result(result):
if result and result.get("success"):
if result.get("logged_in"):
self.log("✅ 金山文档已登录")
self.log("✅ 环境准备就绪")
# 更新金山文档面板状态
self.kdocs_widget.status_label.setText("✅ 已登录")
from .constants import get_status_style
self.kdocs_widget.status_label.setStyleSheet(get_status_style(True))
else:
self.log("⚠️ 金山文档未登录,正在获取登录二维码...")
# 自动切换到金山文档页面并获取二维码
self._switch_page(3) # 索引3是金山文档页面
QTimer.singleShot(300, self.kdocs_widget._get_qr_code)
else:
error = result.get("error", "未知错误") if result else "检测失败"
self.log(f"⚠️ 金山文档检测失败: {error}")
self.log("✅ 环境准备就绪")
def on_error(error):
self.log(f"⚠️ 金山文档检测出错: {error}")
self.log("✅ 环境准备就绪")
self._kdocs_init_worker = Worker(check_kdocs_login)
self._kdocs_init_worker.signals.result.connect(on_result)
self._kdocs_init_worker.signals.error.connect(on_error)
self._kdocs_init_worker.start()
def closeEvent(self, event):
"""窗口关闭事件"""
# 保存配置
from config import get_config, save_config
config = get_config()
config.theme = self._current_theme
save_config(config)
# 清理金山文档上传器
try:
from core.kdocs_uploader import get_kdocs_uploader
uploader = get_kdocs_uploader()
uploader.close()
except Exception:
pass
event.accept()