feat(ui): 初步完成历史记录前端适配

This commit is contained in:
DLmaster
2025-02-21 12:04:52 +08:00
parent 3a9c670172
commit 5d7227c009
10 changed files with 606 additions and 272 deletions

View File

@@ -39,6 +39,10 @@ from qfluentwidgets import (
Signal,
ComboBox,
CheckBox,
IconWidget,
FluentIcon,
CardWidget,
BodyLabel,
qconfig,
ConfigItem,
TimeEdit,
@@ -319,3 +323,53 @@ class TimeEditSettingCard(SettingCard):
qconfig.set(self.configItem_time, value)
self.TimeEdit.setTime(QTime.fromString(value, "HH:mm"))
class StatefulItemCard(CardWidget):
def __init__(self, item: list, parent=None):
super().__init__(parent)
self.Layout = QHBoxLayout(self)
self.Label = BodyLabel(item[0], self)
self.icon = IconWidget(FluentIcon.MORE, self)
self.icon.setFixedSize(16, 16)
self.update_status(item[1])
self.Layout.addWidget(self.icon)
self.Layout.addWidget(self.Label)
self.Layout.addStretch(1)
def update_status(self, status: str):
if status == "完成":
self.icon.setIcon(FluentIcon.ACCEPT)
self.Label.setTextColor("#0eb840", "#0eb840")
elif status == "等待":
self.icon.setIcon(FluentIcon.MORE)
self.Label.setTextColor("#161823", "#e3f9fd")
elif status == "运行":
self.icon.setIcon(FluentIcon.PLAY)
self.Label.setTextColor("#177cb0", "#70f3ff")
elif status == "跳过":
self.icon.setIcon(FluentIcon.REMOVE)
self.Label.setTextColor("#75878a", "#7397ab")
elif status == "异常":
self.icon.setIcon(FluentIcon.CLOSE)
self.Label.setTextColor("#ff2121", "#ff2121")
class QuantifiedItemCard(CardWidget):
def __init__(self, item: list, parent=None):
super().__init__(parent)
self.Layout = QHBoxLayout(self)
self.Name = BodyLabel(item[0], self)
self.Numb = BodyLabel(str(item[1]), self)
self.Layout.addWidget(self.Name)
self.Layout.addStretch(1)
self.Layout.addWidget(self.Numb)

View File

@@ -34,8 +34,6 @@ from PySide6.QtWidgets import (
)
from qfluentwidgets import (
CardWidget,
IconWidget,
BodyLabel,
Pivot,
ScrollArea,
FluentIcon,
@@ -53,6 +51,7 @@ import json
from app.core import Config, TaskManager, Task, MainInfoBar
from .Widget import StatefulItemCard
class DispatchCenter(QWidget):
@@ -335,7 +334,7 @@ class DispatchBox(QWidget):
self.viewLayout.addLayout(self.Layout)
self.viewLayout.setContentsMargins(3, 0, 3, 3)
self.task_cards: List[ItemCard] = []
self.task_cards: List[StatefulItemCard] = []
def create_task(self, task_list: list):
"""创建任务队列"""
@@ -351,7 +350,7 @@ class DispatchBox(QWidget):
for task in task_list:
self.task_cards.append(ItemCard(task))
self.task_cards.append(StatefulItemCard(task))
self.Layout.addWidget(self.task_cards[-1])
self.Layout.addStretch(1)
@@ -373,7 +372,7 @@ class DispatchBox(QWidget):
self.viewLayout.addLayout(self.Layout)
self.viewLayout.setContentsMargins(3, 0, 3, 3)
self.user_cards: List[ItemCard] = []
self.user_cards: List[StatefulItemCard] = []
def create_user(self, user_list: list):
"""创建用户队列"""
@@ -389,7 +388,7 @@ class DispatchBox(QWidget):
for user in user_list:
self.user_cards.append(ItemCard(user))
self.user_cards.append(StatefulItemCard(user))
self.Layout.addWidget(self.user_cards[-1])
self.Layout.addStretch(1)
@@ -419,38 +418,3 @@ class DispatchBox(QWidget):
self.text.moveCursor(QTextCursor.End)
self.text.ensureCursorVisible()
class ItemCard(CardWidget):
def __init__(self, task_item: list, parent=None):
super().__init__(parent)
self.Layout = QHBoxLayout(self)
self.Label = BodyLabel(task_item[0], self)
self.icon = IconWidget(FluentIcon.MORE, self)
self.icon.setFixedSize(16, 16)
self.update_status(task_item[1])
self.Layout.addWidget(self.icon)
self.Layout.addWidget(self.Label)
self.Layout.addStretch(1)
def update_status(self, status: str):
if status == "完成":
self.icon.setIcon(FluentIcon.ACCEPT)
self.Label.setTextColor("#0eb840", "#0eb840")
elif status == "等待":
self.icon.setIcon(FluentIcon.MORE)
self.Label.setTextColor("#7397ab", "#7397ab")
elif status == "运行":
self.icon.setIcon(FluentIcon.PLAY)
self.Label.setTextColor("#2e4e7e", "#2e4e7e")
elif status == "跳过":
self.icon.setIcon(FluentIcon.REMOVE)
self.Label.setTextColor("#606060", "#d2d2d2")
elif status == "异常":
self.icon.setIcon(FluentIcon.CLOSE)
self.Label.setTextColor("#ff2121", "#ff2121")

264
app/ui/history.py Normal file
View File

@@ -0,0 +1,264 @@
# <AUTO_MAA:A MAA Multi Account Management and Automation Tool>
# Copyright © <2024> <DLmaster361>
# This file is part of AUTO_MAA.
# AUTO_MAA is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
# AUTO_MAA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
# the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with AUTO_MAA. If not, see <https://www.gnu.org/licenses/>.
# DLmaster_361@163.com
"""
AUTO_MAA
AUTO_MAA历史记录界面
v4.2
作者DLmaster_361
"""
from loguru import logger
from PySide6.QtWidgets import (
QWidget,
QVBoxLayout,
QHBoxLayout,
)
from qfluentwidgets import (
ScrollArea,
FluentIcon,
HeaderCardWidget,
PushButton,
ExpandGroupSettingCard,
TextBrowser,
)
from PySide6.QtCore import Signal
import os
from functools import partial
from pathlib import Path
from typing import List
from app.core import Config
from .Widget import StatefulItemCard, QuantifiedItemCard
class History(QWidget):
def __init__(
self,
parent=None,
):
super().__init__(parent)
self.setObjectName("历史记录")
content_widget = QWidget()
self.content_layout = QVBoxLayout(content_widget)
scrollArea = ScrollArea()
scrollArea.setWidgetResizable(True)
scrollArea.setWidget(content_widget)
layout = QVBoxLayout()
layout.addWidget(scrollArea)
self.setLayout(layout)
self.history_card_list = []
self.refresh()
def refresh(self):
"""刷新脚本实例界面"""
while self.content_layout.count() > 0:
item = self.content_layout.takeAt(0)
if item.spacerItem():
self.content_layout.removeItem(item.spacerItem())
elif item.widget():
item.widget().deleteLater()
self.history_card_list = []
history_dict = Config.search_history()
for date, user_list in history_dict.items():
self.history_card_list.append(HistoryCard(date, user_list, self))
self.content_layout.addWidget(self.history_card_list[-1])
self.content_layout.addStretch(1)
class HistoryCard(ExpandGroupSettingCard):
def __init__(self, date: str, user_list: List[Path], parent=None):
super().__init__(
FluentIcon.HISTORY,
date,
f"{date}的历史运行记录与统计信息",
parent,
)
widget = QWidget()
Layout = QVBoxLayout(widget)
self.viewLayout.setContentsMargins(0, 0, 0, 0)
self.viewLayout.setSpacing(0)
self.addGroupWidget(widget)
self.user_history_card_list = []
for user_path in user_list:
self.user_history_card_list.append(self.UserHistoryCard(user_path, self))
Layout.addWidget(self.user_history_card_list[-1])
class UserHistoryCard(HeaderCardWidget):
def __init__(
self,
user_history_path: Path,
parent=None,
):
super().__init__(parent)
self.setTitle(user_history_path.name.replace(".json", ""))
self.user_history_path = user_history_path
self.main_history = Config.load_maa_logs("总览", user_history_path)
self.index_card = self.IndexCard(self.main_history["条目索引"], self)
self.statistics_card = QHBoxLayout()
self.log_card = self.LogCard(self)
self.index_card.index_changed.connect(self.update_info)
self.viewLayout.addWidget(self.index_card)
self.viewLayout.addLayout(self.statistics_card)
self.viewLayout.addWidget(self.log_card)
self.viewLayout.setContentsMargins(0, 0, 0, 0)
self.viewLayout.setSpacing(0)
self.viewLayout.setStretch(0, 1)
self.viewLayout.setStretch(2, 4)
self.update_info("数据总览")
def update_info(self, index: str) -> None:
"""更新信息"""
if index == "数据总览":
while self.statistics_card.count() > 0:
item = self.statistics_card.takeAt(0)
if item.spacerItem():
self.statistics_card.removeItem(item.spacerItem())
elif item.widget():
item.widget().deleteLater()
for name, item_list in self.main_history["统计数据"].items():
statistics_card = self.StatisticsCard(name, item_list, self)
self.statistics_card.addWidget(statistics_card)
self.log_card.hide()
else:
single_history = Config.load_maa_logs(
"单项",
self.user_history_path.with_suffix("")
/ f"{index.replace(":","-")}.json",
)
while self.statistics_card.count() > 0:
item = self.statistics_card.takeAt(0)
if item.spacerItem():
self.statistics_card.removeItem(item.spacerItem())
elif item.widget():
item.widget().deleteLater()
for name, item_list in single_history["统计数据"].items():
statistics_card = self.StatisticsCard(name, item_list, self)
self.statistics_card.addWidget(statistics_card)
self.log_card.text.setText(single_history["日志信息"])
self.log_card.button.clicked.disconnect()
self.log_card.button.clicked.connect(
lambda: os.startfile(
self.user_history_path.with_suffix("")
/ f"{index.replace(":","-")}.log"
)
)
self.log_card.show()
self.viewLayout.setStretch(1, self.statistics_card.count())
self.setMinimumHeight(300)
class IndexCard(HeaderCardWidget):
index_changed = Signal(str)
def __init__(self, index_list: list, parent=None):
super().__init__(parent)
self.setTitle("记录条目")
self.Layout = QVBoxLayout()
self.viewLayout.addLayout(self.Layout)
self.viewLayout.setContentsMargins(3, 0, 3, 3)
self.index_cards: List[StatefulItemCard] = []
for index in index_list:
self.index_cards.append(StatefulItemCard(index))
self.index_cards[-1].clicked.connect(
partial(self.index_changed.emit, index[0])
)
self.Layout.addWidget(self.index_cards[-1])
self.Layout.addStretch(1)
class StatisticsCard(HeaderCardWidget):
def __init__(self, name: str, item_list: list, parent=None):
super().__init__(parent)
self.setTitle(name)
self.Layout = QVBoxLayout()
self.viewLayout.addLayout(self.Layout)
self.viewLayout.setContentsMargins(3, 0, 3, 3)
self.item_cards: List[QuantifiedItemCard] = []
for item in item_list:
self.item_cards.append(QuantifiedItemCard(item))
self.Layout.addWidget(self.item_cards[-1])
if len(item_list) == 0:
self.Layout.addWidget(QuantifiedItemCard(["暂无记录", ""]))
self.Layout.addStretch(1)
class LogCard(HeaderCardWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setTitle("日志")
self.text = TextBrowser(self)
self.button = PushButton("打开日志文件", self)
self.button.clicked.connect(lambda: print("打开日志文件"))
Layout = QVBoxLayout()
Layout.addWidget(self.text)
Layout.addWidget(self.button)
self.viewLayout.setContentsMargins(3, 0, 3, 3)
self.viewLayout.addLayout(Layout)

View File

@@ -46,6 +46,8 @@ from qfluentwidgets import (
from PySide6.QtGui import QIcon, QCloseEvent
from PySide6.QtCore import Qt, QTimer
import json
from datetime import datetime, timedelta
import shutil
from app.core import Config, TaskManager, MainTimer, MainInfoBar
from app.services import Notify, Crypto, System
@@ -53,6 +55,7 @@ from .setting import Setting
from .member_manager import MemberManager
from .queue_manager import QueueManager
from .dispatch_center import DispatchCenter
from .history import History
class AUTO_MAA(MSFluentWindow):
@@ -76,6 +79,7 @@ class AUTO_MAA(MSFluentWindow):
self.member_manager = MemberManager(self)
self.queue_manager = QueueManager(self)
self.dispatch_center = DispatchCenter(self)
self.history = History(self)
self.addSubInterface(
self.setting,
@@ -105,6 +109,13 @@ class AUTO_MAA(MSFluentWindow):
FluentIcon.IOT,
NavigationItemPosition.TOP,
)
self.addSubInterface(
self.history,
FluentIcon.HISTORY,
"历史记录",
FluentIcon.HISTORY,
NavigationItemPosition.BOTTOM,
)
self.stackedWidget.currentChanged.connect(
lambda index: (self.member_manager.refresh() if index == 1 else None)
)
@@ -123,6 +134,9 @@ class AUTO_MAA(MSFluentWindow):
self.dispatch_center.update_top_bar() if index == 3 else None
)
)
self.stackedWidget.currentChanged.connect(
lambda index: (self.history.refresh() if index == 4 else None)
)
# 创建系统托盘及其菜单
self.tray = QSystemTrayIcon(
@@ -197,6 +211,9 @@ class AUTO_MAA(MSFluentWindow):
qconfig.load(Config.config_path, Config.global_config)
Config.global_config.save()
# 清理旧日志
self.clean_old_logs()
# 检查密码
self.setting.check_PASSWORD()
@@ -247,6 +264,40 @@ class AUTO_MAA(MSFluentWindow):
if reason == QSystemTrayIcon.DoubleClick:
self.show_ui("显示主窗口")
def clean_old_logs(self):
"""
删除超过用户设定天数的日志文件(基于目录日期)
"""
if (
Config.global_config.get(Config.global_config.function_HistoryRetentionTime)
== 0
):
logger.info("由于用户设置日志永久保留,跳过日志清理")
return
deleted_count = 0
for date_folder in (Config.app_path / "history").iterdir():
if not date_folder.is_dir():
continue # 只处理日期文件夹
try:
# 只检查 `YYYY-MM-DD` 格式的文件夹
folder_date = datetime.strptime(date_folder.name, "%Y-%m-%d")
if datetime.now() - folder_date > timedelta(
days=Config.global_config.get(
Config.global_config.function_HistoryRetentionTime
)
):
shutil.rmtree(date_folder, ignore_errors=True)
deleted_count += 1
logger.info(f"已删除超期日志目录: {date_folder}")
except ValueError:
logger.warning(f"非日期格式的目录: {date_folder}")
logger.info(f"清理完成: {deleted_count} 个日期目录")
def start_main_task(self) -> None:
"""启动主任务"""

View File

@@ -77,7 +77,6 @@ class Setting(QWidget):
self.function = FunctionSettingCard(self)
self.start = StartSettingCard(self)
self.ui = UiSettingCard(self)
self.log_settings = LogSettingCard(self)
self.notification = NotifySettingCard(self)
self.security = SecuritySettingCard(self)
self.updater = UpdaterSettingCard(self)
@@ -93,7 +92,6 @@ class Setting(QWidget):
content_layout.addWidget(self.function)
content_layout.addWidget(self.start)
content_layout.addWidget(self.ui)
content_layout.addWidget(self.log_settings)
content_layout.addWidget(self.notification)
content_layout.addWidget(self.security)
content_layout.addWidget(self.updater)
@@ -419,6 +417,13 @@ class FunctionSettingCard(HeaderCardWidget):
super().__init__(parent)
self.setTitle("功能")
self.card_HistoryRetentionTime = ComboBoxSettingCard(
configItem=Config.global_config.function_HistoryRetentionTime,
icon=FluentIcon.PAGE_RIGHT,
title="历史记录保留时间",
content="选择历史记录的保留时间,超期自动清理",
texts=["7 天", "15 天", "30 天", "60 天", "永久"],
)
self.card_IfAllowSleep = SwitchSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="启动时阻止系统休眠",
@@ -434,6 +439,7 @@ class FunctionSettingCard(HeaderCardWidget):
)
Layout = QVBoxLayout()
Layout.addWidget(self.card_HistoryRetentionTime)
Layout.addWidget(self.card_IfAllowSleep)
Layout.addWidget(self.card_IfSilence)
Layout.addWidget(self.card_IfAgreeBilibili)
@@ -799,35 +805,6 @@ class OtherSettingCard(HeaderCardWidget):
self.viewLayout.setSpacing(0)
self.addGroupWidget(widget)
class LogSettingCard(HeaderCardWidget):
"""日志管理设置"""
def __init__(self, parent=None):
super().__init__(parent)
self.setTitle("日志管理")
# 日志存储开关
self.card_IfEnableLog = SwitchSettingCard(
icon=FluentIcon.PAGE_RIGHT,
title="启用日志存储",
content="记录并存储每次运行的日志,用于多账号日常掉落统计",
configItem=Config.global_config.function_IfEnableLog,
)
# 日志保留天数设置
self.card_LogRetentionDays = ComboBoxSettingCard(
configItem=Config.global_config.function_LogRetentionDays,
icon=FluentIcon.PAGE_RIGHT,
title="日志保留天数",
content="选择日志的保留时间,超期自动清理",
texts=["7 天", "15 天", "30 天", "60 天", "永不清理"],
)
Layout = QVBoxLayout()
Layout.addWidget(self.card_IfEnableLog)
Layout.addWidget(self.card_LogRetentionDays)
self.viewLayout.addLayout(Layout)
def version_text(version_numb: list) -> str:
"""将版本号列表转为可读的文本信息"""