# AUTO_MAA:A MAA Multi Account Management and Automation Tool # Copyright © 2024-2025 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 . # Contact: DLmaster_361@163.com """ AUTO_MAA AUTO_MAA计划管理界面 v4.3 作者:DLmaster_361 """ from loguru import logger from PySide6.QtWidgets import ( QWidget, QFileDialog, QHBoxLayout, QVBoxLayout, QStackedWidget, QTableWidgetItem, QHeaderView, ) from PySide6.QtGui import QIcon from qfluentwidgets import ( Action, ScrollArea, FluentIcon, MessageBox, HeaderCardWidget, CommandBar, ExpandGroupSettingCard, PushSettingCard, TableWidget, PrimaryToolButton, ) from PySide6.QtCore import Signal from datetime import datetime from functools import partial from pathlib import Path from typing import List import shutil import json from app.core import Config, MainInfoBar, TaskManager, MaaPlanConfig, Network from app.services import Crypto from .downloader import DownloadManager from .Widget import ( LineEditMessageBox, LineEditSettingCard, SpinBoxSettingCard, ComboBoxMessageBox, EditableComboBoxSettingCard, PasswordLineEditSettingCard, UserLableSettingCard, ComboBoxSettingCard, SwitchSettingCard, PushAndSwitchButtonSettingCard, PushAndComboBoxSettingCard, PivotArea, ) class PlanManager(QWidget): """计划管理父界面""" def __init__(self, parent=None): super().__init__(parent) self.setObjectName("计划管理") layout = QVBoxLayout(self) self.tools = CommandBar() self.plan_manager = self.PlanSettingBox(self) # 逐个添加动作 self.tools.addActions( [ Action(FluentIcon.ADD_TO, "新建计划表", triggered=self.add_setting_box), Action( FluentIcon.REMOVE_FROM, "删除计划表", triggered=self.del_setting_box ), ] ) self.tools.addSeparator() self.tools.addActions( [ Action( FluentIcon.LEFT_ARROW, "向左移动", triggered=self.left_setting_box ), Action( FluentIcon.RIGHT_ARROW, "向右移动", triggered=self.right_setting_box ), ] ) self.tools.addSeparator() layout.addWidget(self.tools) layout.addWidget(self.plan_manager) def add_setting_box(self): """添加一个计划表""" choice = ComboBoxMessageBox( self.window(), "选择一个计划类型以添加相应计划表", ["选择计划类型"], [["MAA"]], ) if choice.exec() and choice.input[0].currentIndex() != -1: if choice.input[0].currentText() == "MAA": index = len(Config.plan_dict) + 1 maa_plan_config = MaaPlanConfig() maa_plan_config.load( Config.app_path / f"config/MaaPlanConfig/计划_{index}/config.json", maa_plan_config, ) maa_plan_config.save() Config.plan_dict[f"计划_{index}"] = { "Type": "Maa", "Path": Config.app_path / f"config/MaaPlanConfig/计划_{index}", "Config": maa_plan_config, } self.plan_manager.add_MaaSettingBox(index) self.plan_manager.switch_SettingBox(index) logger.success(f"计划管理 计划_{index} 添加成功") MainInfoBar.push_info_bar( "success", "操作成功", f"添加计划表 计划_{index}", 3000 ) def del_setting_box(self): """删除一个计划表""" name = self.plan_manager.pivot.currentRouteKey() if name == None: logger.warning("删除计划表时未选择计划表") MainInfoBar.push_info_bar( "warning", "未选择计划表", "请选择一个计划表", 5000 ) return None if len(Config.running_list) > 0: logger.warning("删除计划表时调度队列未停止运行") MainInfoBar.push_info_bar( "warning", "调度中心正在执行任务", "请等待或手动中止任务", 5000 ) return None choice = MessageBox( "确认", f"确定要删除 {name} 吗?", self.window(), ) if choice.exec(): self.plan_manager.clear_SettingBox() shutil.rmtree(Config.plan_dict[name]["Path"]) Config.change_plan(name, "禁用") for i in range(int(name[3:]) + 1, len(Config.plan_dict) + 1): if Config.plan_dict[f"计划_{i}"]["Path"].exists(): Config.plan_dict[f"计划_{i}"]["Path"].rename( Config.plan_dict[f"计划_{i}"]["Path"].with_name(f"计划_{i-1}") ) Config.change_queue(f"计划_{i}", f"计划_{i-1}") self.plan_manager.show_SettingBox(max(int(name[3:]) - 1, 1)) logger.success(f"计划表 {name} 删除成功") MainInfoBar.push_info_bar("success", "操作成功", f"删除计划表 {name}", 3000) def left_setting_box(self): """向左移动计划表""" name = self.plan_manager.pivot.currentRouteKey() if name == None: logger.warning("向左移动计划表时未选择计划表") MainInfoBar.push_info_bar( "warning", "未选择计划表", "请选择一个计划表", 5000 ) return None index = int(name[3:]) if index == 1: logger.warning("向左移动计划表时已到达最左端") MainInfoBar.push_info_bar( "warning", "已经是第一个计划表", "无法向左移动", 5000 ) return None if len(Config.running_list) > 0: logger.warning("向左移动计划表时调度队列未停止运行") MainInfoBar.push_info_bar( "warning", "调度中心正在执行任务", "请等待或手动中止任务", 5000 ) return None self.plan_manager.clear_SettingBox() Config.plan_dict[name]["Path"].rename( Config.plan_dict[name]["Path"].with_name("计划_0") ) Config.change_queue(name, "计划_0") Config.plan_dict[f"计划_{index-1}"]["Path"].rename( Config.plan_dict[name]["Path"] ) Config.change_queue(f"计划_{index-1}", name) Config.plan_dict[name]["Path"].with_name("计划_0").rename( Config.plan_dict[f"计划_{index-1}"]["Path"] ) Config.change_queue("计划_0", f"计划_{index-1}") self.plan_manager.show_SettingBox(index - 1) logger.success(f"计划表 {name} 左移成功") MainInfoBar.push_info_bar("success", "操作成功", f"左移计划表 {name}", 3000) def right_setting_box(self): """向右移动计划表""" name = self.plan_manager.pivot.currentRouteKey() if name == None: logger.warning("向右移动计划表时未选择计划表") MainInfoBar.push_info_bar( "warning", "未选择计划表", "请选择一个计划表", 5000 ) return None index = int(name[3:]) if index == len(Config.plan_dict): logger.warning("向右移动计划表时已到达最右端") MainInfoBar.push_info_bar( "warning", "已经是最后一个计划表", "无法向右移动", 5000 ) return None if len(Config.running_list) > 0: logger.warning("向右移动计划表时调度队列未停止运行") MainInfoBar.push_info_bar( "warning", "调度中心正在执行任务", "请等待或手动中止任务", 5000 ) return None self.plan_manager.clear_SettingBox() Config.plan_dict[name]["Path"].rename( Config.plan_dict[name]["Path"].with_name("计划_0") ) Config.change_queue(name, "计划_0") Config.plan_dict[f"计划_{index+1}"]["Path"].rename( Config.plan_dict[name]["Path"] ) Config.change_queue(f"计划_{index+1}", name) Config.plan_dict[name]["Path"].with_name("计划_0").rename( Config.plan_dict[f"计划_{index+1}"]["Path"] ) Config.change_queue("计划_0", f"计划_{index+1}") self.plan_manager.show_SettingBox(index + 1) logger.success(f"计划表 {name} 右移成功") MainInfoBar.push_info_bar("success", "操作成功", f"右移计划表 {name}", 3000) def refresh_dashboard(self): """刷新所有计划表的用户仪表盘""" for script in self.plan_manager.script_list: script.user_setting.user_manager.user_dashboard.load_info() class PlanSettingBox(QWidget): """计划管理子页面组""" def __init__(self, parent=None): super().__init__(parent) self.setObjectName("计划管理页面组") self.pivotArea = PivotArea(self) self.pivot = self.pivotArea.pivot self.stackedWidget = QStackedWidget(self) self.stackedWidget.setContentsMargins(0, 0, 0, 0) self.stackedWidget.setStyleSheet("background: transparent; border: none;") self.script_list: List[PlanManager.PlanSettingBox.MaaPlanSettingBox] = [] self.Layout = QVBoxLayout(self) self.Layout.addWidget(self.pivotArea) self.Layout.addWidget(self.stackedWidget) self.Layout.setContentsMargins(0, 0, 0, 0) self.pivot.currentItemChanged.connect( lambda index: self.switch_SettingBox( int(index[3:]), if_chang_pivot=False ) ) self.show_SettingBox(1) def show_SettingBox(self, index) -> None: """加载所有子界面""" Config.search_plan() for name, info in Config.plan_dict.items(): if info["Type"] == "Maa": self.add_MaaSettingBox(int(name[3:])) self.switch_SettingBox(index) def switch_SettingBox(self, index: int, if_chang_pivot: bool = True) -> None: """切换到指定的子界面""" if len(Config.plan_dict) == 0: return None if index > len(Config.plan_dict): return None if if_chang_pivot: self.pivot.setCurrentItem(self.script_list[index - 1].objectName()) self.stackedWidget.setCurrentWidget(self.script_list[index - 1]) def clear_SettingBox(self) -> None: """清空所有子界面""" for sub_interface in self.script_list: self.stackedWidget.removeWidget(sub_interface) sub_interface.deleteLater() self.script_list.clear() self.pivot.clear() def add_MaaPlanSettingBox(self, uid: int) -> None: """添加一个MAA设置界面""" maa_plan_setting_box = self.MaaPlanSettingBox(uid, self) self.script_list.append(maa_plan_setting_box) self.stackedWidget.addWidget(self.script_list[-1]) self.pivot.addItem(routeKey=f"计划_{uid}", text=f"计划 {uid}") class MaaPlanSettingBox(HeaderCardWidget): """MAA类计划设置界面""" def __init__(self, uid: int, parent=None): super().__init__(parent) self.setObjectName(f"计划_{uid}") self.config = Config.plan_dict[f"计划_{uid}"]["Config"] self.dashboard = TableWidget(self) self.dashboard.setColumnCount(11) self.dashboard.setHorizontalHeaderLabels( [ "吃理智药", "连战次数", "关卡选择", "备选关卡 - 1", "备选关卡 - 2", "剩余理智关卡", ] ) self.dashboard.setEditTriggers(TableWidget.NoEditTriggers) self.dashboard.verticalHeader().setVisible(False) for col in range(6): self.dashboard.horizontalHeader().setSectionResizeMode( col, QHeaderView.ResizeMode.Stretch ) self.viewLayout.addWidget(self.dashboard) self.viewLayout.setContentsMargins(3, 0, 3, 3) Config.PASSWORD_refreshed.connect(self.load_info) def load_info(self): self.user_data = Config.plan_dict[self.name]["UserData"] self.dashboard.setRowCount(len(self.user_data)) for name, info in self.user_data.items(): config = info["Config"] text_list = [] if not config.get(config.Data_IfPassCheck): text_list.append("未通过人工排查") text_list.append( f"今日已代理{config.get(config.Data_ProxyTimes)}次" if Config.server_date().strftime("%Y-%m-%d") == config.get(config.Data_LastProxyDate) else "今日未进行代理" ) text_list.append( "本周剿灭已完成" if datetime.strptime( config.get(config.Data_LastAnnihilationDate), "%Y-%m-%d", ).isocalendar()[:2] == Config.server_date().isocalendar()[:2] else "本周剿灭未完成" ) button = PrimaryToolButton(FluentIcon.CHEVRON_RIGHT, self) button.setFixedSize(32, 32) button.clicked.connect(partial(self.switch_to.emit, name)) self.dashboard.setItem( int(name[3:]) - 1, 0, QTableWidgetItem(config.get(config.Info_Name)), ) self.dashboard.setItem( int(name[3:]) - 1, 1, QTableWidgetItem(config.get(config.Info_Id)), ) self.dashboard.setItem( int(name[3:]) - 1, 2, QTableWidgetItem( Crypto.AUTO_decryptor( config.get(config.Info_Password), Config.PASSWORD, ) if Config.PASSWORD else "******" ), ) self.dashboard.setItem( int(name[3:]) - 1, 3, QTableWidgetItem( "启用" if config.get(config.Info_Status) and config.get(config.Info_RemainedDay) != 0 else "禁用" ), ) self.dashboard.setItem( int(name[3:]) - 1, 4, QTableWidgetItem(" | ".join(text_list)), ) self.dashboard.setItem( int(name[3:]) - 1, 5, QTableWidgetItem(str(config.get(config.Info_MedicineNumb))), ) self.dashboard.setItem( int(name[3:]) - 1, 6, QTableWidgetItem( Config.gameid_dict["ALL"]["text"][ Config.gameid_dict["ALL"]["value"].index( config.get(config.Info_GameId) ) ] if config.get(config.Info_GameId) in Config.gameid_dict["ALL"]["value"] else config.get(config.Info_GameId) ), ) self.dashboard.setItem( int(name[3:]) - 1, 7, QTableWidgetItem( Config.gameid_dict["ALL"]["text"][ Config.gameid_dict["ALL"]["value"].index( config.get(config.Info_GameId_1) ) ] if config.get(config.Info_GameId_1) in Config.gameid_dict["ALL"]["value"] else config.get(config.Info_GameId_1) ), ) self.dashboard.setItem( int(name[3:]) - 1, 8, QTableWidgetItem( Config.gameid_dict["ALL"]["text"][ Config.gameid_dict["ALL"]["value"].index( config.get(config.Info_GameId_2) ) ] if config.get(config.Info_GameId_2) in Config.gameid_dict["ALL"]["value"] else config.get(config.Info_GameId_2) ), ) self.dashboard.setItem( int(name[3:]) - 1, 9, QTableWidgetItem( "不使用" if config.get(config.Info_GameId_Remain) == "-" else ( ( Config.gameid_dict["ALL"]["text"][ Config.gameid_dict["ALL"]["value"].index( config.get(config.Info_GameId_Remain) ) ] ) if config.get(config.Info_GameId_Remain) in Config.gameid_dict["ALL"]["value"] else config.get(config.Info_GameId_Remain) ) ), ) self.dashboard.setCellWidget(int(name[3:]) - 1, 10, button)