feat: 知识管理平台精简版 - PyQt6桌面应用
主要功能: - 账号管理:添加/编辑/删除账号,测试登录 - 浏览任务:批量浏览应读/选读内容并标记已读 - 截图管理:wkhtmltoimage截图,查看历史 - 金山文档:扫码登录/微信快捷登录,自动上传截图 技术栈: - PyQt6 GUI框架 - Playwright 浏览器自动化 - SQLite 本地数据存储 - wkhtmltoimage 网页截图 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
120
ui/log_widget.py
Normal file
120
ui/log_widget.py
Normal file
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Log display panel - collapsible log output area
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from PyQt6.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QHBoxLayout, QPlainTextEdit,
|
||||
QPushButton, QFrame, QLabel
|
||||
)
|
||||
from PyQt6.QtCore import Qt, pyqtSlot
|
||||
from PyQt6.QtGui import QTextCursor
|
||||
|
||||
from .constants import LOG_MIN_HEIGHT, BUTTON_HEIGHT_SMALL, BUTTON_SPACING
|
||||
|
||||
|
||||
class LogWidget(QWidget):
|
||||
"""Log display panel"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setObjectName("log_widget")
|
||||
self._collapsed = False
|
||||
self._max_lines = 500
|
||||
self._setup_ui()
|
||||
|
||||
def _setup_ui(self):
|
||||
"""Setup UI"""
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setSpacing(0)
|
||||
|
||||
# Header bar
|
||||
header = QFrame()
|
||||
header.setFixedHeight(36)
|
||||
header.setStyleSheet("background-color: rgba(0,0,0,0.03); border-bottom: 1px solid rgba(0,0,0,0.08);")
|
||||
header_layout = QHBoxLayout(header)
|
||||
header_layout.setContentsMargins(16, 0, 16, 0)
|
||||
header_layout.setSpacing(BUTTON_SPACING)
|
||||
|
||||
# Title
|
||||
title = QLabel("📜 日志输出")
|
||||
title.setStyleSheet("font-weight: bold; font-size: 13px;")
|
||||
header_layout.addWidget(title)
|
||||
|
||||
header_layout.addStretch()
|
||||
|
||||
# Clear button
|
||||
self._clear_btn = QPushButton("清空")
|
||||
self._clear_btn.setFixedWidth(60)
|
||||
self._clear_btn.setFixedHeight(BUTTON_HEIGHT_SMALL)
|
||||
self._clear_btn.clicked.connect(self.clear)
|
||||
header_layout.addWidget(self._clear_btn)
|
||||
|
||||
# Toggle button
|
||||
self._toggle_btn = QPushButton("▼")
|
||||
self._toggle_btn.setFixedWidth(36)
|
||||
self._toggle_btn.setFixedHeight(BUTTON_HEIGHT_SMALL)
|
||||
self._toggle_btn.clicked.connect(self._toggle_collapse)
|
||||
header_layout.addWidget(self._toggle_btn)
|
||||
|
||||
layout.addWidget(header)
|
||||
|
||||
# Log text area
|
||||
self._text_edit = QPlainTextEdit()
|
||||
self._text_edit.setReadOnly(True)
|
||||
self._text_edit.setMinimumHeight(LOG_MIN_HEIGHT)
|
||||
self._text_edit.setMaximumHeight(250)
|
||||
self._text_edit.setStyleSheet("""
|
||||
QPlainTextEdit {
|
||||
font-family: "Consolas", "Monaco", "Courier New", monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
""")
|
||||
layout.addWidget(self._text_edit)
|
||||
|
||||
def _toggle_collapse(self):
|
||||
"""Toggle collapse state"""
|
||||
self._collapsed = not self._collapsed
|
||||
self._text_edit.setVisible(not self._collapsed)
|
||||
self._toggle_btn.setText("▲" if self._collapsed else "▼")
|
||||
|
||||
@pyqtSlot(str)
|
||||
def append_log(self, message: str):
|
||||
"""Append log message"""
|
||||
timestamp = datetime.now().strftime("%H:%M:%S")
|
||||
formatted = f"[{timestamp}] {message}"
|
||||
|
||||
self._text_edit.appendPlainText(formatted)
|
||||
|
||||
# Limit lines
|
||||
doc = self._text_edit.document()
|
||||
if doc.blockCount() > self._max_lines:
|
||||
cursor = QTextCursor(doc)
|
||||
cursor.movePosition(QTextCursor.MoveOperation.Start)
|
||||
cursor.select(QTextCursor.SelectionType.BlockUnderCursor)
|
||||
cursor.movePosition(
|
||||
QTextCursor.MoveOperation.Down,
|
||||
QTextCursor.MoveMode.KeepAnchor,
|
||||
doc.blockCount() - self._max_lines
|
||||
)
|
||||
cursor.removeSelectedText()
|
||||
|
||||
# Scroll to bottom
|
||||
self._text_edit.moveCursor(QTextCursor.MoveOperation.End)
|
||||
|
||||
def log(self, message: str):
|
||||
"""Log alias"""
|
||||
self.append_log(message)
|
||||
|
||||
def clear(self):
|
||||
"""Clear log"""
|
||||
self._text_edit.clear()
|
||||
|
||||
def get_text(self) -> str:
|
||||
"""Get all log text"""
|
||||
return self._text_edit.toPlainText()
|
||||
Reference in New Issue
Block a user