From ed947743fcf8ebf1a3a72312e08be1602d0a3363 Mon Sep 17 00:00:00 2001 From: gitea Date: Mon, 29 Sep 2025 11:26:29 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=BA=9B=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- toolbox/codes/common/clibs.py | 2 +- toolbox/codes/common/db_operation.py | 14 +++--- toolbox/codes/common/exception_handler.py | 19 +++++--- toolbox/codes/common/ui2py.py | 28 ------------ toolbox/codes/ui/main_ui.py | 25 +++++++---- toolbox/codes/ui/overlay_page/overlay_ui.py | 48 ++++++++++++++------- toolbox/codes/ui/stacked_pages/w08_log.py | 46 +++++++++++++++++--- toolbox/readme.md | 17 +++++++- 8 files changed, 130 insertions(+), 69 deletions(-) delete mode 100644 toolbox/codes/common/ui2py.py diff --git a/toolbox/codes/common/clibs.py b/toolbox/codes/common/clibs.py index 5e8f1ed..a6cd3f9 100644 --- a/toolbox/codes/common/clibs.py +++ b/toolbox/codes/common/clibs.py @@ -16,7 +16,7 @@ win_width, win_height = 1100, 500 conn, cursor = None, None listW_items = {"实用工具": "w10_practical", "效率提升": "w20_efficiency", "财务分析": "w30_financial"} icon = f"{base_path}/assets/media/icon.ico" - +caller_frame = None def delete_files_in_directory(directory): path = Path(directory) if path.exists() and path.is_dir(): diff --git a/toolbox/codes/common/db_operation.py b/toolbox/codes/common/db_operation.py index c067952..12d5b27 100644 --- a/toolbox/codes/common/db_operation.py +++ b/toolbox/codes/common/db_operation.py @@ -1,7 +1,7 @@ import sqlite3 import time from inspect import currentframe -from functools import singledispatch +from functools import singledispatch, wraps from codes.common import clibs @@ -45,7 +45,9 @@ def db_init(): conn.close() def db_lock(func): + @wraps(func) def wrapper(*args, **kwargs): + clibs.caller_frame = currentframe().f_back try: clibs.lock.acquire(True) ret = func(*args, **kwargs) @@ -93,11 +95,11 @@ def db_close(): @db_lock def db_write_logs(content, module="", level="info"): - if module == "": - frame = currentframe().f_back - module_name = frame.f_globals["__name__"] - line_no = frame.f_lineno - module = f"{module_name}.{line_no}" + if module == "" and clibs.caller_frame is not None: + module_name = clibs.caller_frame.f_globals["__name__"].split(".")[-1] # + func_name = clibs.caller_frame.f_code.co_name + line_no = clibs.caller_frame.f_lineno + module = f"{module_name}-{func_name}:{line_no}" if level.lower() not in ["info", "warning", "error", "exception"]: level = "unknown" diff --git a/toolbox/codes/common/exception_handler.py b/toolbox/codes/common/exception_handler.py index cd58945..ad8836a 100644 --- a/toolbox/codes/common/exception_handler.py +++ b/toolbox/codes/common/exception_handler.py @@ -1,19 +1,28 @@ from functools import wraps from codes.common import db_operation -from inspect import getfile -from pathlib import Path +from inspect import currentframe +import traceback def handle_exception(stop: bool = False): def exceptions(func): - module = Path(getfile(func)).stem - func_name = func.__name__ @wraps(func) def wrapper(*args, **kwargs): + real_frame = currentframe().f_back try: return func(*args, **kwargs) except Exception as e: - db_operation.db_write_logs(str(e), "@".join([func_name, module]), "exception") + for frame, lineno in traceback.walk_tb(e.__traceback__): + if frame.f_code.co_name == func.__name__: + real_frame = frame + break + + tb = traceback.format_exc() # 完整堆栈 + module_name = real_frame.f_globals["__name__"].split(".")[-1] + func_name = real_frame.f_code.co_name + line_no = real_frame.f_lineno + module = f"{module_name}-{func_name}:{line_no}" + db_operation.db_write_logs(tb, module, "exception") if stop: raise e return wrapper diff --git a/toolbox/codes/common/ui2py.py b/toolbox/codes/common/ui2py.py deleted file mode 100644 index c396862..0000000 --- a/toolbox/codes/common/ui2py.py +++ /dev/null @@ -1,28 +0,0 @@ -import subprocess -import sys -from codes.common import clibs -from pathlib import Path - -UIC_CMD = "pyside6-uic" - - -def single_uic(ui_path: str, py_path: str): - for file in Path(ui_path).rglob("*.ui"): - file_name = file.stem - ui_file = file - py_file = Path(py_path) / f"{file_name}.py" - cmd = [UIC_CMD, "-o", py_file, ui_file] - - print(f"Processing {ui_file} -> {py_file}") - try: - subprocess.run(cmd, check=True, capture_output=True, text=True) - except subprocess.CalledProcessError as e: - print(f"转换失败: {ui_file}\n{e.stderr}", file=sys.stderr) - -def main(): - ui_path = clibs.base_path / "assets" / "ui" - py_path = clibs.base_path / "codes" / "ui" - single_uic(str(ui_path), str(py_path)) - -if __name__ == "__main__": - main() diff --git a/toolbox/codes/ui/main_ui.py b/toolbox/codes/ui/main_ui.py index 0c00337..3c69cd7 100644 --- a/toolbox/codes/ui/main_ui.py +++ b/toolbox/codes/ui/main_ui.py @@ -140,18 +140,16 @@ class MainWindow(QMainWindow): else: image_url = f"""https://www.bing.com{image["url"]}""" file = Path(f"{clibs.base_path}/assets/media/bg/{image_name}.jpg") - try: - req = requests.get(image_url, stream=True, timeout=10) - with open(file, "wb") as f: - for chunk in req.iter_content(chunk_size=8192): - f.write(chunk) - except Exception as e: - pass + req = requests.get(image_url, stream=True, timeout=10) + with open(file, "wb") as f: + for chunk in req.iter_content(chunk_size=8192): + f.write(chunk) # proverbs hitokoto = "https://v1.hitokoto.cn/" proverbs = [] proverb_file = Path(f"{clibs.base_path}/assets/media/hitokoto.json") req = requests.get(hitokoto) + print(f"req.text = {req.text}") if not proverb_file.exists(): proverb_file.touch() proverb_file.write_text("[]") @@ -160,7 +158,18 @@ class MainWindow(QMainWindow): with open(proverb_file, mode="rt", encoding="utf-8") as f: proverbs = json.load(f) - proverbs.append(eval(req.text)) + proverb = json.loads(req.text) + if None in proverb.values(): + for k, v in proverb.items(): + if v is None: + if v == "from_who": + proverb.update({k: "佚名"}) + elif v == "from": + proverb.update({k: "不知道"}) + else: + proverb.update({k: "-"}) + + proverbs.append(proverb) proverbs = del_repeat_proverb(proverbs) with open(proverb_file, mode="wt", encoding="utf-8") as f: json.dump(proverbs, f, ensure_ascii=False) diff --git a/toolbox/codes/ui/overlay_page/overlay_ui.py b/toolbox/codes/ui/overlay_page/overlay_ui.py index 54fae0c..27d7384 100644 --- a/toolbox/codes/ui/overlay_page/overlay_ui.py +++ b/toolbox/codes/ui/overlay_page/overlay_ui.py @@ -10,20 +10,32 @@ from codes.common.signal_bus import signal_bus class LunarClockLabel(QLabel): - def __init__(self, parent=None): + def __init__(self, parent=None, flag=0): super().__init__(parent) self.setMinimumWidth(350) timer = QTimer(self) - timer.timeout.connect(self.update_time) timer.start(1000) - self.update_time() + if flag == 0: + self.update_date() + timer.timeout.connect(self.update_date) + else: + self.update_time() + timer.timeout.connect(self.update_time) + + def update_date(self): + dt = QDateTime.currentDateTime() + g = dt.date() + z = ZhDate.today() + week = "一二三四五六日"[g.dayOfWeek() - 1] + text = f"{g.year()}年{g.month()}月{g.day()}日 {z.chinese()[5:]} 星期{week}" + self.setText(text) def update_time(self): dt = QDateTime.currentDateTime() g = dt.date() z = ZhDate.today() week = "一二三四五六日"[g.dayOfWeek() - 1] - text = f"{g.year()}年{g.month()}月{g.day()}日 {z.chinese()[5:]} 星期{week} {dt.toString('hh:mm:ss')}" + text = f"{dt.toString('hh:mm:ss')}" self.setText(text) @@ -54,6 +66,8 @@ class WidgetWithBg(QWidget): self.lb_empty_up = QLabel(self) layout_v.addWidget(self.lb_empty_up) # 头像区 + layout_h_1 = QHBoxLayout() + layout_h_1.addStretch(1) self.lb_avatar = DoubleClickLabel(self) self.lb_avatar.setAlignment(Qt.AlignmentFlag.AlignCenter) avatar = QPixmap(clibs.avatar) @@ -61,7 +75,15 @@ class WidgetWithBg(QWidget): self.lb_avatar.setPixmap(avatar) self.lb_avatar.setScaledContents(True) self.lb_avatar.setFixedSize(144, 144) - layout_v.addWidget(self.lb_avatar, alignment=Qt.AlignmentFlag.AlignCenter) + layout_h_1.addWidget(self.lb_avatar) + self.lb_time = LunarClockLabel(self, flag=1) + self.lb_time.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.lb_time.setStyleSheet("color: rgba(255,255,255,255);") + self.lb_time.setFont(QFont("Arial Black", 56, QFont.Weight.Bold)) + layout_h_1.addWidget(self.lb_time) + layout_h_1.addStretch(1) + layout_v.addLayout(layout_h_1) + # layout_v.addWidget(self.lb_avatar, alignment=Qt.AlignmentFlag.AlignCenter) # 艺术字区 self.lb_name = QLabel(self) self.lb_name.setAlignment(Qt.AlignmentFlag.AlignCenter) @@ -99,13 +121,13 @@ class WidgetWithBg(QWidget): self.line_right.setLineWidth(1) self.line_right.setFixedWidth(100) # 时间区-时间 - self.lb_time = LunarClockLabel(self) - self.lb_time.setAlignment(Qt.AlignmentFlag.AlignCenter) - self.lb_time.setStyleSheet("color: rgba(255,255,255,255);") - self.lb_time.setFont(QFont("Consolas", 12, QFont.Weight.Bold)) + self.lb_date = LunarClockLabel(self) + self.lb_date.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.lb_date.setStyleSheet("color: rgba(255,255,255,255);") + self.lb_date.setFont(QFont("Consolas", 12, QFont.Weight.Bold)) layout_h.addStretch(1) layout_h.addWidget(self.line_left) - layout_h.addWidget(self.lb_time) + layout_h.addWidget(self.lb_date) layout_h.addWidget(self.line_right) layout_h.addStretch(1) layout_v.addLayout(layout_h) @@ -141,10 +163,6 @@ class WidgetWithBg(QWidget): self.lb_avatar.doubleClicked.connect(self.toggle_auth_show) self.le_password.returnPressed.connect(self.validate_password) signal_bus.home_overlay_auth.connect(self.toggle_auth_show) - # self.sc_caL = QShortcut(QKeySequence("Esc"), self) - # self.sc_caL.activated.connect(self.toggle_auth_show) - # self.sc_caS = QShortcut(QKeySequence("Ctrl+Alt+M"), self) - # self.sc_caS.activated.connect(signal_bus.ho_full_screen.emit) def toggle_auth_show(self): if self.le_is_visible: @@ -178,7 +196,7 @@ class WidgetWithBg(QWidget): self.hide_le_password() return False else: - QMessageBox.critical(self, "错误", "密码不正确,请确认后重新输入!") + # QMessageBox.critical(self, "错误", "密码不正确,请确认后重新输入!") self.show_le_password() return False diff --git a/toolbox/codes/ui/stacked_pages/w08_log.py b/toolbox/codes/ui/stacked_pages/w08_log.py index a2d2b23..3154692 100644 --- a/toolbox/codes/ui/stacked_pages/w08_log.py +++ b/toolbox/codes/ui/stacked_pages/w08_log.py @@ -1,4 +1,4 @@ -from PySide6.QtWidgets import QWidget, QLabel, QMessageBox, QVBoxLayout, QTreeWidget, QHBoxLayout, QPushButton, QFrame, QLineEdit, QCheckBox, QTreeWidgetItem, QDialog +from PySide6.QtWidgets import QWidget, QLabel, QMessageBox, QVBoxLayout, QTreeWidget, QHeaderView, QHBoxLayout, QPushButton, QFrame, QLineEdit, QCheckBox, QTreeWidgetItem, QDialog, QPlainTextEdit, QApplication from PySide6.QtCore import Qt, Signal from PySide6.QtGui import QColor, QIcon, QFont, QKeySequence, QIntValidator, QShortcut @@ -6,6 +6,30 @@ from codes.common.signal_bus import signal_bus from codes.common import db_operation from codes.common import clibs + +class LogDialog(QDialog): + def __init__(self, content, parent=None): + super().__init__(parent) + self.setWindowTitle("日志详情") + self.setGeometry(100, 100, 700, 300) + self.center_on_screen() + layout = QVBoxLayout(self) + self.plain_text_edit = QPlainTextEdit() + self.plain_text_edit.setReadOnly(True) + self.plain_text_edit.setPlainText(content) + layout.addWidget(self.plain_text_edit) + + def center_on_screen(self): + screen_geometry = QApplication.primaryScreen().geometry() + screen_width = screen_geometry.width() + screen_height = screen_geometry.height() + dialog_width = self.width() + dialog_height = self.height() + x = (screen_width - dialog_width) // 2 + y = (screen_height - dialog_height) // 2 + self.move(x, y) + + class PageNumberInput(QDialog): def __init__(self, parent=None): super().__init__(parent) @@ -64,7 +88,11 @@ class W08Log(QWidget): def ui_init(self): layout_v = QVBoxLayout(self) self.treeW = QTreeWidget() + self.treeW.setUniformRowHeights(True) self.treeW.setHeaderLabels(["ID", "时间戳", "告警级别", "模块信息", "告警内容"]) + header = self.treeW.header() + for i in range(self.treeW.columnCount()): + header.setSectionResizeMode(i, QHeaderView.ResizeMode.ResizeToContents) layout_v.addWidget(self.treeW, stretch=9) layout_h = QHBoxLayout() @@ -113,6 +141,7 @@ class W08Log(QWidget): self.setLayout(layout_v) def setup_slot(self): + self.treeW.itemDoubleClicked.connect(self.show_single_log) self.pb_previous.clicked.connect(self.previous_page) self.pb_next.clicked.connect(self.next_page) self.pb_search.clicked.connect(self.search_page) @@ -153,9 +182,6 @@ class W08Log(QWidget): self.records, self.len_records = db_operation.db_query_logs(levels=levels) if search_text: - # ids = [_[0] for _ in self.records] - # placeholder = ",".join(ids) - # clibs.cursor.execute(f"SELECT * FROM logs WHERE id IN ({placeholder}) and content like ?", (ids + [search_text, ])) self.records, self.len_records = db_operation.db_query_logs(search_text, self.records) self.is_searching = True @@ -219,6 +245,16 @@ class W08Log(QWidget): color = colors[record[2]] for col in range(5): item.setBackground(col, color) + item.setTextAlignment(0, Qt.AlignmentFlag.AlignRight) self.treeW.scrollToBottom() - + def show_single_log(self, item, column): + log_id = f"id = {item.text(0)}" + log_ts = f"ts = {item.text(1)}" + log_level = f"level = {item.text(2)}" + log_module = f"module = {item.text(3)}\n" + deco_line = "=" * 40 + log_msg = item.text(4) + content = "\n".join([log_id, log_ts, log_level, log_module, deco_line, log_msg]) + dialog = LogDialog(content, self) + dialog.exec() diff --git a/toolbox/readme.md b/toolbox/readme.md index 02ab343..6ff302d 100644 --- a/toolbox/readme.md +++ b/toolbox/readme.md @@ -2,6 +2,19 @@ ## 功能 +### 计算器 + +### 颜色板 + +### 时间转换 + +### ASCII码速查 + +### 账本 + +### 待办提醒 + +### 密码 ## TODOs @@ -9,4 +22,6 @@ ### 修改密码 -### 自定义图标 \ No newline at end of file +### 自定义图标 + +