From 0d904b229e622932ea928147e7fc594e5653f516 Mon Sep 17 00:00:00 2001 From: aoxuan Date: Sun, 18 May 2025 01:57:48 +0800 Subject: [PATCH 01/10] =?UTF-8?q?feat(core):=20=E5=88=9D=E6=AD=A5=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E6=96=B0=E5=A2=9E=E7=94=A8=E6=88=B7=E5=8D=95=E7=8B=AC?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/core/config.py | 14 +++ app/models/MAA.py | 41 ++++++- app/services/notification.py | 122 +++++++++++++++++++++ app/ui/member_manager.py | 207 +++++++++++++++++++++++++++++++++++ 4 files changed, 381 insertions(+), 3 deletions(-) diff --git a/app/core/config.py b/app/core/config.py index 77cfbbf..6a5fb17 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -439,6 +439,20 @@ class MaaUserConfig(LQConfig): "Data", "CustomInfrastPlanIndex", "0" ) + # 新增用户单独通知字段 + self.Notify_Enable = ConfigItem("Notify_Enable", False, False) + self.Notify_IfSMTP = ConfigItem("Notify_IfSMTP", False, False) + self.Notify_SMTPServerAddress = ConfigItem("Notify_SMTPServerAddress", "", "") + self.Notify_AuthorizationCode = ConfigItem("Notify_AuthorizationCode", "", "") + self.Notify_FromAddress = ConfigItem("Notify_FromAddress", "", "") + self.Notify_ToAddress = ConfigItem("Notify_ToAddress", "", "") + self.Notify_IfServerChan = ConfigItem("Notify_IfServerChan", False, False) + self.Notify_ServerChanKey = ConfigItem("Notify_ServerChanKey", "", "") + self.Notify_ServerChanChannel = ConfigItem("Notify_ServerChanChannel", "", "") + self.Notify_ServerChanTag = ConfigItem("Notify_ServerChanTag", "", "") + self.Notify_IfCompanyWebHookBot = ConfigItem("Notify_IfCompanyWebHookBot", False, False) + self.Notify_CompanyWebHookBotUrl = ConfigItem("Notify_CompanyWebHookBotUrl", "", "") + class MaaPlanConfig(LQConfig): """MAA计划表配置""" diff --git a/app/models/MAA.py b/app/models/MAA.py index 260d0ca..6662a30 100644 --- a/app/models/MAA.py +++ b/app/models/MAA.py @@ -40,6 +40,7 @@ from typing import Union, List, Dict from app.core import Config, MaaConfig, MaaUserConfig from app.services import Notify, System +from app.services.notification import Notification, UserNotification class MaaManager(QObject): @@ -1746,7 +1747,6 @@ class MaaManager(QObject): ) if mode == "代理结果": - # 生成文本通知内容 message_text = ( f"任务开始时间:{message["start_time"]},结束时间:{message["end_time"]}\n" @@ -1768,14 +1768,26 @@ class MaaManager(QObject): template = env.get_template("MAA_result.html") message_html = template.render(message) + # 发送全局通知 Notify.send_mail("网页", title, message_html) Notify.ServerChanPush(title, f"{message_text}\n\nAUTO_MAA 敬上") Notify.CompanyWebHookBotPush(title, f"{message_text}\n\nAUTO_MAA 敬上") + # 发送用户单独通知 + for user_name in message["failed_user"].split("、") + message["waiting_user"].split("、"): + if not user_name: # 跳过空字符串 + continue + user_config = Config.member_dict.get(user_name) + if user_config and user_config.get(user_config.Notify_Enable): + user_notify = UserNotification(user_config) + user_notify.send_notification( + f"{self.mode[2:4]}任务未完成通知", + f"您的{self.mode[2:4]}任务未完成,请检查相关设置。\n\n{message_text}" + ) + return message_text elif mode == "统计信息": - # 生成文本通知内容 formatted = [] for stage, items in message["drop_statistics"].items(): @@ -1801,18 +1813,41 @@ class MaaManager(QObject): template = env.get_template("MAA_statistics.html") message_html = template.render(message) + # 发送全局通知 Notify.send_mail("网页", title, message_html) # ServerChan的换行是两个换行符。故而将\n替换为\n\n serverchan_message = message_text.replace("\n", "\n\n") Notify.ServerChanPush(title, f"{serverchan_message}\n\nAUTO_MAA 敬上") Notify.CompanyWebHookBotPush(title, f"{message_text}\n\nAUTO_MAA 敬上") - elif mode == "公招六星": + # 发送用户单独通知 + user_name = message.get("user_info") + if user_name: + user_config = Config.member_dict.get(user_name) + if user_config and user_config.get(user_config.Notify_Enable): + user_notify = UserNotification(user_config) + user_notify.send_notification( + f"{self.mode[2:4]}任务统计报告", + f"您的{self.mode[2:4]}任务统计报告如下:\n\n{message_text}" + ) + elif mode == "公招六星": # 生成HTML通知内容 template = env.get_template("MAA_six_star.html") message_html = template.render(message) + # 发送全局通知 Notify.send_mail("网页", title, message_html) Notify.ServerChanPush(title, "好羡慕~\n\nAUTO_MAA 敬上") Notify.CompanyWebHookBotPush(title, "好羡慕~\n\nAUTO_MAA 敬上") + + # 发送用户单独通知 + user_name = message.get("user_name") + if user_name: + user_config = Config.member_dict.get(user_name) + if user_config and user_config.get(user_config.Notify_Enable): + user_notify = UserNotification(user_config) + user_notify.send_notification( + "公招六星通知", + "恭喜您在公招中获得了六星干员!" + ) diff --git a/app/services/notification.py b/app/services/notification.py index 0f63acf..9666f9a 100644 --- a/app/services/notification.py +++ b/app/services/notification.py @@ -313,4 +313,126 @@ class Notification(QWidget): return True +class UserNotification: + """用户单独通知服务""" + + def __init__(self, user_config): + self.config = user_config + + def send_notification(self, title: str, content: str) -> bool: + """发送用户通知 + + Args: + title: 通知标题 + content: 通知内容 + + Returns: + bool: 是否发送成功 + """ + if not self.config.get(self.config.Notify_Enable): + return False + + success = False + + # 发送邮件通知 + if self._check_smtp_config(): + try: + self._send_email(title, content) + success = True + except Exception as e: + logger.error(f"发送邮件通知失败: {str(e)}") + + # 发送ServerChan通知 + if self.config.get(self.config.Notify_IfServerChan) and self._check_serverchan_config(): + try: + self._send_serverchan(title, content) + success = True + except Exception as e: + logger.error(f"发送ServerChan通知失败: {str(e)}") + + # 发送企业微信机器人通知 + if self.config.get(self.config.Notify_IfCompanyWebHookBot) and self._check_webhook_config(): + try: + self._send_webhook(title, content) + success = True + except Exception as e: + logger.error(f"发送企业微信机器人通知失败: {str(e)}") + + return success + + def _check_smtp_config(self) -> bool: + """检查SMTP配置是否完整""" + return all([ + self.config.get(self.config.Notify_IfSMTP), + self.config.get(self.config.Notify_SMTPServerAddress), + self.config.get(self.config.Notify_AuthorizationCode), + self.config.get(self.config.Notify_FromAddress), + self.config.get(self.config.Notify_ToAddress) + ]) + + def _check_serverchan_config(self) -> bool: + """检查ServerChan配置是否完整""" + return bool(self.config.get(self.config.Notify_ServerChanKey)) + + def _check_webhook_config(self) -> bool: + """检查企业微信机器人配置是否完整""" + return bool(self.config.get(self.config.Notify_CompanyWebHookBotUrl)) + + def _send_email(self, title: str, content: str): + """发送邮件通知""" + import smtplib + from email.mime.text import MIMEText + from email.header import Header + + msg = MIMEText(content, 'plain', 'utf-8') + msg['Subject'] = Header(title, 'utf-8') + msg['From'] = self.config.get(self.config.Notify_FromAddress) + msg['To'] = self.config.get(self.config.Notify_ToAddress) + + server = smtplib.SMTP_SSL(self.config.get(self.config.Notify_SMTPServerAddress)) + server.login( + self.config.get(self.config.Notify_FromAddress), + self.config.get(self.config.Notify_AuthorizationCode) + ) + server.send_message(msg) + server.quit() + + def _send_serverchan(self, title: str, content: str): + """发送ServerChan通知""" + import requests + + key = self.config.get(self.config.Notify_ServerChanKey) + channel = self.config.get(self.config.Notify_ServerChanChannel) + tag = self.config.get(self.config.Notify_ServerChanTag) + + url = f"https://sctapi.ftqq.com/{key}.send" + data = { + "title": title, + "desp": content, + "channel": channel if channel else 9, # 默认使用企业微信通道 + "tag": tag if tag else "" + } + + response = requests.post(url, data=data) + if response.status_code != 200: + raise Exception(f"ServerChan API返回错误: {response.text}") + + def _send_webhook(self, title: str, content: str): + """发送企业微信机器人通知""" + import requests + import json + + url = self.config.get(self.config.Notify_CompanyWebHookBotUrl) + data = { + "msgtype": "markdown", + "markdown": { + "content": f"### {title}\n{content}" + } + } + + response = requests.post(url, json=data) + if response.status_code != 200: + raise Exception(f"企业微信机器人API返回错误: {response.text}") + + Notify = Notification() diff --git a/app/ui/member_manager.py b/app/ui/member_manager.py index 34ff739..71fc30f 100644 --- a/app/ui/member_manager.py +++ b/app/ui/member_manager.py @@ -1529,6 +1529,140 @@ class MemberManager(QWidget): parent=self, ) + # 新增单独通知卡片 + self.card_NotifyEnable = SwitchSettingCard( + icon=FluentIcon.INFO, + title="启用单独通知", + content="启用后,任务结束将向该用户单独推送通知", + qconfig=self.config, + configItem=self.config.Notify_Enable, + parent=self + ) + self.card_NotifyIfSMTP = SwitchSettingCard( + icon=FluentIcon.INFO, + title="启用SMTP通知", + content="是否启用单独通知的SMTP邮件推送", + qconfig=self.config, + configItem=self.config.Notify_IfSMTP, + parent=self + ) + self.card_NotifySMTP = LineEditSettingCard( + icon=FluentIcon.INFO, + title="SMTP服务器地址", + content="单独通知的SMTP服务器地址", + text="请输入SMTP服务器地址", + qconfig=self.config, + configItem=self.config.Notify_SMTPServerAddress, + parent=self + ) + self.card_NotifyAuthCode = PasswordLineEditSettingCard( + icon=FluentIcon.INFO, + title="授权码", + content="单独通知的邮箱授权码", + text="请输入授权码", + algorithm="AUTO", + qconfig=self.config, + configItem=self.config.Notify_AuthorizationCode, + parent=self + ) + self.card_NotifyFrom = LineEditSettingCard( + icon=FluentIcon.INFO, + title="发件人邮箱", + content="单独通知的发件人邮箱", + text="请输入发件人邮箱", + qconfig=self.config, + configItem=self.config.Notify_FromAddress, + parent=self + ) + self.card_NotifyTo = LineEditSettingCard( + icon=FluentIcon.INFO, + title="收件人邮箱", + content="单独通知的收件人邮箱", + text="请输入收件人邮箱", + qconfig=self.config, + configItem=self.config.Notify_ToAddress, + parent=self + ) + self.card_NotifyIfServerChan = SwitchSettingCard( + icon=FluentIcon.INFO, + title="启用ServerChan", + content="是否启用单独通知的ServerChan推送", + qconfig=self.config, + configItem=self.config.Notify_IfServerChan, + parent=self + ) + self.card_NotifyServerChanKey = LineEditSettingCard( + icon=FluentIcon.INFO, + title="ServerChanKey", + content="单独通知的ServerChan SendKey", + text="请输入ServerChanKey", + qconfig=self.config, + configItem=self.config.Notify_ServerChanKey, + parent=self + ) + self.card_NotifyServerChanChannel = LineEditSettingCard( + icon=FluentIcon.INFO, + title="ServerChanChannel", + content="单独通知的ServerChan Channel", + text="请输入ServerChanChannel", + qconfig=self.config, + configItem=self.config.Notify_ServerChanChannel, + parent=self + ) + self.card_NotifyServerChanTag = LineEditSettingCard( + icon=FluentIcon.INFO, + title="ServerChanTag", + content="单独通知的ServerChan Tag", + text="请输入ServerChanTag", + qconfig=self.config, + configItem=self.config.Notify_ServerChanTag, + parent=self + ) + self.card_NotifyIfCompanyWebHookBot = SwitchSettingCard( + icon=FluentIcon.INFO, + title="启用企业微信机器人", + content="是否启用单独通知的企业微信机器人推送", + qconfig=self.config, + configItem=self.config.Notify_IfCompanyWebHookBot, + parent=self + ) + self.card_NotifyCompanyWebHookBotUrl = LineEditSettingCard( + icon=FluentIcon.INFO, + title="企业微信机器人WebhookUrl", + content="单独通知的企业微信机器人Webhook地址", + text="请输入WebhookUrl", + qconfig=self.config, + configItem=self.config.Notify_CompanyWebHookBotUrl, + parent=self + ) + + # 设置通知卡片默认隐藏 + self.card_NotifyIfSMTP.setVisible(False) + self.card_NotifySMTP.setVisible(False) + self.card_NotifyAuthCode.setVisible(False) + self.card_NotifyFrom.setVisible(False) + self.card_NotifyTo.setVisible(False) + self.card_NotifyIfServerChan.setVisible(False) + self.card_NotifyServerChanKey.setVisible(False) + self.card_NotifyServerChanChannel.setVisible(False) + self.card_NotifyServerChanTag.setVisible(False) + self.card_NotifyIfCompanyWebHookBot.setVisible(False) + self.card_NotifyCompanyWebHookBotUrl.setVisible(False) + + # 连接通知启用开关的信号 + self.card_NotifyEnable.checkedChanged.connect(self.toggle_notify_settings) + self.card_NotifyIfSMTP.checkedChanged.connect(self.toggle_smtp_settings) + + # 根据配置状态初始化显示 + if self.config.get(self.config.Notify_Enable): + self.toggle_notify_settings(True) + if self.config.get(self.config.Notify_IfSMTP): + self.toggle_smtp_settings(True) + if self.config.get(self.config.Notify_IfServerChan): + self.toggle_serverchan_settings(True) + if self.config.get(self.config.Notify_IfCompanyWebHookBot): + self.toggle_webhook_settings(True) + h1_layout = QHBoxLayout() h1_layout.addWidget(self.card_Name) h1_layout.addWidget(self.card_Id) @@ -1566,6 +1700,27 @@ class MemberManager(QWidget): Layout.addLayout(h6_layout) Layout.addLayout(h7_layout) Layout.addLayout(h8_layout) + + # 创建通知设置容器 + notify_container = QWidget() + notify_layout = QVBoxLayout(notify_container) + notify_layout.setContentsMargins(0, 0, 0, 0) + notify_layout.setSpacing(0) + + notify_layout.addWidget(self.card_NotifyEnable) + notify_layout.addWidget(self.card_NotifyIfSMTP) + notify_layout.addWidget(self.card_NotifySMTP) + notify_layout.addWidget(self.card_NotifyAuthCode) + notify_layout.addWidget(self.card_NotifyFrom) + notify_layout.addWidget(self.card_NotifyTo) + notify_layout.addWidget(self.card_NotifyIfServerChan) + notify_layout.addWidget(self.card_NotifyServerChanKey) + notify_layout.addWidget(self.card_NotifyServerChanChannel) + notify_layout.addWidget(self.card_NotifyServerChanTag) + notify_layout.addWidget(self.card_NotifyIfCompanyWebHookBot) + notify_layout.addWidget(self.card_NotifyCompanyWebHookBotUrl) + + Layout.addWidget(notify_container) self.viewLayout.addLayout(Layout) self.viewLayout.setContentsMargins(3, 0, 3, 3) @@ -1588,6 +1743,14 @@ class MemberManager(QWidget): Config.gameid_refreshed.connect(self.refresh_gameid) Config.PASSWORD_refreshed.connect(self.refresh_password) + # 连接ServerChan和企业微信机器人的开关信号 + self.card_NotifyIfServerChan.checkedChanged.connect( + lambda checked: self.toggle_serverchan_settings(checked) + ) + self.card_NotifyIfCompanyWebHookBot.checkedChanged.connect( + lambda checked: self.toggle_webhook_settings(checked) + ) + self.switch_mode() self.switch_infrastructure() @@ -1709,3 +1872,47 @@ class MemberManager(QWidget): } }, ) + + def toggle_notify_settings(self, checked: bool): + """切换通知设置卡片的显示状态""" + self.card_NotifyIfSMTP.setVisible(checked) + self.card_NotifyIfServerChan.setVisible(checked) + self.card_NotifyIfCompanyWebHookBot.setVisible(checked) + + # 根据SMTP开关状态控制相关设置 + if checked and self.config.get(self.config.Notify_IfSMTP): + self.toggle_smtp_settings(True) + else: + self.toggle_smtp_settings(False) + + # 根据ServerChan开关状态控制相关设置 + if checked and self.config.get(self.config.Notify_IfServerChan): + self.toggle_serverchan_settings(True) + else: + self.toggle_serverchan_settings(False) + + # 根据企业微信机器人开关状态控制相关设置 + if checked and self.config.get(self.config.Notify_IfCompanyWebHookBot): + self.toggle_webhook_settings(True) + else: + self.toggle_webhook_settings(False) + + def toggle_smtp_settings(self, checked: bool): + """切换SMTP相关设置的显示状态""" + if self.config.get(self.config.Notify_Enable): + self.card_NotifySMTP.setVisible(checked) + self.card_NotifyAuthCode.setVisible(checked) + self.card_NotifyFrom.setVisible(checked) + self.card_NotifyTo.setVisible(checked) + + def toggle_serverchan_settings(self, checked: bool): + """切换ServerChan相关设置的显示状态""" + if self.config.get(self.config.Notify_Enable): + self.card_NotifyServerChanKey.setVisible(checked) + self.card_NotifyServerChanChannel.setVisible(checked) + self.card_NotifyServerChanTag.setVisible(checked) + + def toggle_webhook_settings(self, checked: bool): + """切换企业微信机器人相关设置的显示状态""" + if self.config.get(self.config.Notify_Enable): + self.card_NotifyCompanyWebHookBotUrl.setVisible(checked) From bc5b15cec2afd41aaafa6f18622e64bcf3ab9406 Mon Sep 17 00:00:00 2001 From: aoxuan Date: Mon, 19 May 2025 01:10:20 +0800 Subject: [PATCH 02/10] =?UTF-8?q?feat(notification):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E9=80=9A=E7=9F=A5=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/notification.py | 173 +++++++++++++++++++++++------------ 1 file changed, 114 insertions(+), 59 deletions(-) diff --git a/app/services/notification.py b/app/services/notification.py index 9666f9a..d5514c1 100644 --- a/app/services/notification.py +++ b/app/services/notification.py @@ -25,18 +25,20 @@ v4.3 作者:DLmaster_361 """ -from PySide6.QtWidgets import QWidget -from PySide6.QtCore import Signal -import requests -import time -from loguru import logger -from plyer import notification import re import smtplib -from email.mime.text import MIMEText -from email.mime.multipart import MIMEMultipart +import time from email.header import Header +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText from email.utils import formataddr + +import requests +from PySide6.QtCore import Signal +from PySide6.QtWidgets import QWidget +from loguru import logger +from plyer import notification + from app.core import Config from app.services.security import Crypto @@ -315,51 +317,57 @@ class Notification(QWidget): class UserNotification: """用户单独通知服务""" - + def __init__(self, user_config): self.config = user_config - + def send_notification(self, title: str, content: str) -> bool: - """发送用户通知 - - Args: - title: 通知标题 - content: 通知内容 - - Returns: - bool: 是否发送成功 - """ + """发送用户通知""" + logger.info(f"单独通知-准备发送用户通知,标题: {title}") + if not self.config.get(self.config.Notify_Enable): + logger.warning("单独通知-用户通知功能未启用,跳过发送") return False - + success = False - - # 发送邮件通知 + + # 邮件通知 if self._check_smtp_config(): try: self._send_email(title, content) success = True except Exception as e: - logger.error(f"发送邮件通知失败: {str(e)}") - - # 发送ServerChan通知 - if self.config.get(self.config.Notify_IfServerChan) and self._check_serverchan_config(): + logger.error(f"单独通知-发送邮件通知失败: {str(e)}") + + # Server酱通知 + if ( + self.config.get(self.config.Notify_IfServerChan) + and self._check_serverchan_config() + ): try: self._send_serverchan(title, content) success = True except Exception as e: - logger.error(f"发送ServerChan通知失败: {str(e)}") - - # 发送企业微信机器人通知 - if self.config.get(self.config.Notify_IfCompanyWebHookBot) and self._check_webhook_config(): + logger.error(f"单独通知-发送 Server酱 通知失败: {str(e)}") + + # 企业微信群机器人 + if ( + self.config.get(self.config.Notify_IfCompanyWebHookBot) + and self._check_webhook_config() + ): try: self._send_webhook(title, content) success = True except Exception as e: - logger.error(f"发送企业微信机器人通知失败: {str(e)}") - + logger.error(f"单独通知-发送企业微信机器人通知失败: {str(e)}") + + if success: + logger.info("单独通知-用户通知发送完成") + else: + logger.warning("单独通知-所有通知方式均发送失败") + return success - + def _check_smtp_config(self) -> bool: """检查SMTP配置是否完整""" return all([ @@ -369,26 +377,27 @@ class UserNotification: self.config.get(self.config.Notify_FromAddress), self.config.get(self.config.Notify_ToAddress) ]) - + def _check_serverchan_config(self) -> bool: """检查ServerChan配置是否完整""" return bool(self.config.get(self.config.Notify_ServerChanKey)) - + def _check_webhook_config(self) -> bool: """检查企业微信机器人配置是否完整""" return bool(self.config.get(self.config.Notify_CompanyWebHookBotUrl)) - + def _send_email(self, title: str, content: str): """发送邮件通知""" + logger.debug("单独通知-开始发送邮件通知") import smtplib from email.mime.text import MIMEText from email.header import Header - + msg = MIMEText(content, 'plain', 'utf-8') msg['Subject'] = Header(title, 'utf-8') msg['From'] = self.config.get(self.config.Notify_FromAddress) msg['To'] = self.config.get(self.config.Notify_ToAddress) - + server = smtplib.SMTP_SSL(self.config.get(self.config.Notify_SMTPServerAddress)) server.login( self.config.get(self.config.Notify_FromAddress), @@ -396,32 +405,77 @@ class UserNotification: ) server.send_message(msg) server.quit() - + logger.success("单独通知-邮件通知发送成功") + def _send_serverchan(self, title: str, content: str): - """发送ServerChan通知""" + """发送 ServerChan 通知,支持 SCT、SC3、自定义域名等""" + logger.debug("单独通知-开始发送 ServerChan 通知") import requests - + import re + key = self.config.get(self.config.Notify_ServerChanKey) - channel = self.config.get(self.config.Notify_ServerChanChannel) tag = self.config.get(self.config.Notify_ServerChanTag) - - url = f"https://sctapi.ftqq.com/{key}.send" - data = { - "title": title, - "desp": content, - "channel": channel if channel else 9, # 默认使用企业微信通道 - "tag": tag if tag else "" - } - - response = requests.post(url, data=data) - if response.status_code != 200: - raise Exception(f"ServerChan API返回错误: {response.text}") - + channel = self.config.get(self.config.Notify_ServerChanChannel) + + if not key: + raise Exception("ServerChan SendKey 未设置") + + # 1. 构造 URL(支持 sctpN 和 sct 开头的) + if key.startswith("sctp"): + match = re.match(r"^sctp(\d+)t", key) + if match: + url = f"https://{match.group(1)}.push.ft07.com/send/{key}.send" + else: + raise ValueError("SendKey 格式错误,sctp 开头但不符合规范") + else: + url = f"https://sctapi.ftqq.com/{key}.send" + + logger.debug(f"单独通知-Server酱推送URL: {url}") + + # 2. 校验 tag 和 channel 格式 + def is_valid(s): + return s == "" or ( + s == "|".join(s.split("|")) and (s.count("|") == 0 or all(s.split("|"))) + ) + + tags = "|".join([_.strip() for _ in tag.split("|")]) if tag else "" + channels = "|".join([_.strip() for _ in channel.split("|")]) if channel else "" + + options = {} + if is_valid(tags): + options["tags"] = tags + else: + logger.warning("单独通知-ServerChan Tag 格式不正确,已忽略") + + if is_valid(channels): + options["channel"] = channels + else: + logger.warning("单独通知-ServerChan Channel 格式不正确,已忽略") + + # 3. 构造 payload + payload = {"title": title, "desp": content, **options} + + headers = {"Content-Type": "application/json;charset=utf-8"} + logger.info(f"单独通知-发送 Server酱通知: {payload}") + + try: + response = requests.post(url, json=payload, headers=headers, timeout=10) + result = response.json() + + if result.get("code") == 0: + logger.success("Server酱通知推送成功") + else: + raise Exception( + f"推送失败,响应码:{result.get('code')}, 信息:{result}" + ) + except Exception as e: + raise Exception(f"Server酱推送失败: {e}") + def _send_webhook(self, title: str, content: str): """发送企业微信机器人通知""" + logger.debug("单独通知-开始发送企业微信机器人通知") import requests - import json - + url = self.config.get(self.config.Notify_CompanyWebHookBotUrl) data = { "msgtype": "markdown", @@ -429,10 +483,11 @@ class UserNotification: "content": f"### {title}\n{content}" } } - + response = requests.post(url, json=data) if response.status_code != 200: raise Exception(f"企业微信机器人API返回错误: {response.text}") - + logger.success("单独通知-企业微信机器人通知发送成功") + Notify = Notification() From a482087abdbc527fd62936b13bc57f519368054c Mon Sep 17 00:00:00 2001 From: DLmaster361 Date: Mon, 19 May 2025 16:54:14 +0800 Subject: [PATCH 03/10] =?UTF-8?q?feat(ui):=20=E5=88=9D=E6=AD=A5=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E7=94=A8=E6=88=B7=E9=80=9A=E7=9F=A5=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/core/config.py | 39 +++-- app/ui/Widget.py | 38 +++++ app/ui/member_manager.py | 332 ++++++++++++++++----------------------- 3 files changed, 198 insertions(+), 211 deletions(-) diff --git a/app/core/config.py b/app/core/config.py index 6a5fb17..3c5781c 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -234,10 +234,6 @@ class GlobalConfig(LQConfig): self.notify_CompanyWebHookBotUrl = ConfigItem( "Notify", "CompanyWebHookBotUrl", "" ) - self.notify_IfPushDeer = ConfigItem( - "Notify", "IfPushDeer", False, BoolValidator() - ) - self.notify_IfPushDeerKey = ConfigItem("Notify", "PushDeerKey", "") self.update_IfAutoUpdate = ConfigItem( "Update", "IfAutoUpdate", False, BoolValidator() @@ -440,18 +436,29 @@ class MaaUserConfig(LQConfig): ) # 新增用户单独通知字段 - self.Notify_Enable = ConfigItem("Notify_Enable", False, False) - self.Notify_IfSMTP = ConfigItem("Notify_IfSMTP", False, False) - self.Notify_SMTPServerAddress = ConfigItem("Notify_SMTPServerAddress", "", "") - self.Notify_AuthorizationCode = ConfigItem("Notify_AuthorizationCode", "", "") - self.Notify_FromAddress = ConfigItem("Notify_FromAddress", "", "") - self.Notify_ToAddress = ConfigItem("Notify_ToAddress", "", "") - self.Notify_IfServerChan = ConfigItem("Notify_IfServerChan", False, False) - self.Notify_ServerChanKey = ConfigItem("Notify_ServerChanKey", "", "") - self.Notify_ServerChanChannel = ConfigItem("Notify_ServerChanChannel", "", "") - self.Notify_ServerChanTag = ConfigItem("Notify_ServerChanTag", "", "") - self.Notify_IfCompanyWebHookBot = ConfigItem("Notify_IfCompanyWebHookBot", False, False) - self.Notify_CompanyWebHookBotUrl = ConfigItem("Notify_CompanyWebHookBotUrl", "", "") + self.Notify_Enabled = ConfigItem("Notify", "Enabled", False, BoolValidator()) + self.Notify_IfSendStatistic = ConfigItem( + "Notify", "IfSendStatistic", False, BoolValidator() + ) + self.Notify_IfSendSixStar = ConfigItem( + "Notify", "IfSendSixStar", False, BoolValidator() + ) + self.Notify_IfSendMail = ConfigItem( + "Notify", "IfSendMail", False, BoolValidator() + ) + self.Notify_ToAddress = ConfigItem("Notify", "ToAddress", "") + self.Notify_IfServerChan = ConfigItem( + "Notify", "IfServerChan", False, BoolValidator() + ) + self.Notify_ServerChanKey = ConfigItem("Notify", "ServerChanKey", "") + self.Notify_ServerChanChannel = ConfigItem("Notify", "ServerChanChannel", "") + self.Notify_ServerChanTag = ConfigItem("Notify", "ServerChanTag", "") + self.Notify_IfCompanyWebHookBot = ConfigItem( + "Notify", "IfCompanyWebHookBot", False, BoolValidator() + ) + self.Notify_CompanyWebHookBotUrl = ConfigItem( + "Notify", "CompanyWebHookBotUrl", "" + ) class MaaPlanConfig(LQConfig): diff --git a/app/ui/Widget.py b/app/ui/Widget.py index 55b3c1d..0e9de98 100644 --- a/app/ui/Widget.py +++ b/app/ui/Widget.py @@ -191,6 +191,44 @@ class ProgressRingMessageBox(MessageBoxBase): self.timer.deleteLater() +class SettingMessageBox(MessageBoxBase): + """设置二级菜单对话框""" + + def __init__( + self, + parent, + title: str, + setting_cards: List[Union[SettingCard, HeaderCardWidget]], + ): + super().__init__(parent) + + self.title = SubtitleLabel(title) + self.button_yes = PrimaryPushButton("确认", self) + self.v_layout = QVBoxLayout() + self.v_layout.addStretch() + self.v_layout.addWidget(self.button_yes) + + self.buttonGroup.hide() + + scrollArea = ScrollArea() + scrollArea.setWidgetResizable(True) + scrollArea.setContentsMargins(0, 0, 0, 0) + scrollArea.setStyleSheet("background: transparent; border: none;") + + content_widget = QWidget() + content_layout = QVBoxLayout(content_widget) + for setting_card in setting_cards: + content_layout.addWidget(setting_card) + scrollArea.setWidget(content_widget) + + # 将组件添加到布局中 + self.viewLayout.addWidget(self.title) + self.viewLayout.addWidget(scrollArea) + self.viewLayout.addLayout(self.v_layout) + + self.button_yes.clicked.connect(self.yesButton.click) + + class NoticeMessageBox(MessageBoxBase): """公告对话框""" diff --git a/app/ui/member_manager.py b/app/ui/member_manager.py index 71fc30f..f2f75e6 100644 --- a/app/ui/member_manager.py +++ b/app/ui/member_manager.py @@ -64,6 +64,7 @@ from .Widget import ( LineEditSettingCard, SpinBoxSettingCard, ComboBoxMessageBox, + SettingMessageBox, EditableComboBoxSettingCard, PasswordLineEditSettingCard, UserLableSettingCard, @@ -1530,138 +1531,32 @@ class MemberManager(QWidget): ) # 新增单独通知卡片 - self.card_NotifyEnable = SwitchSettingCard( - icon=FluentIcon.INFO, - title="启用单独通知", - content="启用后,任务结束将向该用户单独推送通知", + self.card_NotifySet = PushAndSwitchButtonSettingCard( + icon=FluentIcon.MAIL, + title="用户单独通知设置", + content="", + text="设置", qconfig=self.config, - configItem=self.config.Notify_Enable, - parent=self + configItem=self.config.Notify_Enabled, + parent=self, ) - self.card_NotifyIfSMTP = SwitchSettingCard( - icon=FluentIcon.INFO, - title="启用SMTP通知", - content="是否启用单独通知的SMTP邮件推送", - qconfig=self.config, - configItem=self.config.Notify_IfSMTP, - parent=self + self.card_EMail = self.EMailSettingCard(self.config, self) + self.card_ServerChan = self.ServerChanSettingCard( + self.config, self ) - self.card_NotifySMTP = LineEditSettingCard( - icon=FluentIcon.INFO, - title="SMTP服务器地址", - content="单独通知的SMTP服务器地址", - text="请输入SMTP服务器地址", - qconfig=self.config, - configItem=self.config.Notify_SMTPServerAddress, - parent=self - ) - self.card_NotifyAuthCode = PasswordLineEditSettingCard( - icon=FluentIcon.INFO, - title="授权码", - content="单独通知的邮箱授权码", - text="请输入授权码", - algorithm="AUTO", - qconfig=self.config, - configItem=self.config.Notify_AuthorizationCode, - parent=self - ) - self.card_NotifyFrom = LineEditSettingCard( - icon=FluentIcon.INFO, - title="发件人邮箱", - content="单独通知的发件人邮箱", - text="请输入发件人邮箱", - qconfig=self.config, - configItem=self.config.Notify_FromAddress, - parent=self - ) - self.card_NotifyTo = LineEditSettingCard( - icon=FluentIcon.INFO, - title="收件人邮箱", - content="单独通知的收件人邮箱", - text="请输入收件人邮箱", - qconfig=self.config, - configItem=self.config.Notify_ToAddress, - parent=self - ) - self.card_NotifyIfServerChan = SwitchSettingCard( - icon=FluentIcon.INFO, - title="启用ServerChan", - content="是否启用单独通知的ServerChan推送", - qconfig=self.config, - configItem=self.config.Notify_IfServerChan, - parent=self - ) - self.card_NotifyServerChanKey = LineEditSettingCard( - icon=FluentIcon.INFO, - title="ServerChanKey", - content="单独通知的ServerChan SendKey", - text="请输入ServerChanKey", - qconfig=self.config, - configItem=self.config.Notify_ServerChanKey, - parent=self - ) - self.card_NotifyServerChanChannel = LineEditSettingCard( - icon=FluentIcon.INFO, - title="ServerChanChannel", - content="单独通知的ServerChan Channel", - text="请输入ServerChanChannel", - qconfig=self.config, - configItem=self.config.Notify_ServerChanChannel, - parent=self - ) - self.card_NotifyServerChanTag = LineEditSettingCard( - icon=FluentIcon.INFO, - title="ServerChanTag", - content="单独通知的ServerChan Tag", - text="请输入ServerChanTag", - qconfig=self.config, - configItem=self.config.Notify_ServerChanTag, - parent=self - ) - self.card_NotifyIfCompanyWebHookBot = SwitchSettingCard( - icon=FluentIcon.INFO, - title="启用企业微信机器人", - content="是否启用单独通知的企业微信机器人推送", - qconfig=self.config, - configItem=self.config.Notify_IfCompanyWebHookBot, - parent=self - ) - self.card_NotifyCompanyWebHookBotUrl = LineEditSettingCard( - icon=FluentIcon.INFO, - title="企业微信机器人WebhookUrl", - content="单独通知的企业微信机器人Webhook地址", - text="请输入WebhookUrl", - qconfig=self.config, - configItem=self.config.Notify_CompanyWebHookBotUrl, - parent=self + self.card_CompanyWebhookBot = ( + self.CompanyWechatPushSettingCard(self.config, self) ) - # 设置通知卡片默认隐藏 - self.card_NotifyIfSMTP.setVisible(False) - self.card_NotifySMTP.setVisible(False) - self.card_NotifyAuthCode.setVisible(False) - self.card_NotifyFrom.setVisible(False) - self.card_NotifyTo.setVisible(False) - self.card_NotifyIfServerChan.setVisible(False) - self.card_NotifyServerChanKey.setVisible(False) - self.card_NotifyServerChanChannel.setVisible(False) - self.card_NotifyServerChanTag.setVisible(False) - self.card_NotifyIfCompanyWebHookBot.setVisible(False) - self.card_NotifyCompanyWebHookBotUrl.setVisible(False) + self.card_NotifySet_list = [ + self.card_EMail, + self.card_ServerChan, + self.card_CompanyWebhookBot, + ] - # 连接通知启用开关的信号 - self.card_NotifyEnable.checkedChanged.connect(self.toggle_notify_settings) - self.card_NotifyIfSMTP.checkedChanged.connect(self.toggle_smtp_settings) - - # 根据配置状态初始化显示 - if self.config.get(self.config.Notify_Enable): - self.toggle_notify_settings(True) - if self.config.get(self.config.Notify_IfSMTP): - self.toggle_smtp_settings(True) - if self.config.get(self.config.Notify_IfServerChan): - self.toggle_serverchan_settings(True) - if self.config.get(self.config.Notify_IfCompanyWebHookBot): - self.toggle_webhook_settings(True) + self.NotifySetCard = SettingMessageBox( + self.window(), "用户通知设置", self.card_NotifySet_list + ) h1_layout = QHBoxLayout() h1_layout.addWidget(self.card_Name) @@ -1700,27 +1595,7 @@ class MemberManager(QWidget): Layout.addLayout(h6_layout) Layout.addLayout(h7_layout) Layout.addLayout(h8_layout) - - # 创建通知设置容器 - notify_container = QWidget() - notify_layout = QVBoxLayout(notify_container) - notify_layout.setContentsMargins(0, 0, 0, 0) - notify_layout.setSpacing(0) - - notify_layout.addWidget(self.card_NotifyEnable) - notify_layout.addWidget(self.card_NotifyIfSMTP) - notify_layout.addWidget(self.card_NotifySMTP) - notify_layout.addWidget(self.card_NotifyAuthCode) - notify_layout.addWidget(self.card_NotifyFrom) - notify_layout.addWidget(self.card_NotifyTo) - notify_layout.addWidget(self.card_NotifyIfServerChan) - notify_layout.addWidget(self.card_NotifyServerChanKey) - notify_layout.addWidget(self.card_NotifyServerChanChannel) - notify_layout.addWidget(self.card_NotifyServerChanTag) - notify_layout.addWidget(self.card_NotifyIfCompanyWebHookBot) - notify_layout.addWidget(self.card_NotifyCompanyWebHookBotUrl) - - Layout.addWidget(notify_container) + Layout.addWidget(self.card_NotifySet) self.viewLayout.addLayout(Layout) self.viewLayout.setContentsMargins(3, 0, 3, 3) @@ -1740,17 +1615,12 @@ class MemberManager(QWidget): self.card_InfrastMode.clicked.connect( self.set_infrastructure ) + self.card_NotifySet.clicked.connect( + self.NotifySetCard.exec_ + ) Config.gameid_refreshed.connect(self.refresh_gameid) Config.PASSWORD_refreshed.connect(self.refresh_password) - # 连接ServerChan和企业微信机器人的开关信号 - self.card_NotifyIfServerChan.checkedChanged.connect( - lambda checked: self.toggle_serverchan_settings(checked) - ) - self.card_NotifyIfCompanyWebHookBot.checkedChanged.connect( - lambda checked: self.toggle_webhook_settings(checked) - ) - self.switch_mode() self.switch_infrastructure() @@ -1873,46 +1743,118 @@ class MemberManager(QWidget): }, ) - def toggle_notify_settings(self, checked: bool): - """切换通知设置卡片的显示状态""" - self.card_NotifyIfSMTP.setVisible(checked) - self.card_NotifyIfServerChan.setVisible(checked) - self.card_NotifyIfCompanyWebHookBot.setVisible(checked) - - # 根据SMTP开关状态控制相关设置 - if checked and self.config.get(self.config.Notify_IfSMTP): - self.toggle_smtp_settings(True) - else: - self.toggle_smtp_settings(False) - - # 根据ServerChan开关状态控制相关设置 - if checked and self.config.get(self.config.Notify_IfServerChan): - self.toggle_serverchan_settings(True) - else: - self.toggle_serverchan_settings(False) - - # 根据企业微信机器人开关状态控制相关设置 - if checked and self.config.get(self.config.Notify_IfCompanyWebHookBot): - self.toggle_webhook_settings(True) - else: - self.toggle_webhook_settings(False) + class EMailSettingCard(HeaderCardWidget): - def toggle_smtp_settings(self, checked: bool): - """切换SMTP相关设置的显示状态""" - if self.config.get(self.config.Notify_Enable): - self.card_NotifySMTP.setVisible(checked) - self.card_NotifyAuthCode.setVisible(checked) - self.card_NotifyFrom.setVisible(checked) - self.card_NotifyTo.setVisible(checked) + def __init__(self, config: MaaUserConfig, parent=None): + super().__init__(parent) + self.setTitle("用户邮箱通知") - def toggle_serverchan_settings(self, checked: bool): - """切换ServerChan相关设置的显示状态""" - if self.config.get(self.config.Notify_Enable): - self.card_NotifyServerChanKey.setVisible(checked) - self.card_NotifyServerChanChannel.setVisible(checked) - self.card_NotifyServerChanTag.setVisible(checked) + self.config = config - def toggle_webhook_settings(self, checked: bool): - """切换企业微信机器人相关设置的显示状态""" - if self.config.get(self.config.Notify_Enable): - self.card_NotifyCompanyWebHookBotUrl.setVisible(checked) + self.card_IfSendMail = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="推送用户邮件通知", + content="是否启用用户邮件通知功能", + qconfig=self.config, + configItem=self.config.Notify_IfSendMail, + parent=self, + ) + self.card_ToAddress = LineEditSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="用户收信邮箱地址", + content="接收用户通知的邮箱地址", + text="请输入用户收信邮箱地址", + qconfig=self.config, + configItem=self.config.Notify_ToAddress, + parent=self, + ) + + Layout = QVBoxLayout() + Layout.addWidget(self.card_IfSendMail) + Layout.addWidget(self.card_ToAddress) + self.viewLayout.addLayout(Layout) + self.viewLayout.setContentsMargins(3, 0, 3, 3) + + class ServerChanSettingCard(HeaderCardWidget): + + def __init__(self, config: MaaUserConfig, parent=None): + super().__init__(parent) + self.setTitle("用户ServerChan通知") + + self.config = config + + self.card_IfServerChan = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="推送用户Server酱通知", + content="是否启用用户Server酱通知功能", + qconfig=self.config, + configItem=self.config.Notify_IfServerChan, + parent=self, + ) + self.card_ServerChanKey = LineEditSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="用户SendKey", + content="SC3与SCT均须填写", + text="请输入用户SendKey", + qconfig=self.config, + configItem=self.config.Notify_ServerChanKey, + parent=self, + ) + self.card_ServerChanChannel = LineEditSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="用户ServerChanChannel代码", + content="留空则默认,多个请使用“|”隔开", + text="请输入Channel代码,仅SCT生效", + qconfig=self.config, + configItem=self.config.Notify_ServerChanChannel, + parent=self, + ) + self.card_ServerChanTag = LineEditSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="用户Tag内容", + content="留空则默认,多个请使用“|”隔开", + text="请输入加入推送的Tag,仅SC3生效", + qconfig=self.config, + configItem=self.config.Notify_ServerChanTag, + parent=self, + ) + + Layout = QVBoxLayout() + Layout.addWidget(self.card_IfServerChan) + Layout.addWidget(self.card_ServerChanKey) + Layout.addWidget(self.card_ServerChanChannel) + Layout.addWidget(self.card_ServerChanTag) + self.viewLayout.addLayout(Layout) + self.viewLayout.setContentsMargins(3, 0, 3, 3) + + class CompanyWechatPushSettingCard(HeaderCardWidget): + + def __init__(self, config: MaaUserConfig, parent=None): + super().__init__(parent) + self.setTitle("用户企业微信推送") + + self.config = config + + self.card_IfCompanyWechat = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="推送用户企业微信机器人通知", + content="是否启用用户企微机器人通知功能", + qconfig=self.config, + configItem=self.config.Notify_IfCompanyWebHookBot, + parent=self, + ) + self.card_CompanyWebHookBotUrl = LineEditSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="WebhookUrl", + content="用户企微群机器人Webhook地址", + text="请输入用户Webhook的Url", + qconfig=self.config, + configItem=self.config.Notify_CompanyWebHookBotUrl, + parent=self, + ) + + Layout = QVBoxLayout() + Layout.addWidget(self.card_IfCompanyWechat) + Layout.addWidget(self.card_CompanyWebHookBotUrl) + self.viewLayout.addLayout(Layout) + self.viewLayout.setContentsMargins(3, 0, 3, 3) From 1641e32e3dcdfb93c8b302ba3bc71b77260a6a8d Mon Sep 17 00:00:00 2001 From: DLmaster361 Date: Mon, 19 May 2025 17:31:50 +0800 Subject: [PATCH 04/10] =?UTF-8?q?feat(ui):=20=E5=AE=8C=E6=88=90=E5=AE=8C?= =?UTF-8?q?=E6=95=B4=E7=94=A8=E6=88=B7=E9=80=9A=E7=9F=A5=E5=AD=90=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ui/member_manager.py | 81 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/app/ui/member_manager.py b/app/ui/member_manager.py index f2f75e6..b8378e9 100644 --- a/app/ui/member_manager.py +++ b/app/ui/member_manager.py @@ -1534,12 +1534,15 @@ class MemberManager(QWidget): self.card_NotifySet = PushAndSwitchButtonSettingCard( icon=FluentIcon.MAIL, title="用户单独通知设置", - content="", + content="未启用任何通知项", text="设置", qconfig=self.config, configItem=self.config.Notify_Enabled, parent=self, ) + self.card_NotifyContent = self.NotifyContentSettingCard( + self.config, self + ) self.card_EMail = self.EMailSettingCard(self.config, self) self.card_ServerChan = self.ServerChanSettingCard( self.config, self @@ -1549,6 +1552,7 @@ class MemberManager(QWidget): ) self.card_NotifySet_list = [ + self.card_NotifyContent, self.card_EMail, self.card_ServerChan, self.card_CompanyWebhookBot, @@ -1615,14 +1619,13 @@ class MemberManager(QWidget): self.card_InfrastMode.clicked.connect( self.set_infrastructure ) - self.card_NotifySet.clicked.connect( - self.NotifySetCard.exec_ - ) + self.card_NotifySet.clicked.connect(self.set_notify) Config.gameid_refreshed.connect(self.refresh_gameid) Config.PASSWORD_refreshed.connect(self.refresh_password) self.switch_mode() self.switch_infrastructure() + self.set_notify(if_show=False) def switch_mode(self) -> None: @@ -1743,6 +1746,76 @@ class MemberManager(QWidget): }, ) + def set_notify(self, if_show: bool = True) -> None: + """设置用户通知相关配置""" + + def short_str(s: str) -> str: + if len(s) <= 10: + return s + return s[:7] + "..." + + if if_show: + self.NotifySetCard.exec_() + + content_list = [] + + if not ( + self.config.get(self.config.Notify_IfSendStatistic) + or self.config.get(self.config.Notify_IfSendSixStar) + ): + content_list.append("未启用任何通知项") + + if self.config.get(self.config.Notify_IfSendStatistic): + content_list.append("统计信息已启用") + if self.config.get(self.config.Notify_IfSendSixStar): + content_list.append("六星喜报已启用") + + if self.config.get(self.config.Notify_IfSendMail): + content_list.append( + f"邮箱通知:{short_str(self.config.get(self.config.Notify_ToAddress))}" + ) + if self.config.get(self.config.Notify_IfServerChan): + content_list.append( + f"Server酱通知:{short_str(self.config.get(self.config.Notify_ServerChanKey))}" + ) + if self.config.get(self.config.Notify_IfCompanyWebHookBot): + content_list.append( + f"企业微信通知:{short_str(self.config.get(self.config.Notify_CompanyWebHookBotUrl))}" + ) + + self.card_NotifySet.setContent(" | ".join(content_list)) + + class NotifyContentSettingCard(HeaderCardWidget): + + def __init__(self, config: MaaUserConfig, parent=None): + super().__init__(parent) + self.setTitle("用户通知内容选项") + + self.config = config + + self.card_IfSendStatistic = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="推送统计信息", + content="推送自动代理统计信息的通知", + qconfig=self.config, + configItem=self.config.Notify_IfSendStatistic, + parent=self, + ) + self.card_IfSendSixStar = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="推送公招高资喜报", + content="公招出现六星词条时推送喜报", + qconfig=self.config, + configItem=self.config.Notify_IfSendSixStar, + parent=self, + ) + + Layout = QVBoxLayout() + Layout.addWidget(self.card_IfSendStatistic) + Layout.addWidget(self.card_IfSendSixStar) + self.viewLayout.addLayout(Layout) + self.viewLayout.setContentsMargins(3, 0, 3, 3) + class EMailSettingCard(HeaderCardWidget): def __init__(self, config: MaaUserConfig, parent=None): From 59ff9bf818865edd027c208029f4e08759d8b9fb Mon Sep 17 00:00:00 2001 From: aoxuan Date: Tue, 20 May 2025 02:11:54 +0800 Subject: [PATCH 05/10] =?UTF-8?q?refactor(notification):=20=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E9=80=9A=E7=9F=A5=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/MAA.py | 82 +++++++------- app/services/notification.py | 211 ++++------------------------------- 2 files changed, 63 insertions(+), 230 deletions(-) diff --git a/app/models/MAA.py b/app/models/MAA.py index e03c18b..a2bd23e 100644 --- a/app/models/MAA.py +++ b/app/models/MAA.py @@ -40,7 +40,6 @@ from typing import Union, List, Dict from app.core import Config, MaaConfig, MaaUserConfig from app.services import Notify, System -from app.services.notification import Notification, UserNotification class MaaManager(QObject): @@ -1773,21 +1772,22 @@ class MaaManager(QObject): message_html = template.render(message) # 发送全局通知 - Notify.send_mail("网页", title, message_html) - Notify.ServerChanPush(title, f"{message_text}\n\nAUTO_MAA 敬上") - Notify.CompanyWebHookBotPush(title, f"{message_text}\n\nAUTO_MAA 敬上") + Notify.send_mail("网页", title, message_html,Config.get(Config.notify_ToAddress)) + serverchan_message = message_text.replace("\n", "\n\n") + Notify.ServerChanPush(title, f"{serverchan_message}\n\nAUTO_MAA 敬上",Config.get(Config.notify_ServerChanKey),Config.get(Config.notify_ServerChanTag),Config.get(Config.notify_ServerChanChannel)) + Notify.CompanyWebHookBotPush(title, f"{message_text}\n\nAUTO_MAA 敬上",Config.get(Config.notify_CompanyWebHookBotUrl)) - # 发送用户单独通知 - for user_name in message["failed_user"].split("、") + message["waiting_user"].split("、"): - if not user_name: # 跳过空字符串 - continue - user_config = Config.member_dict.get(user_name) - if user_config and user_config.get(user_config.Notify_Enable): - user_notify = UserNotification(user_config) - user_notify.send_notification( - f"{self.mode[2:4]}任务未完成通知", - f"您的{self.mode[2:4]}任务未完成,请检查相关设置。\n\n{message_text}" - ) + # # 发送用户单独通知 + # for user_name in message["failed_user"].split("、") + message["waiting_user"].split("、"): + # if not user_name: # 跳过空字符串 + # continue + # user_config = Config.member_dict.get(user_name) + # if user_config and user_config.get(user_config.Notify_Enable): + # user_notify = UserNotification(user_config) + # user_notify.send_notification( + # f"{self.mode[2:4]}任务未完成通知", + # f"您的{self.mode[2:4]}任务未完成,请检查相关设置。\n\n{message_text}" + # ) return message_text @@ -1818,22 +1818,22 @@ class MaaManager(QObject): message_html = template.render(message) # 发送全局通知 - Notify.send_mail("网页", title, message_html) + Notify.send_mail("网页", title, message_html,Config.get(Config.notify_ToAddress)) # ServerChan的换行是两个换行符。故而将\n替换为\n\n serverchan_message = message_text.replace("\n", "\n\n") - Notify.ServerChanPush(title, f"{serverchan_message}\n\nAUTO_MAA 敬上") - Notify.CompanyWebHookBotPush(title, f"{message_text}\n\nAUTO_MAA 敬上") + Notify.ServerChanPush(title, f"{serverchan_message}\n\nAUTO_MAA 敬上",Config.get(Config.notify_ServerChanKey),Config.get(Config.notify_ServerChanTag),Config.get(Config.notify_ServerChanChannel)) + Notify.CompanyWebHookBotPush(title, f"{message_text}\n\nAUTO_MAA 敬上",Config.get(Config.notify_CompanyWebHookBotUrl)) - # 发送用户单独通知 - user_name = message.get("user_info") - if user_name: - user_config = Config.member_dict.get(user_name) - if user_config and user_config.get(user_config.Notify_Enable): - user_notify = UserNotification(user_config) - user_notify.send_notification( - f"{self.mode[2:4]}任务统计报告", - f"您的{self.mode[2:4]}任务统计报告如下:\n\n{message_text}" - ) + # # 发送用户单独通知 + # user_name = message.get("user_info") + # if user_name: + # user_config = Config.member_dict.get(user_name) + # if user_config and user_config.get(user_config.Notify_Enable): + # user_notify = UserNotification(user_config) + # user_notify.send_notification( + # f"{self.mode[2:4]}任务统计报告", + # f"您的{self.mode[2:4]}任务统计报告如下:\n\n{message_text}" + # ) elif mode == "公招六星": # 生成HTML通知内容 @@ -1841,17 +1841,17 @@ class MaaManager(QObject): message_html = template.render(message) # 发送全局通知 - Notify.send_mail("网页", title, message_html) - Notify.ServerChanPush(title, "好羡慕~\n\nAUTO_MAA 敬上") - Notify.CompanyWebHookBotPush(title, "好羡慕~\n\nAUTO_MAA 敬上") + Notify.send_mail("网页", title, message_html,Config.get(Config.notify_ToAddress)) + Notify.ServerChanPush(title, "好羡慕~\n\nAUTO_MAA 敬上",Config.get(Config.notify_ServerChanKey),Config.get(Config.notify_ServerChanTag),Config.get(Config.notify_ServerChanChannel)) + Notify.CompanyWebHookBotPush(title, "好羡慕~\n\nAUTO_MAA 敬上",Config.get(Config.notify_CompanyWebHookBotUrl)) - # 发送用户单独通知 - user_name = message.get("user_name") - if user_name: - user_config = Config.member_dict.get(user_name) - if user_config and user_config.get(user_config.Notify_Enable): - user_notify = UserNotification(user_config) - user_notify.send_notification( - "公招六星通知", - "恭喜您在公招中获得了六星干员!" - ) + # # 发送用户单独通知 + # user_name = message.get("user_name") + # if user_name: + # user_config = Config.member_dict.get(user_name) + # if user_config and user_config.get(user_config.Notify_Enable): + # user_notify = UserNotification(user_config) + # user_notify.send_notification( + # "公招六星通知", + # "恭喜您在公招中获得了六星干员!" + # ) diff --git a/app/services/notification.py b/app/services/notification.py index d5514c1..639e3ac 100644 --- a/app/services/notification.py +++ b/app/services/notification.py @@ -67,7 +67,7 @@ class Notification(QWidget): return True - def send_mail(self, mode, title, content) -> None: + def send_mail(self, mode, title, content, to_address) -> None: """推送邮件通知""" if Config.get(Config.notify_IfSendMail): @@ -84,7 +84,7 @@ class Notification(QWidget): or not bool( re.match( r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", - Config.get(Config.notify_ToAddress), + to_address, ) ) ): @@ -114,7 +114,7 @@ class Notification(QWidget): message["To"] = formataddr( ( Header("AUTO_MAA用户", "utf-8").encode(), - Config.get(Config.notify_ToAddress), + to_address, ) ) # 收件人显示的名字 message["Subject"] = Header(title, "utf-8") @@ -132,20 +132,21 @@ class Notification(QWidget): ) smtpObj.sendmail( Config.get(Config.notify_FromAddress), - Config.get(Config.notify_ToAddress), + to_address, message.as_string(), ) smtpObj.quit() logger.success("邮件发送成功") + return None except Exception as e: logger.error(f"发送邮件时出错:\n{e}") self.push_info_bar.emit("error", "发送邮件时出错", f"{e}", -1) + return None + return None - def ServerChanPush(self, title, content): - """使用Server酱推送通知(支持 tag 和 channel,避免使用SDK)""" + def ServerChanPush(self, title, content, send_key, tag, channel): + """使用Server酱推送通知""" if Config.get(Config.notify_IfServerChan): - send_key = Config.get(Config.notify_ServerChanKey) - if not send_key: logger.error("请正确设置Server酱的SendKey") self.push_info_bar.emit( @@ -173,11 +174,11 @@ class Notification(QWidget): tags = "|".join( _.strip() - for _ in Config.get(Config.notify_ServerChanTag).split("|") + for _ in tag.split("|") ) channels = "|".join( _.strip() - for _ in Config.get(Config.notify_ServerChanChannel).split("|") + for _ in channel.split("|") ) options = {} @@ -227,12 +228,13 @@ class Notification(QWidget): "error", "Server酱通知推送异常", f"请检查相关设置,如还有问题可联系开发者", -1 ) return f"Server酱通知推送异常:{str(e)}" + return None - def CompanyWebHookBotPush(self, title, content): + def CompanyWebHookBotPush(self, title, content,webhook_url): """使用企业微信群机器人推送通知""" if Config.get(Config.notify_IfCompanyWebHookBot): - if Config.get(Config.notify_CompanyWebHookBotUrl) == "": + if webhook_url == "": logger.error("请正确设置企业微信群机器人的WebHook地址") self.push_info_bar.emit( "error", @@ -244,11 +246,11 @@ class Notification(QWidget): content = f"{title}\n{content}" data = {"msgtype": "text", "text": {"content": content}} - # 从远程服务器获取最新主题图像 + for _ in range(3): try: response = requests.post( - url=Config.get(Config.notify_CompanyWebHookBotUrl), + url=webhook_url, json=data, timeout=10, ) @@ -279,6 +281,7 @@ class Notification(QWidget): -1, ) return f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}' + return None def send_test_notification(self): """发送测试通知到所有已启用的通知渠道""" @@ -296,6 +299,7 @@ class Notification(QWidget): "文本", "AUTO_MAA测试通知", "这是 AUTO_MAA 外部通知测试信息。如果你看到了这段内容,说明 AUTO_MAA 的通知功能已经正确配置且可以正常工作!", + Config.get(Config.notify_ToAddress), ) # 发送Server酱通知 @@ -303,6 +307,9 @@ class Notification(QWidget): self.ServerChanPush( "AUTO_MAA测试通知", "这是 AUTO_MAA 外部通知测试信息。如果你看到了这段内容,说明 AUTO_MAA 的通知功能已经正确配置且可以正常工作!", + Config.get(Config.notify_ServerChanKey), + Config.get(Config.notify_ServerChanTag), + Config.get(Config.notify_ServerChanChannel), ) # 发送企业微信机器人通知 @@ -310,184 +317,10 @@ class Notification(QWidget): self.CompanyWebHookBotPush( "AUTO_MAA测试通知", "这是 AUTO_MAA 外部通知测试信息。如果你看到了这段内容,说明 AUTO_MAA 的通知功能已经正确配置且可以正常工作!", + Config.get(Config.notify_CompanyWebHookBotUrl), ) return True -class UserNotification: - """用户单独通知服务""" - - def __init__(self, user_config): - self.config = user_config - - def send_notification(self, title: str, content: str) -> bool: - """发送用户通知""" - logger.info(f"单独通知-准备发送用户通知,标题: {title}") - - if not self.config.get(self.config.Notify_Enable): - logger.warning("单独通知-用户通知功能未启用,跳过发送") - return False - - success = False - - # 邮件通知 - if self._check_smtp_config(): - try: - self._send_email(title, content) - success = True - except Exception as e: - logger.error(f"单独通知-发送邮件通知失败: {str(e)}") - - # Server酱通知 - if ( - self.config.get(self.config.Notify_IfServerChan) - and self._check_serverchan_config() - ): - try: - self._send_serverchan(title, content) - success = True - except Exception as e: - logger.error(f"单独通知-发送 Server酱 通知失败: {str(e)}") - - # 企业微信群机器人 - if ( - self.config.get(self.config.Notify_IfCompanyWebHookBot) - and self._check_webhook_config() - ): - try: - self._send_webhook(title, content) - success = True - except Exception as e: - logger.error(f"单独通知-发送企业微信机器人通知失败: {str(e)}") - - if success: - logger.info("单独通知-用户通知发送完成") - else: - logger.warning("单独通知-所有通知方式均发送失败") - - return success - - def _check_smtp_config(self) -> bool: - """检查SMTP配置是否完整""" - return all([ - self.config.get(self.config.Notify_IfSMTP), - self.config.get(self.config.Notify_SMTPServerAddress), - self.config.get(self.config.Notify_AuthorizationCode), - self.config.get(self.config.Notify_FromAddress), - self.config.get(self.config.Notify_ToAddress) - ]) - - def _check_serverchan_config(self) -> bool: - """检查ServerChan配置是否完整""" - return bool(self.config.get(self.config.Notify_ServerChanKey)) - - def _check_webhook_config(self) -> bool: - """检查企业微信机器人配置是否完整""" - return bool(self.config.get(self.config.Notify_CompanyWebHookBotUrl)) - - def _send_email(self, title: str, content: str): - """发送邮件通知""" - logger.debug("单独通知-开始发送邮件通知") - import smtplib - from email.mime.text import MIMEText - from email.header import Header - - msg = MIMEText(content, 'plain', 'utf-8') - msg['Subject'] = Header(title, 'utf-8') - msg['From'] = self.config.get(self.config.Notify_FromAddress) - msg['To'] = self.config.get(self.config.Notify_ToAddress) - - server = smtplib.SMTP_SSL(self.config.get(self.config.Notify_SMTPServerAddress)) - server.login( - self.config.get(self.config.Notify_FromAddress), - self.config.get(self.config.Notify_AuthorizationCode) - ) - server.send_message(msg) - server.quit() - logger.success("单独通知-邮件通知发送成功") - - def _send_serverchan(self, title: str, content: str): - """发送 ServerChan 通知,支持 SCT、SC3、自定义域名等""" - logger.debug("单独通知-开始发送 ServerChan 通知") - import requests - import re - - key = self.config.get(self.config.Notify_ServerChanKey) - tag = self.config.get(self.config.Notify_ServerChanTag) - channel = self.config.get(self.config.Notify_ServerChanChannel) - - if not key: - raise Exception("ServerChan SendKey 未设置") - - # 1. 构造 URL(支持 sctpN 和 sct 开头的) - if key.startswith("sctp"): - match = re.match(r"^sctp(\d+)t", key) - if match: - url = f"https://{match.group(1)}.push.ft07.com/send/{key}.send" - else: - raise ValueError("SendKey 格式错误,sctp 开头但不符合规范") - else: - url = f"https://sctapi.ftqq.com/{key}.send" - - logger.debug(f"单独通知-Server酱推送URL: {url}") - - # 2. 校验 tag 和 channel 格式 - def is_valid(s): - return s == "" or ( - s == "|".join(s.split("|")) and (s.count("|") == 0 or all(s.split("|"))) - ) - - tags = "|".join([_.strip() for _ in tag.split("|")]) if tag else "" - channels = "|".join([_.strip() for _ in channel.split("|")]) if channel else "" - - options = {} - if is_valid(tags): - options["tags"] = tags - else: - logger.warning("单独通知-ServerChan Tag 格式不正确,已忽略") - - if is_valid(channels): - options["channel"] = channels - else: - logger.warning("单独通知-ServerChan Channel 格式不正确,已忽略") - - # 3. 构造 payload - payload = {"title": title, "desp": content, **options} - - headers = {"Content-Type": "application/json;charset=utf-8"} - logger.info(f"单独通知-发送 Server酱通知: {payload}") - - try: - response = requests.post(url, json=payload, headers=headers, timeout=10) - result = response.json() - - if result.get("code") == 0: - logger.success("Server酱通知推送成功") - else: - raise Exception( - f"推送失败,响应码:{result.get('code')}, 信息:{result}" - ) - except Exception as e: - raise Exception(f"Server酱推送失败: {e}") - - def _send_webhook(self, title: str, content: str): - """发送企业微信机器人通知""" - logger.debug("单独通知-开始发送企业微信机器人通知") - import requests - - url = self.config.get(self.config.Notify_CompanyWebHookBotUrl) - data = { - "msgtype": "markdown", - "markdown": { - "content": f"### {title}\n{content}" - } - } - - response = requests.post(url, json=data) - if response.status_code != 200: - raise Exception(f"企业微信机器人API返回错误: {response.text}") - logger.success("单独通知-企业微信机器人通知发送成功") - - Notify = Notification() From 86df9e7a50a44001027cc0cbbd65bff5e992fec8 Mon Sep 17 00:00:00 2001 From: DLmaster361 Date: Wed, 21 May 2025 01:00:38 +0800 Subject: [PATCH 06/10] =?UTF-8?q?chore(ui):=20=E4=BC=98=E5=8C=96=E4=BA=8C?= =?UTF-8?q?=E7=BA=A7=E8=8F=9C=E5=8D=95=E6=98=BE=E7=A4=BA=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ui/Widget.py | 138 +++++++++++++++++++++++++++----------- app/ui/dispatch_center.py | 22 +++--- app/ui/history.py | 11 +-- app/ui/home.py | 22 +++--- app/ui/member_manager.py | 100 ++++++++++++--------------- app/ui/queue_manager.py | 20 +++--- app/ui/setting.py | 10 +-- 7 files changed, 182 insertions(+), 141 deletions(-) diff --git a/app/ui/Widget.py b/app/ui/Widget.py index 0e9de98..4aa98be 100644 --- a/app/ui/Widget.py +++ b/app/ui/Widget.py @@ -74,6 +74,7 @@ from qfluentwidgets import ( ScrollArea, Pivot, PivotItem, + FlyoutViewBase, ) from qfluentwidgets.common.overload import singledispatchmethod import os @@ -191,44 +192,6 @@ class ProgressRingMessageBox(MessageBoxBase): self.timer.deleteLater() -class SettingMessageBox(MessageBoxBase): - """设置二级菜单对话框""" - - def __init__( - self, - parent, - title: str, - setting_cards: List[Union[SettingCard, HeaderCardWidget]], - ): - super().__init__(parent) - - self.title = SubtitleLabel(title) - self.button_yes = PrimaryPushButton("确认", self) - self.v_layout = QVBoxLayout() - self.v_layout.addStretch() - self.v_layout.addWidget(self.button_yes) - - self.buttonGroup.hide() - - scrollArea = ScrollArea() - scrollArea.setWidgetResizable(True) - scrollArea.setContentsMargins(0, 0, 0, 0) - scrollArea.setStyleSheet("background: transparent; border: none;") - - content_widget = QWidget() - content_layout = QVBoxLayout(content_widget) - for setting_card in setting_cards: - content_layout.addWidget(setting_card) - scrollArea.setWidget(content_widget) - - # 将组件添加到布局中 - self.viewLayout.addWidget(self.title) - self.viewLayout.addWidget(scrollArea) - self.viewLayout.addLayout(self.v_layout) - - self.button_yes.clicked.connect(self.yesButton.click) - - class NoticeMessageBox(MessageBoxBase): """公告对话框""" @@ -309,6 +272,39 @@ class NoticeMessageBox(MessageBoxBase): self.Layout.addStretch(1) +class SettingFlyoutView(FlyoutViewBase): + """设置卡二级菜单弹出组件""" + + def __init__( + self, + parent, + title: str, + setting_cards: List[Union[SettingCard, HeaderCardWidget]], + ): + super().__init__(parent) + + self.title = SubtitleLabel(title) + + content_widget = QWidget() + content_layout = QVBoxLayout(content_widget) + content_layout.setSpacing(0) + content_layout.setContentsMargins(0, 0, 11, 0) + for setting_card in setting_cards: + content_layout.addWidget(setting_card) + + scrollArea = ScrollArea() + scrollArea.setWidgetResizable(True) + scrollArea.setContentsMargins(0, 0, 0, 0) + scrollArea.setStyleSheet("background: transparent; border: none;") + scrollArea.setWidget(content_widget) + + self.viewLayout = QVBoxLayout(self) + self.viewLayout.setSpacing(12) + self.viewLayout.setContentsMargins(20, 16, 9, 16) + self.viewLayout.addWidget(self.title) + self.viewLayout.addWidget(scrollArea) + + class SwitchSettingCard(SettingCard): """Setting card with switch button""" @@ -971,6 +967,72 @@ class TimeEditSettingCard(SettingCard): self.TimeEdit.setTime(QTime.fromString(value, "HH:mm")) +class UserNoticeSettingCard(PushAndSwitchButtonSettingCard): + """Setting card with User's Notice""" + + def __init__( + self, + icon: Union[str, QIcon, FluentIconBase], + title: str, + content: Union[str, None], + text: str, + qconfig: QConfig, + configItem: ConfigItem, + configItems: Dict[str, ConfigItem], + parent=None, + ): + + super().__init__(icon, title, content, text, qconfig, configItem, parent) + self.qconfig = qconfig + self.configItems = configItems + self.Lable = SubtitleLabel(self) + + if configItems: + for config_item in configItems.values(): + config_item.valueChanged.connect(self.setValues) + self.setValues() + + self.hBoxLayout.addWidget(self.Lable, 0, Qt.AlignRight) + self.hBoxLayout.addSpacing(16) + + def setValues(self): + + def short_str(s: str) -> str: + if len(s) <= 10: + return s + return s[:10] + "..." + + content_list = [] + + if self.configItems: + + if not ( + self.qconfig.get(self.configItems["IfSendStatistic"]) + or self.qconfig.get(self.configItems["IfSendSixStar"]) + ): + content_list.append("未启用任何通知项") + + if self.qconfig.get(self.configItems["IfSendStatistic"]): + content_list.append("统计信息已启用") + if self.qconfig.get(self.configItems["IfSendSixStar"]): + content_list.append("六星喜报已启用") + + if self.qconfig.get(self.configItems["IfSendMail"]): + content_list.append( + f"邮箱通知:{short_str(self.qconfig.get(self.configItems["ToAddress"]))}" + ) + if self.qconfig.get(self.configItems["IfServerChan"]): + content_list.append( + f"Server酱通知:{short_str(self.qconfig.get(self.configItems["ServerChanKey"]))}" + ) + if self.qconfig.get(self.configItems["IfCompanyWebHookBot"]): + content_list.append( + f"企业微信通知:{short_str(self.qconfig.get(self.configItems["CompanyWebHookBotUrl"]))}" + ) + + self.setContent(" | ".join(content_list)) + + class StatusSwitchSetting(SwitchButton): def __init__( diff --git a/app/ui/dispatch_center.py b/app/ui/dispatch_center.py index 8ecb47a..70c0747 100644 --- a/app/ui/dispatch_center.py +++ b/app/ui/dispatch_center.py @@ -333,28 +333,24 @@ class DispatchCenter(QWidget): self.setObjectName(name) - layout = QVBoxLayout() + self.top_bar = self.DispatchTopBar(self, name) + self.info = self.DispatchInfoCard(self) + + content_widget = QWidget() + content_layout = QVBoxLayout(content_widget) + content_layout.setContentsMargins(0, 0, 0, 0) + content_layout.addWidget(self.top_bar) + content_layout.addWidget(self.info) scrollArea = ScrollArea() scrollArea.setWidgetResizable(True) scrollArea.setContentsMargins(0, 0, 0, 0) scrollArea.setStyleSheet("background: transparent; border: none;") - - content_widget = QWidget() - content_layout = QVBoxLayout(content_widget) - - self.top_bar = self.DispatchTopBar(self, name) - self.info = self.DispatchInfoCard(self) - - content_layout.addWidget(self.top_bar) - content_layout.addWidget(self.info) - scrollArea.setWidget(content_widget) + layout = QVBoxLayout(self) layout.addWidget(scrollArea) - self.setLayout(layout) - class DispatchTopBar(CardWidget): def __init__(self, parent=None, name: str = None): diff --git a/app/ui/history.py b/app/ui/history.py index 6da7a8e..ddf5d95 100644 --- a/app/ui/history.py +++ b/app/ui/history.py @@ -61,21 +61,22 @@ class History(QWidget): super().__init__(parent) self.setObjectName("历史记录") + self.history_top_bar = self.HistoryTopBar(self) + self.history_top_bar.search_history.connect(self.reload_history) + content_widget = QWidget() self.content_layout = QVBoxLayout(content_widget) - self.history_top_bar = self.HistoryTopBar(self) - - self.history_top_bar.search_history.connect(self.reload_history) + self.content_layout.setContentsMargins(0, 0, 11, 0) scrollArea = ScrollArea() scrollArea.setWidgetResizable(True) scrollArea.setContentsMargins(0, 0, 0, 0) scrollArea.setStyleSheet("background: transparent; border: none;") scrollArea.setWidget(content_widget) - layout = QVBoxLayout() + + layout = QVBoxLayout(self) layout.addWidget(self.history_top_bar) layout.addWidget(scrollArea) - self.setLayout(layout) self.history_card_list = [] diff --git a/app/ui/home.py b/app/ui/home.py index 3bd08c5..9a60344 100644 --- a/app/ui/home.py +++ b/app/ui/home.py @@ -62,14 +62,6 @@ class Home(QWidget): self.banner = Banner() self.banner_text = TextBrowser() - widget = QWidget() - Layout = QVBoxLayout(widget) - - Layout.addWidget(self.banner) - Layout.addWidget(self.banner_text) - Layout.setStretch(0, 2) - Layout.setStretch(1, 3) - v_layout = QVBoxLayout(self.banner) v_layout.setContentsMargins(0, 0, 0, 15) v_layout.setSpacing(5) @@ -146,14 +138,22 @@ class Home(QWidget): # 将底部水平布局添加到垂直布局 v_layout.addLayout(h2_layout) - layout = QVBoxLayout() + content_widget = QWidget() + content_layout = QVBoxLayout(content_widget) + content_layout.setContentsMargins(0, 0, 0, 0) + content_layout.addWidget(self.banner) + content_layout.addWidget(self.banner_text) + content_layout.setStretch(0, 2) + content_layout.setStretch(1, 3) + scrollArea = ScrollArea() scrollArea.setWidgetResizable(True) scrollArea.setContentsMargins(0, 0, 0, 0) scrollArea.setStyleSheet("background: transparent; border: none;") - scrollArea.setWidget(widget) + scrollArea.setWidget(content_widget) + + layout = QVBoxLayout(self) layout.addWidget(scrollArea) - self.setLayout(layout) self.set_banner() diff --git a/app/ui/member_manager.py b/app/ui/member_manager.py index b8378e9..4e96e69 100644 --- a/app/ui/member_manager.py +++ b/app/ui/member_manager.py @@ -47,6 +47,8 @@ from qfluentwidgets import ( PushSettingCard, TableWidget, PrimaryToolButton, + Flyout, + FlyoutAnimationType, ) from PySide6.QtCore import Signal from datetime import datetime @@ -64,7 +66,7 @@ from .Widget import ( LineEditSettingCard, SpinBoxSettingCard, ComboBoxMessageBox, - SettingMessageBox, + SettingFlyoutView, EditableComboBoxSettingCard, PasswordLineEditSettingCard, UserLableSettingCard, @@ -73,6 +75,7 @@ from .Widget import ( PushAndSwitchButtonSettingCard, PushAndComboBoxSettingCard, StatusSwitchSetting, + UserNoticeSettingCard, PivotArea, ) @@ -565,29 +568,25 @@ class MemberManager(QWidget): self.setObjectName(f"脚本_{uid}") self.config = Config.member_dict[f"脚本_{uid}"]["Config"] - layout = QVBoxLayout() + self.app_setting = self.AppSettingCard(f"脚本_{uid}", self.config, self) + self.user_setting = self.UserManager(f"脚本_{uid}", self) + + content_widget = QWidget() + content_layout = QVBoxLayout(content_widget) + content_layout.setContentsMargins(0, 0, 11, 0) + content_layout.addWidget(self.app_setting) + content_layout.addWidget(self.user_setting) + content_layout.addStretch(1) scrollArea = ScrollArea() scrollArea.setWidgetResizable(True) scrollArea.setContentsMargins(0, 0, 0, 0) scrollArea.setStyleSheet("background: transparent; border: none;") - - content_widget = QWidget() - content_layout = QVBoxLayout(content_widget) - - self.app_setting = self.AppSettingCard(f"脚本_{uid}", self.config, self) - self.user_setting = self.UserManager(f"脚本_{uid}", self) - - content_layout.addWidget(self.app_setting) - content_layout.addWidget(self.user_setting) - content_layout.addStretch(1) - scrollArea.setWidget(content_widget) + layout = QVBoxLayout(self) layout.addWidget(scrollArea) - self.setLayout(layout) - class AppSettingCard(HeaderCardWidget): def __init__(self, name: str, config: MaaConfig, parent=None): @@ -1531,13 +1530,23 @@ class MemberManager(QWidget): ) # 新增单独通知卡片 - self.card_NotifySet = PushAndSwitchButtonSettingCard( + self.card_NotifySet = UserNoticeSettingCard( icon=FluentIcon.MAIL, title="用户单独通知设置", content="未启用任何通知项", text="设置", qconfig=self.config, configItem=self.config.Notify_Enabled, + configItems={ + "IfSendStatistic": self.config.Notify_IfSendStatistic, + "IfSendSixStar": self.config.Notify_IfSendSixStar, + "IfSendMail": self.config.Notify_IfSendMail, + "ToAddress": self.config.Notify_ToAddress, + "IfServerChan": self.config.Notify_IfServerChan, + "ServerChanKey": self.config.Notify_ServerChanKey, + "IfCompanyWebHookBot": self.config.Notify_IfCompanyWebHookBot, + "CompanyWebHookBotUrl": self.config.Notify_CompanyWebHookBotUrl, + }, parent=self, ) self.card_NotifyContent = self.NotifyContentSettingCard( @@ -1558,9 +1567,10 @@ class MemberManager(QWidget): self.card_CompanyWebhookBot, ] - self.NotifySetCard = SettingMessageBox( - self.window(), "用户通知设置", self.card_NotifySet_list + self.NotifySetCard = SettingFlyoutView( + self, "用户通知设置", self.card_NotifySet_list ) + self.NotifySetCard.setVisible(False) h1_layout = QHBoxLayout() h1_layout.addWidget(self.card_Name) @@ -1625,7 +1635,6 @@ class MemberManager(QWidget): self.switch_mode() self.switch_infrastructure() - self.set_notify(if_show=False) def switch_mode(self) -> None: @@ -1746,44 +1755,17 @@ class MemberManager(QWidget): }, ) - def set_notify(self, if_show: bool = True) -> None: + def set_notify(self) -> None: """设置用户通知相关配置""" - def short_str(s: str) -> str: - if len(s) <= 10: - return s - return s[:7] + "..." - - if if_show: - self.NotifySetCard.exec_() - - content_list = [] - - if not ( - self.config.get(self.config.Notify_IfSendStatistic) - or self.config.get(self.config.Notify_IfSendSixStar) - ): - content_list.append("未启用任何通知项") - - if self.config.get(self.config.Notify_IfSendStatistic): - content_list.append("统计信息已启用") - if self.config.get(self.config.Notify_IfSendSixStar): - content_list.append("六星喜报已启用") - - if self.config.get(self.config.Notify_IfSendMail): - content_list.append( - f"邮箱通知:{short_str(self.config.get(self.config.Notify_ToAddress))}" - ) - if self.config.get(self.config.Notify_IfServerChan): - content_list.append( - f"Server酱通知:{short_str(self.config.get(self.config.Notify_ServerChanKey))}" - ) - if self.config.get(self.config.Notify_IfCompanyWebHookBot): - content_list.append( - f"企业微信通知:{short_str(self.config.get(self.config.Notify_CompanyWebHookBotUrl))}" - ) - - self.card_NotifySet.setContent(" | ".join(content_list)) + self.NotifySetCard.setVisible(True) + Flyout.make( + self.NotifySetCard, + self.card_NotifySet, + self, + aniType=FlyoutAnimationType.PULL_UP, + isDeleteOnClose=False, + ) class NotifyContentSettingCard(HeaderCardWidget): @@ -1814,6 +1796,7 @@ class MemberManager(QWidget): Layout.addWidget(self.card_IfSendStatistic) Layout.addWidget(self.card_IfSendSixStar) self.viewLayout.addLayout(Layout) + self.viewLayout.setSpacing(3) self.viewLayout.setContentsMargins(3, 0, 3, 3) class EMailSettingCard(HeaderCardWidget): @@ -1846,6 +1829,7 @@ class MemberManager(QWidget): Layout.addWidget(self.card_IfSendMail) Layout.addWidget(self.card_ToAddress) self.viewLayout.addLayout(Layout) + self.viewLayout.setSpacing(3) self.viewLayout.setContentsMargins(3, 0, 3, 3) class ServerChanSettingCard(HeaderCardWidget): @@ -1898,6 +1882,7 @@ class MemberManager(QWidget): Layout.addWidget(self.card_ServerChanChannel) Layout.addWidget(self.card_ServerChanTag) self.viewLayout.addLayout(Layout) + self.viewLayout.setSpacing(3) self.viewLayout.setContentsMargins(3, 0, 3, 3) class CompanyWechatPushSettingCard(HeaderCardWidget): @@ -1908,7 +1893,7 @@ class MemberManager(QWidget): self.config = config - self.card_IfCompanyWechat = SwitchSettingCard( + self.card_IfCompanyWebHookBot = SwitchSettingCard( icon=FluentIcon.PAGE_RIGHT, title="推送用户企业微信机器人通知", content="是否启用用户企微机器人通知功能", @@ -1927,7 +1912,8 @@ class MemberManager(QWidget): ) Layout = QVBoxLayout() - Layout.addWidget(self.card_IfCompanyWechat) + Layout.addWidget(self.card_IfCompanyWebHookBot) Layout.addWidget(self.card_CompanyWebHookBotUrl) self.viewLayout.addLayout(Layout) + self.viewLayout.setSpacing(3) self.viewLayout.setContentsMargins(3, 0, 3, 3) diff --git a/app/ui/queue_manager.py b/app/ui/queue_manager.py index c450071..a8ff7a4 100644 --- a/app/ui/queue_manager.py +++ b/app/ui/queue_manager.py @@ -379,16 +379,6 @@ class QueueManager(QWidget): self.setObjectName(f"调度队列_{uid}") self.config = Config.queue_dict[f"调度队列_{uid}"]["Config"] - layout = QVBoxLayout() - - scrollArea = ScrollArea() - scrollArea.setWidgetResizable(True) - scrollArea.setContentsMargins(0, 0, 0, 0) - scrollArea.setStyleSheet("background: transparent; border: none;") - - content_widget = QWidget() - content_layout = QVBoxLayout(content_widget) - self.queue_set = self.QueueSetSettingCard(self.config, self) self.time = self.TimeSettingCard(self.config, self) self.task = self.TaskSettingCard(self.config, self) @@ -398,18 +388,24 @@ class QueueManager(QWidget): parent=self, ) + content_widget = QWidget() + content_layout = QVBoxLayout(content_widget) + content_layout.setContentsMargins(0, 0, 11, 0) content_layout.addWidget(self.queue_set) content_layout.addWidget(self.time) content_layout.addWidget(self.task) content_layout.addWidget(self.history) content_layout.addStretch(1) + scrollArea = ScrollArea() + scrollArea.setWidgetResizable(True) + scrollArea.setContentsMargins(0, 0, 0, 0) + scrollArea.setStyleSheet("background: transparent; border: none;") scrollArea.setWidget(content_widget) + layout = QVBoxLayout(self) layout.addWidget(scrollArea) - self.setLayout(layout) - class QueueSetSettingCard(HeaderCardWidget): def __init__(self, config: QueueConfig, parent=None): diff --git a/app/ui/setting.py b/app/ui/setting.py index 3dbcf7c..2f2be41 100644 --- a/app/ui/setting.py +++ b/app/ui/setting.py @@ -70,9 +70,6 @@ class Setting(QWidget): super().__init__(parent) self.setObjectName("设置") - content_widget = QWidget() - content_layout = QVBoxLayout(content_widget) - self.function = FunctionSettingCard(self) self.start = StartSettingCard(self) self.ui = UiSettingCard(self) @@ -93,6 +90,9 @@ class Setting(QWidget): ) self.other.card_Notice.clicked.connect(lambda: self.show_notice(if_show=True)) + content_widget = QWidget() + content_layout = QVBoxLayout(content_widget) + content_layout.setContentsMargins(0, 0, 11, 0) content_layout.addWidget(self.function) content_layout.addWidget(self.start) content_layout.addWidget(self.ui) @@ -106,9 +106,9 @@ class Setting(QWidget): scrollArea.setContentsMargins(0, 0, 0, 0) scrollArea.setStyleSheet("background: transparent; border: none;") scrollArea.setWidget(content_widget) - layout = QVBoxLayout() + + layout = QVBoxLayout(self) layout.addWidget(scrollArea) - self.setLayout(layout) def agree_bilibili(self) -> None: """授权bilibili游戏隐私政策""" From 3127c836039cb339a5fce869f681b4a705ef4415 Mon Sep 17 00:00:00 2001 From: aoxuan Date: Fri, 23 May 2025 15:01:26 +0800 Subject: [PATCH 07/10] =?UTF-8?q?feat(notification):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=8D=95=E7=8B=AC=E9=80=9A=E7=9F=A5=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/MAA.py | 224 ++++++++++++++++----- app/services/notification.py | 377 +++++++++++++++++------------------ 2 files changed, 361 insertions(+), 240 deletions(-) diff --git a/app/models/MAA.py b/app/models/MAA.py index a2bd23e..2cb5810 100644 --- a/app/models/MAA.py +++ b/app/models/MAA.py @@ -608,13 +608,14 @@ class MaaManager(QObject): Config.app_path / f"history/{curdate}/{user_data["Info"]["Name"]}/{start_time.strftime("%H-%M-%S")}.json", ) - - if Config.get(Config.notify_IfSendSixStar) and if_six_star: - + if if_six_star: self.push_notification( "公招六星", f"喜报:用户 {user[0]} 公招出六星啦!", - {"user_name": user_data["Info"]["Name"]}, + { + "user_name": user_data["Info"]["Name"], + "user_index": user[2], + }, ) # 执行MAA解压更新动作 @@ -643,6 +644,7 @@ class MaaManager(QObject): if Config.get(Config.notify_IfSendStatistic): statistics = Config.merge_maa_logs("指定项", user_logs_list) + statistics["user_index"] = user[2] statistics["user_info"] = user[0] statistics["start_time"] = user_start_time.strftime( "%Y-%m-%d %H:%M:%S" @@ -1772,26 +1774,30 @@ class MaaManager(QObject): message_html = template.render(message) # 发送全局通知 - Notify.send_mail("网页", title, message_html,Config.get(Config.notify_ToAddress)) + if Config.get(Config.notify_IfSendMail): + Notify.send_mail( + "网页", title, message_html, Config.get(Config.notify_ToAddress) + ) serverchan_message = message_text.replace("\n", "\n\n") - Notify.ServerChanPush(title, f"{serverchan_message}\n\nAUTO_MAA 敬上",Config.get(Config.notify_ServerChanKey),Config.get(Config.notify_ServerChanTag),Config.get(Config.notify_ServerChanChannel)) - Notify.CompanyWebHookBotPush(title, f"{message_text}\n\nAUTO_MAA 敬上",Config.get(Config.notify_CompanyWebHookBotUrl)) - - # # 发送用户单独通知 - # for user_name in message["failed_user"].split("、") + message["waiting_user"].split("、"): - # if not user_name: # 跳过空字符串 - # continue - # user_config = Config.member_dict.get(user_name) - # if user_config and user_config.get(user_config.Notify_Enable): - # user_notify = UserNotification(user_config) - # user_notify.send_notification( - # f"{self.mode[2:4]}任务未完成通知", - # f"您的{self.mode[2:4]}任务未完成,请检查相关设置。\n\n{message_text}" - # ) + if Config.get(Config.notify_IfServerChan): + Notify.ServerChanPush( + title, + f"{serverchan_message}\n\nAUTO_MAA 敬上", + Config.get(Config.notify_ServerChanKey), + Config.get(Config.notify_ServerChanTag), + Config.get(Config.notify_ServerChanChannel), + ) + if Config.get(Config.notify_IfCompanyWebHookBot): + Notify.CompanyWebHookBotPush( + title, + f"{message_text}\n\nAUTO_MAA 敬上", + Config.get(Config.notify_CompanyWebHookBotUrl), + ) return message_text elif mode == "统计信息": + user_index = message.get("user_index") # 生成文本通知内容 formatted = [] for stage, items in message["drop_statistics"].items(): @@ -1818,40 +1824,166 @@ class MaaManager(QObject): message_html = template.render(message) # 发送全局通知 - Notify.send_mail("网页", title, message_html,Config.get(Config.notify_ToAddress)) + if Config.get(Config.notify_IfSendMail): + Notify.send_mail( + "网页", title, message_html, Config.get(Config.notify_ToAddress) + ) # ServerChan的换行是两个换行符。故而将\n替换为\n\n serverchan_message = message_text.replace("\n", "\n\n") - Notify.ServerChanPush(title, f"{serverchan_message}\n\nAUTO_MAA 敬上",Config.get(Config.notify_ServerChanKey),Config.get(Config.notify_ServerChanTag),Config.get(Config.notify_ServerChanChannel)) - Notify.CompanyWebHookBotPush(title, f"{message_text}\n\nAUTO_MAA 敬上",Config.get(Config.notify_CompanyWebHookBotUrl)) + if Config.get(Config.notify_IfServerChan): + Notify.ServerChanPush( + title, + f"{serverchan_message}\n\nAUTO_MAA 敬上", + Config.get(Config.notify_ServerChanKey), + Config.get(Config.notify_ServerChanTag), + Config.get(Config.notify_ServerChanChannel), + ) + if Config.get(Config.notify_IfCompanyWebHookBot): + Notify.CompanyWebHookBotPush( + title, + f"{message_text}\n\nAUTO_MAA 敬上", + Config.get(Config.notify_CompanyWebHookBotUrl), + ) - # # 发送用户单独通知 - # user_name = message.get("user_info") - # if user_name: - # user_config = Config.member_dict.get(user_name) - # if user_config and user_config.get(user_config.Notify_Enable): - # user_notify = UserNotification(user_config) - # user_notify.send_notification( - # f"{self.mode[2:4]}任务统计报告", - # f"您的{self.mode[2:4]}任务统计报告如下:\n\n{message_text}" - # ) + # 发送用户单独通知 + user_data = self.data.get(user_index, {}).get("Config", {}) + if user_data["Notify"].get("IfSendStatistic", False): + if user_data.get("Notify") and user_data["Notify"].get( + "Enabled", False + ): + # 发送邮件通知 + if user_data.get("Notify", {}).get("IfSendMail", False): + userToAddress = user_data.get("Notify", {}).get("ToAddress") + if userToAddress: + Notify.send_mail("网页", title, message_text, userToAddress) + else: + logger.error( + f"{self.name} | 用户邮箱地址为空,无法发送用户单独的邮件通知" + ) + + # 发送ServerChan通知 + if user_data.get("Notify", {}).get("IfServerChan", False): + userServerChanKey = user_data.get("Notify", {}).get( + "ServerChanKey" + ) + userServerChanTag = user_data.get("Notify", {}).get( + "ServerChanTag" + ) + userServerChanChannel = user_data.get("Notify", {}).get( + "ServerChanChannel" + ) + if userServerChanKey: + Notify.ServerChanPush( + title, + f"{serverchan_message}\n\nAUTO_MAA 敬上", + userServerChanKey, + userServerChanTag, + userServerChanChannel, + ) + else: + logger.error( + f"{self.name} |用户ServerChan密钥为空,无法发送用户单独的ServerChan通知" + ) + + # 推送CompanyWebHookBot通知 + if user_data.get("Notify", {}).get("IfCompanyWebHookBot", False): + userCompanyWebHookBotUrl = user_data.get("Notify", {}).get( + "CompanyWebHookBotUrl" + ) + if userCompanyWebHookBotUrl: + Notify.CompanyWebHookBotPush( + title, + f"{message_text}\n\nAUTO_MAA 敬上", + userCompanyWebHookBotUrl, + ) + else: + logger.error( + f"{self.name} |用户CompanyWebHookBot密钥为空,无法发送用户单独的CompanyWebHookBot通知" + ) elif mode == "公招六星": + user_index = message.get("user_index") # 生成HTML通知内容 template = env.get_template("MAA_six_star.html") + + # 这里需要看一下,我给message加了个user_index message_html = template.render(message) - # 发送全局通知 - Notify.send_mail("网页", title, message_html,Config.get(Config.notify_ToAddress)) - Notify.ServerChanPush(title, "好羡慕~\n\nAUTO_MAA 敬上",Config.get(Config.notify_ServerChanKey),Config.get(Config.notify_ServerChanTag),Config.get(Config.notify_ServerChanChannel)) - Notify.CompanyWebHookBotPush(title, "好羡慕~\n\nAUTO_MAA 敬上",Config.get(Config.notify_CompanyWebHookBotUrl)) + if Config.get(Config.notify_IfSendSixStar): + # 发送全局通知 + if Config.get(Config.notify_IfSendMail): + Notify.send_mail( + "网页", title, message_html, Config.get(Config.notify_ToAddress) + ) + if Config.get(Config.notify_IfServerChan): + Notify.ServerChanPush( + title, + "好羡慕~\n\nAUTO_MAA 敬上", + Config.get(Config.notify_ServerChanKey), + Config.get(Config.notify_ServerChanTag), + Config.get(Config.notify_ServerChanChannel), + ) + if Config.get(Config.notify_IfCompanyWebHookBot): + Notify.CompanyWebHookBotPush( + title, + "好羡慕~\n\nAUTO_MAA 敬上", + Config.get(Config.notify_CompanyWebHookBotUrl), + ) + # 发送用户单独通知 + user_data = self.data.get(user_index, {}).get("Config", {}) - # # 发送用户单独通知 - # user_name = message.get("user_name") - # if user_name: - # user_config = Config.member_dict.get(user_name) - # if user_config and user_config.get(user_config.Notify_Enable): - # user_notify = UserNotification(user_config) - # user_notify.send_notification( - # "公招六星通知", - # "恭喜您在公招中获得了六星干员!" - # ) + # 判断是否单独发送六星 + if user_data["Notify"].get("IfSendSixStar", False): + if user_data.get("Notify") and user_data["Notify"].get( + "Enabled", False + ): + # 发送邮件通知 + if user_data.get("Notify", {}).get("IfSendMail", False): + userToAddress = user_data.get("Notify", {}).get("ToAddress") + if userToAddress: + Notify.send_mail("网页", title, message_html, userToAddress) + else: + logger.error( + f"{self.name} | 用户邮箱地址为空,无法发送用户单独的邮件通知" + ) + + # 发送ServerChan通知 + if user_data.get("Notify", {}).get("IfServerChan", False): + userServerChanKey = user_data.get("Notify", {}).get( + "ServerChanKey" + ) + userServerChanTag = user_data.get("Notify", {}).get( + "ServerChanTag" + ) + userServerChanChannel = user_data.get("Notify", {}).get( + "ServerChanChannel" + ) + if userServerChanKey: + Notify.ServerChanPush( + title, + "好羡慕~\n\nAUTO_MAA 敬上", + userServerChanKey, + userServerChanTag, + userServerChanChannel, + ) + else: + logger.error( + f"{self.name} |用户ServerChan密钥为空,无法发送用户单独的ServerChan通知" + ) + + # 推送CompanyWebHookBot通知 + if user_data.get("Notify", {}).get("IfCompanyWebHookBot", False): + userCompanyWebHookBotUrl = user_data.get("Notify", {}).get( + "CompanyWebHookBotUrl" + ) + if userCompanyWebHookBotUrl: + Notify.CompanyWebHookBotPush( + title, + "好羡慕~\n\nAUTO_MAA 敬上", + userCompanyWebHookBotUrl, + ) + else: + logger.error( + f"{self.name} |用户CompanyWebHookBot密钥为空,无法发送用户单独的CompanyWebHookBot通知" + ) + return None diff --git a/app/services/notification.py b/app/services/notification.py index 639e3ac..4cb60bb 100644 --- a/app/services/notification.py +++ b/app/services/notification.py @@ -69,219 +69,208 @@ class Notification(QWidget): def send_mail(self, mode, title, content, to_address) -> None: """推送邮件通知""" - - if Config.get(Config.notify_IfSendMail): - - if ( - Config.get(Config.notify_SMTPServerAddress) == "" - or Config.get(Config.notify_AuthorizationCode) == "" - or not bool( - re.match( - r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", - Config.get(Config.notify_FromAddress), - ) - ) - or not bool( - re.match( - r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", - to_address, - ) - ) - ): - logger.error( - "请正确设置邮件通知的SMTP服务器地址、授权码、发件人地址和收件人地址" - ) - self.push_info_bar.emit( - "error", - "邮件通知推送异常", - "请正确设置邮件通知的SMTP服务器地址、授权码、发件人地址和收件人地址", - -1, - ) - return None - - try: - # 定义邮件正文 - if mode == "文本": - message = MIMEText(content, "plain", "utf-8") - elif mode == "网页": - message = MIMEMultipart("alternative") - message["From"] = formataddr( - ( - Header("AUTO_MAA通知服务", "utf-8").encode(), - Config.get(Config.notify_FromAddress), - ) - ) # 发件人显示的名字 - message["To"] = formataddr( - ( - Header("AUTO_MAA用户", "utf-8").encode(), - to_address, - ) - ) # 收件人显示的名字 - message["Subject"] = Header(title, "utf-8") - - if mode == "网页": - message.attach(MIMEText(content, "html", "utf-8")) - - smtpObj = smtplib.SMTP_SSL( - Config.get(Config.notify_SMTPServerAddress), - 465, - ) - smtpObj.login( + if ( + Config.get(Config.notify_SMTPServerAddress) == "" + or Config.get(Config.notify_AuthorizationCode) == "" + or not bool( + re.match( + r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", Config.get(Config.notify_FromAddress), - Crypto.win_decryptor(Config.get(Config.notify_AuthorizationCode)), ) - smtpObj.sendmail( - Config.get(Config.notify_FromAddress), + ) + or not bool( + re.match( + r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", to_address, - message.as_string(), ) - smtpObj.quit() - logger.success("邮件发送成功") - return None - except Exception as e: - logger.error(f"发送邮件时出错:\n{e}") - self.push_info_bar.emit("error", "发送邮件时出错", f"{e}", -1) - return None + ) + ): + logger.error( + "请正确设置邮件通知的SMTP服务器地址、授权码、发件人地址和收件人地址" + ) + self.push_info_bar.emit( + "error", + "邮件通知推送异常", + "请正确设置邮件通知的SMTP服务器地址、授权码、发件人地址和收件人地址", + -1, + ) + return None + + try: + # 定义邮件正文 + if mode == "文本": + message = MIMEText(content, "plain", "utf-8") + elif mode == "网页": + message = MIMEMultipart("alternative") + message["From"] = formataddr( + ( + Header("AUTO_MAA通知服务", "utf-8").encode(), + Config.get(Config.notify_FromAddress), + ) + ) # 发件人显示的名字 + message["To"] = formataddr( + ( + Header("AUTO_MAA用户", "utf-8").encode(), + to_address, + ) + ) # 收件人显示的名字 + message["Subject"] = Header(title, "utf-8") + + if mode == "网页": + message.attach(MIMEText(content, "html", "utf-8")) + + smtpObj = smtplib.SMTP_SSL( + Config.get(Config.notify_SMTPServerAddress), + 465, + ) + smtpObj.login( + Config.get(Config.notify_FromAddress), + Crypto.win_decryptor(Config.get(Config.notify_AuthorizationCode)), + ) + smtpObj.sendmail( + Config.get(Config.notify_FromAddress), + to_address, + message.as_string(), + ) + smtpObj.quit() + logger.success("邮件发送成功") + return None + except Exception as e: + logger.error(f"发送邮件时出错:\n{e}") + self.push_info_bar.emit("error", "发送邮件时出错", f"{e}", -1) + return None return None def ServerChanPush(self, title, content, send_key, tag, channel): """使用Server酱推送通知""" - if Config.get(Config.notify_IfServerChan): - if not send_key: - logger.error("请正确设置Server酱的SendKey") - self.push_info_bar.emit( - "error", "Server酱通知推送异常", "请正确设置Server酱的SendKey", -1 - ) - return None + if not send_key: + logger.error("请正确设置Server酱的SendKey") + self.push_info_bar.emit( + "error", "Server酱通知推送异常", "请正确设置Server酱的SendKey", -1 + ) + return None - try: - # 构造 URL - if send_key.startswith("sctp"): - match = re.match(r"^sctp(\d+)t", send_key) - if match: - url = f"https://{match.group(1)}.push.ft07.com/send/{send_key}.send" - else: - raise ValueError("SendKey 格式错误(sctp)") + try: + # 构造 URL + if send_key.startswith("sctp"): + match = re.match(r"^sctp(\d+)t", send_key) + if match: + url = f"https://{match.group(1)}.push.ft07.com/send/{send_key}.send" else: - url = f"https://sctapi.ftqq.com/{send_key}.send" - - # 构建 tags 和 channel - def is_valid(s): - return s == "" or ( - s == "|".join(s.split("|")) - and (s.count("|") == 0 or all(s.split("|"))) - ) - - tags = "|".join( - _.strip() - for _ in tag.split("|") - ) - channels = "|".join( - _.strip() - for _ in channel.split("|") - ) - - options = {} - if is_valid(tags): - options["tags"] = tags - else: - logger.warning("Server酱 Tag 配置不正确,将被忽略") - self.push_info_bar.emit( - "warning", - "Server酱通知推送异常", - "请正确设置 ServerChan 的 Tag", - -1, - ) - - if is_valid(channels): - options["channel"] = channels - else: - logger.warning("Server酱 Channel 配置不正确,将被忽略") - self.push_info_bar.emit( - "warning", - "Server酱通知推送异常", - "请正确设置 ServerChan 的 Channel", - -1, - ) - - # 请求发送 - params = {"title": title, "desp": content, **options} - headers = {"Content-Type": "application/json;charset=utf-8"} - - response = requests.post(url, json=params, headers=headers, timeout=10) - result = response.json() - - if result.get("code") == 0: - logger.info("Server酱推送通知成功") - return True - else: - error_code = result.get("code", "-1") - logger.error(f"Server酱通知推送失败:响应码:{error_code}") - self.push_info_bar.emit( - "error", "Server酱通知推送失败", f"响应码:{error_code}", -1 - ) - return f"Server酱通知推送失败:{error_code}" - - except Exception as e: - logger.exception("Server酱通知推送异常") - self.push_info_bar.emit( - "error", "Server酱通知推送异常", f"请检查相关设置,如还有问题可联系开发者", -1 - ) - return f"Server酱通知推送异常:{str(e)}" - return None - - def CompanyWebHookBotPush(self, title, content,webhook_url): - """使用企业微信群机器人推送通知""" - if Config.get(Config.notify_IfCompanyWebHookBot): - - if webhook_url == "": - logger.error("请正确设置企业微信群机器人的WebHook地址") - self.push_info_bar.emit( - "error", - "企业微信群机器人通知推送异常", - "请正确设置企业微信群机器人的WebHook地址", - -1, - ) - return None - - content = f"{title}\n{content}" - data = {"msgtype": "text", "text": {"content": content}} - - for _ in range(3): - try: - response = requests.post( - url=webhook_url, - json=data, - timeout=10, - ) - info = response.json() - break - except Exception as e: - err = e - time.sleep(0.1) + raise ValueError("SendKey 格式错误(sctp)") else: - logger.error(f"推送企业微信群机器人时出错:{err}") + url = f"https://sctapi.ftqq.com/{send_key}.send" + + # 构建 tags 和 channel + def is_valid(s): + return s == "" or ( + s == "|".join(s.split("|")) + and (s.count("|") == 0 or all(s.split("|"))) + ) + + tags = "|".join(_.strip() for _ in tag.split("|")) + channels = "|".join(_.strip() for _ in channel.split("|")) + + options = {} + if is_valid(tags): + options["tags"] = tags + else: + logger.warning("Server酱 Tag 配置不正确,将被忽略") self.push_info_bar.emit( - "error", - "企业微信群机器人通知推送失败", - f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}', + "warning", + "Server酱通知推送异常", + "请正确设置 ServerChan 的 Tag", -1, ) - return None - if info["errcode"] == 0: - logger.info("企业微信群机器人推送通知成功") + if is_valid(channels): + options["channel"] = channels + else: + logger.warning("Server酱 Channel 配置不正确,将被忽略") + self.push_info_bar.emit( + "warning", + "Server酱通知推送异常", + "请正确设置 ServerChan 的 Channel", + -1, + ) + + # 请求发送 + params = {"title": title, "desp": content, **options} + headers = {"Content-Type": "application/json;charset=utf-8"} + + response = requests.post(url, json=params, headers=headers, timeout=10) + result = response.json() + + if result.get("code") == 0: + logger.info("Server酱推送通知成功") return True else: - logger.error(f"企业微信群机器人推送通知失败:{info}") + error_code = result.get("code", "-1") + logger.error(f"Server酱通知推送失败:响应码:{error_code}") self.push_info_bar.emit( - "error", - "企业微信群机器人通知推送失败", - f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}', - -1, + "error", "Server酱通知推送失败", f"响应码:{error_code}", -1 ) - return f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}' - return None + return f"Server酱通知推送失败:{error_code}" + + except Exception as e: + logger.exception("Server酱通知推送异常") + self.push_info_bar.emit( + "error", + "Server酱通知推送异常", + "请检查相关设置和网络连接。如全部配置正确,请稍后再试。", + -1, + ) + return f"Server酱通知推送异常:{str(e)}" + + def CompanyWebHookBotPush(self, title, content, webhook_url): + """使用企业微信群机器人推送通知""" + if webhook_url == "": + logger.error("请正确设置企业微信群机器人的WebHook地址") + self.push_info_bar.emit( + "error", + "企业微信群机器人通知推送异常", + "请正确设置企业微信群机器人的WebHook地址", + -1, + ) + return None + + content = f"{title}\n{content}" + data = {"msgtype": "text", "text": {"content": content}} + + for _ in range(3): + try: + response = requests.post( + url=webhook_url, + json=data, + timeout=10, + ) + info = response.json() + break + except Exception as e: + err = e + time.sleep(0.1) + else: + logger.error(f"推送企业微信群机器人时出错:{err}") + self.push_info_bar.emit( + "error", + "企业微信群机器人通知推送失败", + f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}', + -1, + ) + return None + + if info["errcode"] == 0: + logger.info("企业微信群机器人推送通知成功") + return True + else: + logger.error(f"企业微信群机器人推送通知失败:{info}") + self.push_info_bar.emit( + "error", + "企业微信群机器人通知推送失败", + f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}', + -1, + ) + return f'使用企业微信群机器人推送通知时出错:{info["errmsg"]}' def send_test_notification(self): """发送测试通知到所有已启用的通知渠道""" From 974a4b634a12e5fd886900da263c555bf80d9565 Mon Sep 17 00:00:00 2001 From: aoxuan Date: Fri, 23 May 2025 15:19:35 +0800 Subject: [PATCH 08/10] =?UTF-8?q?feat(ui):=20=E4=BC=98=E5=8C=96=E6=95=8F?= =?UTF-8?q?=E6=84=9F=E4=BF=A1=E6=81=AF=E6=98=BE=E7=A4=BA=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ui/Widget.py | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/app/ui/Widget.py b/app/ui/Widget.py index 4aa98be..cf21c1d 100644 --- a/app/ui/Widget.py +++ b/app/ui/Widget.py @@ -25,17 +25,24 @@ v4.3 作者:DLmaster_361 """ +import os +import re +from datetime import datetime +from functools import partial +from typing import Optional, Union, List, Dict +from urllib.parse import urlparse + +import markdown +from PySide6.QtCore import Qt, QTime, QTimer, QEvent, QSize +from PySide6.QtGui import QIcon, QPixmap, QPainter, QPainterPath from PySide6.QtWidgets import ( QApplication, QWidget, - QWidget, QLabel, QHBoxLayout, QVBoxLayout, QSizePolicy, ) -from PySide6.QtCore import Qt, QTime, QTimer, QEvent, QSize -from PySide6.QtGui import QIcon, QPixmap, QPainter, QPainterPath from qfluentwidgets import ( LineEdit, PasswordLineEdit, @@ -77,13 +84,6 @@ from qfluentwidgets import ( FlyoutViewBase, ) from qfluentwidgets.common.overload import singledispatchmethod -import os -import re -import markdown -from datetime import datetime -from urllib.parse import urlparse -from functools import partial -from typing import Optional, Union, List, Dict from app.core import Config from app.services import Crypto @@ -998,9 +998,31 @@ class UserNoticeSettingCard(PushAndSwitchButtonSettingCard): def setValues(self): def short_str(s: str) -> str: - if len(s) <= 10: - return s - return s[:10] + "..." + if s.startswith(("SC", "sc")): + # SendKey:首4 + 末4 + return f"{s[:4]}***{s[-4:]}" if len(s) > 8 else s + + elif s.startswith(("http://", "https://")): + # Webhook URL:域名 + 路径尾4 + parsed_url = urlparse(s) + domain = parsed_url.netloc + path_tail = ( + parsed_url.path[-4:] + if len(parsed_url.path) > 4 + else parsed_url.path + ) + return f"{domain}" + + elif "@" in s: + # # 邮箱:显示@前最多3字符 + 域名 + # username, domain = s.split("@", 1) + # displayed_name = username[-3:] if len(username) > 3 else username + # 邮箱展示全部 + return f"{s}" + + else: + # 普通字符串:末尾3字符 + return f"***{s[-3:]}" if len(s) > 3 else s content_list = [] From f5d898c89ef09941230ecc60035aa7253888d894 Mon Sep 17 00:00:00 2001 From: DLmaster361 Date: Fri, 23 May 2025 22:59:09 +0800 Subject: [PATCH 09/10] =?UTF-8?q?fix(maa):=20=E5=B0=86=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=E5=88=A4=E5=AE=9A=E8=BF=87=E7=A8=8B=E5=85=A8=E9=83=A8=E7=A7=BB?= =?UTF-8?q?=E5=85=A5`push=5Fnotification`=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/core/config.py | 2 +- app/models/MAA.py | 347 ++++++++++++++++++++--------------------- app/ui/Widget.py | 25 +-- resources/version.json | 7 +- 4 files changed, 192 insertions(+), 189 deletions(-) diff --git a/app/core/config.py b/app/core/config.py index 3c5781c..77dbb72 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -584,7 +584,7 @@ class MaaPlanConfig(LQConfig): class AppConfig(GlobalConfig): - VERSION = "4.3.8.3" + VERSION = "4.3.8.4" gameid_refreshed = Signal() PASSWORD_refreshed = Signal() diff --git a/app/models/MAA.py b/app/models/MAA.py index 2cb5810..5b1ceef 100644 --- a/app/models/MAA.py +++ b/app/models/MAA.py @@ -614,8 +614,8 @@ class MaaManager(QObject): f"喜报:用户 {user[0]} 公招出六星啦!", { "user_name": user_data["Info"]["Name"], - "user_index": user[2], }, + user_data, ) # 执行MAA解压更新动作 @@ -641,27 +641,23 @@ class MaaManager(QObject): logger.info(f"{self.name} | 更新动作结束") - if Config.get(Config.notify_IfSendStatistic): - - statistics = Config.merge_maa_logs("指定项", user_logs_list) - statistics["user_index"] = user[2] - statistics["user_info"] = user[0] - statistics["start_time"] = user_start_time.strftime( - "%Y-%m-%d %H:%M:%S" - ) - statistics["end_time"] = datetime.now().strftime( - "%Y-%m-%d %H:%M:%S" - ) - statistics["maa_result"] = ( - "代理任务全部完成" - if (run_book["Annihilation"] and run_book["Routine"]) - else "代理任务未全部完成" - ) - self.push_notification( - "统计信息", - f"{current_date} | 用户 {user[0]} 的自动代理统计报告", - statistics, - ) + # 发送统计信息 + statistics = Config.merge_maa_logs("指定项", user_logs_list) + statistics["user_index"] = user[2] + statistics["user_info"] = user[0] + statistics["start_time"] = user_start_time.strftime("%Y-%m-%d %H:%M:%S") + statistics["end_time"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + statistics["maa_result"] = ( + "代理任务全部完成" + if (run_book["Annihilation"] and run_book["Routine"]) + else "代理任务未全部完成" + ) + self.push_notification( + "统计信息", + f"{current_date} | 用户 {user[0]} 的自动代理统计报告", + statistics, + user_data, + ) if run_book["Annihilation"] and run_book["Routine"]: # 成功完成代理的用户修改相关参数 @@ -854,6 +850,17 @@ class MaaManager(QObject): self.data[_]["Config"]["Info"]["Name"] for _ in wait_index ], } + + # 生成结果文本 + result_text = ( + f"任务开始时间:{result["start_time"]},结束时间:{result["end_time"]}\n" + f"已完成数:{result["completed_count"]},未完成数:{result["uncompleted_count"]}\n\n" + ) + if len(result["failed_user"]) > 0: + result_text += f"{self.mode[2:4]}未成功的用户:\n{"\n".join(result["failed_user"])}\n" + if len(result["waiting_user"]) > 0: + result_text += f"\n未开始{self.mode[2:4]}的用户:\n{"\n".join(result["waiting_user"])}\n" + # 推送代理结果通知 Notify.push_plyer( title.replace("报告", "已完成!"), @@ -861,15 +868,7 @@ class MaaManager(QObject): f"已完成用户数:{len(over_index)},未完成用户数:{len(error_index) + len(wait_index)}", 10, ) - if Config.get(Config.notify_SendTaskResultTime) == "任何时刻" or ( - Config.get(Config.notify_SendTaskResultTime) == "仅失败时" - and len(error_index) + len(wait_index) != 0 - ): - result_text = self.push_notification("代理结果", title, result) - else: - result_text = self.push_notification( - "代理结果", title, result, if_get_text_only=True - ) + self.push_notification("代理结果", title, result) self.agree_bilibili(False) self.log_monitor.deleteLater() @@ -1743,15 +1742,21 @@ class MaaManager(QObject): mode: str, title: str, message: Union[str, dict], - if_get_text_only: bool = False, - ) -> str: + user_data: Dict[str, Dict[str, Union[str, int, bool]]] = None, + ) -> None: """通过所有渠道推送通知""" env = Environment( loader=FileSystemLoader(str(Config.app_path / "resources/html")) ) - if mode == "代理结果": + if mode == "代理结果" and ( + Config.get(Config.notify_SendTaskResultTime) == "任何时刻" + or ( + Config.get(Config.notify_SendTaskResultTime) == "仅失败时" + and message["uncompleted_count"] != 0 + ) + ): # 生成文本通知内容 message_text = ( f"任务开始时间:{message["start_time"]},结束时间:{message["end_time"]}\n" @@ -1763,9 +1768,6 @@ class MaaManager(QObject): if len(message["waiting_user"]) > 0: message_text += f"\n未开始{self.mode[2:4]}的用户:\n{"\n".join(message["waiting_user"])}\n" - if if_get_text_only: - return message_text - # 生成HTML通知内容 message["failed_user"] = "、".join(message["failed_user"]) message["waiting_user"] = "、".join(message["waiting_user"]) @@ -1773,12 +1775,16 @@ class MaaManager(QObject): template = env.get_template("MAA_result.html") message_html = template.render(message) + # ServerChan的换行是两个换行符。故而将\n替换为\n\n + serverchan_message = message_text.replace("\n", "\n\n") + # 发送全局通知 + if Config.get(Config.notify_IfSendMail): Notify.send_mail( "网页", title, message_html, Config.get(Config.notify_ToAddress) ) - serverchan_message = message_text.replace("\n", "\n\n") + if Config.get(Config.notify_IfServerChan): Notify.ServerChanPush( title, @@ -1787,6 +1793,7 @@ class MaaManager(QObject): Config.get(Config.notify_ServerChanTag), Config.get(Config.notify_ServerChanChannel), ) + if Config.get(Config.notify_IfCompanyWebHookBot): Notify.CompanyWebHookBotPush( title, @@ -1794,10 +1801,8 @@ class MaaManager(QObject): Config.get(Config.notify_CompanyWebHookBotUrl), ) - return message_text - elif mode == "统计信息": - user_index = message.get("user_index") + # 生成文本通知内容 formatted = [] for stage, items in message["drop_statistics"].items(): @@ -1823,98 +1828,96 @@ class MaaManager(QObject): template = env.get_template("MAA_statistics.html") message_html = template.render(message) - # 发送全局通知 - if Config.get(Config.notify_IfSendMail): - Notify.send_mail( - "网页", title, message_html, Config.get(Config.notify_ToAddress) - ) # ServerChan的换行是两个换行符。故而将\n替换为\n\n serverchan_message = message_text.replace("\n", "\n\n") - if Config.get(Config.notify_IfServerChan): - Notify.ServerChanPush( - title, - f"{serverchan_message}\n\nAUTO_MAA 敬上", - Config.get(Config.notify_ServerChanKey), - Config.get(Config.notify_ServerChanTag), - Config.get(Config.notify_ServerChanChannel), - ) - if Config.get(Config.notify_IfCompanyWebHookBot): - Notify.CompanyWebHookBotPush( - title, - f"{message_text}\n\nAUTO_MAA 敬上", - Config.get(Config.notify_CompanyWebHookBotUrl), - ) - # 发送用户单独通知 - user_data = self.data.get(user_index, {}).get("Config", {}) - if user_data["Notify"].get("IfSendStatistic", False): - if user_data.get("Notify") and user_data["Notify"].get( - "Enabled", False - ): - # 发送邮件通知 - if user_data.get("Notify", {}).get("IfSendMail", False): - userToAddress = user_data.get("Notify", {}).get("ToAddress") - if userToAddress: - Notify.send_mail("网页", title, message_text, userToAddress) - else: - logger.error( - f"{self.name} | 用户邮箱地址为空,无法发送用户单独的邮件通知" - ) + # 发送全局通知 + if Config.get(Config.notify_IfSendStatistic): - # 发送ServerChan通知 - if user_data.get("Notify", {}).get("IfServerChan", False): - userServerChanKey = user_data.get("Notify", {}).get( - "ServerChanKey" - ) - userServerChanTag = user_data.get("Notify", {}).get( - "ServerChanTag" - ) - userServerChanChannel = user_data.get("Notify", {}).get( - "ServerChanChannel" - ) - if userServerChanKey: - Notify.ServerChanPush( - title, - f"{serverchan_message}\n\nAUTO_MAA 敬上", - userServerChanKey, - userServerChanTag, - userServerChanChannel, - ) - else: - logger.error( - f"{self.name} |用户ServerChan密钥为空,无法发送用户单独的ServerChan通知" - ) - - # 推送CompanyWebHookBot通知 - if user_data.get("Notify", {}).get("IfCompanyWebHookBot", False): - userCompanyWebHookBotUrl = user_data.get("Notify", {}).get( - "CompanyWebHookBotUrl" - ) - if userCompanyWebHookBotUrl: - Notify.CompanyWebHookBotPush( - title, - f"{message_text}\n\nAUTO_MAA 敬上", - userCompanyWebHookBotUrl, - ) - else: - logger.error( - f"{self.name} |用户CompanyWebHookBot密钥为空,无法发送用户单独的CompanyWebHookBot通知" - ) - - elif mode == "公招六星": - user_index = message.get("user_index") - # 生成HTML通知内容 - template = env.get_template("MAA_six_star.html") - - # 这里需要看一下,我给message加了个user_index - message_html = template.render(message) - - if Config.get(Config.notify_IfSendSixStar): - # 发送全局通知 if Config.get(Config.notify_IfSendMail): Notify.send_mail( "网页", title, message_html, Config.get(Config.notify_ToAddress) ) + + if Config.get(Config.notify_IfServerChan): + Notify.ServerChanPush( + title, + f"{serverchan_message}\n\nAUTO_MAA 敬上", + Config.get(Config.notify_ServerChanKey), + Config.get(Config.notify_ServerChanTag), + Config.get(Config.notify_ServerChanChannel), + ) + + if Config.get(Config.notify_IfCompanyWebHookBot): + Notify.CompanyWebHookBotPush( + title, + f"{message_text}\n\nAUTO_MAA 敬上", + Config.get(Config.notify_CompanyWebHookBotUrl), + ) + + # 发送用户单独通知 + if ( + user_data["Notify"]["Enabled"] + and user_data["Notify"]["IfSendStatistic"] + ): + + # 发送邮件通知 + if user_data["Notify"]["IfSendMail"]: + if user_data["Notify"]["ToAddress"]: + Notify.send_mail( + "网页", + title, + message_html, + user_data["Notify"]["ToAddress"], + ) + else: + logger.error( + f"{self.name} | 用户邮箱地址为空,无法发送用户单独的邮件通知" + ) + + # 发送ServerChan通知 + if user_data["Notify"]["IfServerChan"]: + if user_data["Notify"]["ServerChanKey"]: + Notify.ServerChanPush( + title, + f"{serverchan_message}\n\nAUTO_MAA 敬上", + user_data["Notify"]["ServerChanKey"], + user_data["Notify"]["ServerChanTag"], + user_data["Notify"]["ServerChanChannel"], + ) + else: + logger.error( + f"{self.name} |用户ServerChan密钥为空,无法发送用户单独的ServerChan通知" + ) + + # 推送CompanyWebHookBot通知 + if user_data["Notify"]["IfCompanyWebHookBot"]: + if user_data["Notify"]["CompanyWebHookBotUrl"]: + Notify.CompanyWebHookBotPush( + title, + f"{message_text}\n\nAUTO_MAA 敬上", + user_data["Notify"]["CompanyWebHookBotUrl"], + ) + else: + logger.error( + f"{self.name} |用户CompanyWebHookBot密钥为空,无法发送用户单独的CompanyWebHookBot通知" + ) + + elif mode == "公招六星": + + # 生成HTML通知内容 + template = env.get_template("MAA_six_star.html") + + message_html = template.render(message) + + # 发送全局通知 + if Config.get(Config.notify_IfSendSixStar): + + if Config.get(Config.notify_IfSendMail): + Notify.send_mail( + "网页", title, message_html, Config.get(Config.notify_ToAddress) + ) + if Config.get(Config.notify_IfServerChan): Notify.ServerChanPush( title, @@ -1923,67 +1926,57 @@ class MaaManager(QObject): Config.get(Config.notify_ServerChanTag), Config.get(Config.notify_ServerChanChannel), ) + if Config.get(Config.notify_IfCompanyWebHookBot): Notify.CompanyWebHookBotPush( title, "好羡慕~\n\nAUTO_MAA 敬上", Config.get(Config.notify_CompanyWebHookBotUrl), ) + # 发送用户单独通知 - user_data = self.data.get(user_index, {}).get("Config", {}) + if user_data["Notify"]["Enabled"] and user_data["Notify"]["IfSendSixStar"]: - # 判断是否单独发送六星 - if user_data["Notify"].get("IfSendSixStar", False): - if user_data.get("Notify") and user_data["Notify"].get( - "Enabled", False - ): - # 发送邮件通知 - if user_data.get("Notify", {}).get("IfSendMail", False): - userToAddress = user_data.get("Notify", {}).get("ToAddress") - if userToAddress: - Notify.send_mail("网页", title, message_html, userToAddress) - else: - logger.error( - f"{self.name} | 用户邮箱地址为空,无法发送用户单独的邮件通知" - ) + # 发送邮件通知 + if user_data["Notify"]["IfSendMail"]: + if user_data["Notify"]["ToAddress"]: + Notify.send_mail( + "网页", + title, + message_html, + user_data["Notify"]["ToAddress"], + ) + else: + logger.error( + f"{self.name} | 用户邮箱地址为空,无法发送用户单独的邮件通知" + ) - # 发送ServerChan通知 - if user_data.get("Notify", {}).get("IfServerChan", False): - userServerChanKey = user_data.get("Notify", {}).get( - "ServerChanKey" - ) - userServerChanTag = user_data.get("Notify", {}).get( - "ServerChanTag" - ) - userServerChanChannel = user_data.get("Notify", {}).get( - "ServerChanChannel" - ) - if userServerChanKey: - Notify.ServerChanPush( - title, - "好羡慕~\n\nAUTO_MAA 敬上", - userServerChanKey, - userServerChanTag, - userServerChanChannel, - ) - else: - logger.error( - f"{self.name} |用户ServerChan密钥为空,无法发送用户单独的ServerChan通知" - ) + # 发送ServerChan通知 + if user_data["Notify"]["IfServerChan"]: - # 推送CompanyWebHookBot通知 - if user_data.get("Notify", {}).get("IfCompanyWebHookBot", False): - userCompanyWebHookBotUrl = user_data.get("Notify", {}).get( - "CompanyWebHookBotUrl" + if user_data["Notify"]["ServerChanKey"]: + Notify.ServerChanPush( + title, + "好羡慕~\n\nAUTO_MAA 敬上", + user_data["Notify"]["ServerChanKey"], + user_data["Notify"]["ServerChanTag"], + user_data["Notify"]["ServerChanChannel"], + ) + else: + logger.error( + f"{self.name} |用户ServerChan密钥为空,无法发送用户单独的ServerChan通知" + ) + + # 推送CompanyWebHookBot通知 + if user_data["Notify"]["IfCompanyWebHookBot"]: + if user_data["Notify"]["CompanyWebHookBotUrl"]: + Notify.CompanyWebHookBotPush( + title, + "好羡慕~\n\nAUTO_MAA 敬上", + user_data["Notify"]["CompanyWebHookBotUrl"], + ) + else: + logger.error( + f"{self.name} |用户CompanyWebHookBot密钥为空,无法发送用户单独的CompanyWebHookBot通知" ) - if userCompanyWebHookBotUrl: - Notify.CompanyWebHookBotPush( - title, - "好羡慕~\n\nAUTO_MAA 敬上", - userCompanyWebHookBotUrl, - ) - else: - logger.error( - f"{self.name} |用户CompanyWebHookBot密钥为空,无法发送用户单独的CompanyWebHookBot通知" - ) return None diff --git a/app/ui/Widget.py b/app/ui/Widget.py index cf21c1d..2647da6 100644 --- a/app/ui/Widget.py +++ b/app/ui/Widget.py @@ -1003,22 +1003,27 @@ class UserNoticeSettingCard(PushAndSwitchButtonSettingCard): return f"{s[:4]}***{s[-4:]}" if len(s) > 8 else s elif s.startswith(("http://", "https://")): - # Webhook URL:域名 + 路径尾4 + # Webhook URL:域名前5 + 路径尾5 parsed_url = urlparse(s) - domain = parsed_url.netloc + domain = ( + parsed_url.netloc[:5] + if len(parsed_url.netloc) > 5 + else parsed_url.netloc + ) path_tail = ( - parsed_url.path[-4:] - if len(parsed_url.path) > 4 + parsed_url.path[-5:] + if len(parsed_url.path) > 5 else parsed_url.path ) - return f"{domain}" + return f"{domain}......{path_tail}" elif "@" in s: - # # 邮箱:显示@前最多3字符 + 域名 - # username, domain = s.split("@", 1) - # displayed_name = username[-3:] if len(username) > 3 else username - # 邮箱展示全部 - return f"{s}" + # 邮箱:@前4/7 + 域名 + username, domain = s.split("@", 1) + displayed_name = ( + f"{username[:4]}......" if len(username) > 7 else username + ) + return f"{displayed_name}@{domain}" else: # 普通字符串:末尾3字符 diff --git a/resources/version.json b/resources/version.json index f1dea9d..8bc0c5c 100644 --- a/resources/version.json +++ b/resources/version.json @@ -1,6 +1,11 @@ { - "main_version": "4.3.8.3", + "main_version": "4.3.8.4", "version_info": { + "4.3.8.4": { + "新增功能": [ + "支持为每一个用户执行独立通知" + ] + }, "4.3.8.3": { "新增功能": [ "用户仪表盘支持直接控制用户状态" From fac85a889f93c09b18f789a804389646d733fe63 Mon Sep 17 00:00:00 2001 From: DLmaster361 Date: Sat, 24 May 2025 18:33:46 +0800 Subject: [PATCH 10/10] =?UTF-8?q?fix(ui):=20=E7=AE=80=E5=8D=95=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=94=A8=E6=88=B7=E9=80=9A=E7=9F=A5=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ui/Widget.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/app/ui/Widget.py b/app/ui/Widget.py index 2647da6..fa6eca5 100644 --- a/app/ui/Widget.py +++ b/app/ui/Widget.py @@ -1003,26 +1003,20 @@ class UserNoticeSettingCard(PushAndSwitchButtonSettingCard): return f"{s[:4]}***{s[-4:]}" if len(s) > 8 else s elif s.startswith(("http://", "https://")): - # Webhook URL:域名前5 + 路径尾5 + # Webhook URL:域名 + 路径尾3 parsed_url = urlparse(s) - domain = ( - parsed_url.netloc[:5] - if len(parsed_url.netloc) > 5 - else parsed_url.netloc - ) + domain = parsed_url.netloc path_tail = ( - parsed_url.path[-5:] - if len(parsed_url.path) > 5 + parsed_url.path[-3:] + if len(parsed_url.path) > 3 else parsed_url.path ) - return f"{domain}......{path_tail}" + return f"{domain}***{path_tail}" elif "@" in s: - # 邮箱:@前4/7 + 域名 + # 邮箱:@前3/6 + 域名 username, domain = s.split("@", 1) - displayed_name = ( - f"{username[:4]}......" if len(username) > 7 else username - ) + displayed_name = f"{username[:3]}***" if len(username) > 6 else username return f"{displayed_name}@{domain}" else: