Files
diary-family/submit_summary_tool.py

451 lines
17 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""
汇总记录提交工具 - PySide6 GUI版本
用于向家庭日报系统提交汇总记录
"""
import sys
import socket
import psutil
import requests
import json
import os
from datetime import datetime
from PySide6.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QLineEdit, QPushButton, QTextEdit, QGroupBox, QFormLayout,
QMessageBox, QSystemTrayIcon, QMenu, QStatusBar, QProgressBar,
QSpinBox, QComboBox
)
from PySide6.QtCore import QTimer, Qt, QSettings
from PySide6.QtGui import QIcon, QAction
class SubmitSummaryTool(QMainWindow):
"""汇总记录提交工具主窗口"""
def __init__(self):
super().__init__()
self.setWindowTitle("汇总记录提交工具")
self.setMinimumSize(600, 500)
self.resize(700, 550)
self.settings = QSettings("DiaryFamily", "SubmitSummaryTool")
self.load_settings()
self.init_ui()
self.setup_tray()
self.start_auto_refresh()
def load_settings(self):
"""加载保存的设置"""
self.server_url = self.settings.value("server_url", "http://localhost:8000")
self.auto_submit = self.settings.value("auto_submit", False, type=bool)
self.submit_interval = self.settings.value("submit_interval", 60, type=int)
self.auto_start = self.settings.value("auto_start", True, type=bool)
def save_settings(self):
"""保存设置"""
self.settings.setValue("server_url", self.server_url)
self.settings.setValue("auto_submit", self.auto_submit)
self.settings.setValue("submit_interval", self.submit_interval)
self.settings.setValue("auto_start", self.auto_start)
def init_ui(self):
"""初始化UI"""
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
main_layout.setSpacing(10)
self.create_server_config_group(main_layout)
self.create_system_info_group(main_layout)
self.create_manual_submit_group(main_layout)
self.create_log_group(main_layout)
self.create_status_bar()
self.create_actions()
self.statusBar().showMessage("就绪")
self.refresh_system_info()
def create_server_config_group(self, parent_layout):
"""服务器配置组"""
group = QGroupBox("服务器配置")
layout = QFormLayout()
layout.setSpacing(10)
self.server_url_edit = QLineEdit()
self.server_url_edit.setPlaceholderText("http://your-server:8000")
self.server_url_edit.setText(self.server_url)
self.server_url_edit.textChanged.connect(self.on_url_changed)
self.auto_submit_check = QPushButton("自动提交")
self.auto_submit_check.setCheckable(True)
self.auto_submit_check.setChecked(self.auto_submit)
self.auto_submit_check.toggled.connect(self.on_auto_submit_toggled)
self.interval_spin = QSpinBox()
self.interval_spin.setRange(10, 3600)
self.interval_spin.setValue(self.submit_interval)
self.interval_spin.setSuffix("")
self.interval_spin.valueChanged.connect(self.on_interval_changed)
self.test_connection_btn = QPushButton("测试连接")
self.test_connection_btn.clicked.connect(self.test_connection)
interval_layout = QHBoxLayout()
interval_layout.addWidget(self.auto_submit_check)
interval_layout.addWidget(self.interval_spin)
interval_layout.addStretch()
layout.addRow("服务器地址:", self.server_url_edit)
layout.addRow("自动提交:", interval_layout)
layout.addRow("", self.test_connection_btn)
group.setLayout(layout)
parent_layout.addWidget(group)
def create_system_info_group(self, parent_layout):
"""系统信息组"""
group = QGroupBox("系统监控信息")
layout = QFormLayout()
layout.setSpacing(8)
self.cpu_label = QLabel("0%")
self.memory_label = QLabel("0%")
self.disk_label = QLabel("0%")
self.hostname_label = QLabel()
self.ip_label = QLabel()
self.timestamp_label = QLabel()
self.cpu_progress = QProgressBar()
self.cpu_progress.setRange(0, 100)
self.memory_progress = QProgressBar()
self.memory_progress.setRange(0, 100)
self.disk_progress = QProgressBar()
self.disk_progress.setRange(0, 100)
layout.addRow("CPU使用率:", self.cpu_progress)
layout.addRow("内存使用率:", self.memory_progress)
layout.addRow("磁盘使用率:", self.disk_progress)
layout.addRow("主机名:", self.hostname_label)
layout.addRow("IP地址:", self.ip_label)
layout.addRow("更新时间:", self.timestamp_label)
refresh_btn = QPushButton("刷新")
refresh_btn.clicked.connect(self.refresh_system_info)
btn_layout = QHBoxLayout()
btn_layout.addWidget(refresh_btn)
btn_layout.addStretch()
layout.addRow("", btn_layout)
group.setLayout(layout)
parent_layout.addWidget(group)
def create_manual_submit_group(self, parent_layout):
"""手动提交组"""
group = QGroupBox("手动提交")
layout = QVBoxLayout()
layout.setSpacing(10)
self.content_edit = QTextEdit()
self.content_edit.setPlaceholderText("输入要提交的内容...")
self.content_edit.setMaximumHeight(100)
submit_btn = QPushButton("提交汇总记录")
submit_btn.clicked.connect(self.manual_submit)
layout.addWidget(self.content_edit)
layout.addWidget(submit_btn)
group.setLayout(layout)
parent_layout.addWidget(group)
def create_log_group(self, parent_layout):
"""日志组"""
group = QGroupBox("运行日志")
layout = QVBoxLayout()
layout.setSpacing(5)
self.log_edit = QTextEdit()
self.log_edit.setReadOnly(True)
self.log_edit.setMaximumHeight(150)
clear_btn = QPushButton("清除日志")
clear_btn.clicked.connect(self.log_edit.clear)
layout.addWidget(self.log_edit)
layout.addWidget(clear_btn, alignment=Qt.AlignRight)
group.setLayout(layout)
parent_layout.addWidget(group)
def create_status_bar(self):
"""创建状态栏"""
self.status_label = QLabel("就绪")
self.statusBar().addPermanentWidget(self.status_label)
def create_actions(self):
"""创建菜单动作"""
self.refresh_action = QAction("刷新", self)
self.refresh_action.triggered.connect(self.refresh_system_info)
self.submit_action = QAction("提交", self)
self.submit_action.triggered.connect(self.manual_submit)
self.quit_action = QAction("退出", self)
self.quit_action.triggered.connect(self.close)
def setup_tray(self):
"""设置系统托盘"""
if QSystemTrayIcon.isSystemTrayAvailable():
self.tray_icon = QSystemTrayIcon(self)
self.tray_icon.setToolTip("汇总记录提交工具")
tray_menu = QMenu()
tray_menu.addAction(self.refresh_action)
tray_menu.addAction(self.submit_action)
tray_menu.addSeparator()
tray_menu.addAction(self.quit_action)
self.tray_icon.setContextMenu(tray_menu)
self.tray_icon.show()
self.tray_icon.activated.connect(self.on_tray_activated)
def on_tray_activated(self, reason):
"""托盘图标激活处理"""
if reason == QSystemTrayIcon.DoubleClick:
self.show()
self.raise_()
self.activateWindow()
def start_auto_refresh(self):
"""启动自动刷新"""
self.timer = QTimer(self)
self.timer.timeout.connect(self.auto_refresh_cycle)
self.timer.start(self.submit_interval * 1000 if self.auto_submit else 5000)
def auto_refresh_cycle(self):
"""自动刷新周期"""
self.refresh_system_info()
if self.auto_submit:
self.auto_submit_content()
def refresh_system_info(self):
"""刷新系统信息"""
try:
cpu = psutil.cpu_percent(interval=None)
memory = psutil.virtual_memory()
disk = psutil.disk_usage('/')
hostname = socket.gethostname()
ip = socket.gethostbyname(hostname)
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
self.cpu_progress.setValue(int(cpu))
self.memory_progress.setValue(int(memory.percent))
self.disk_progress.setValue(int(disk.percent))
self.hostname_label.setText(hostname)
self.ip_label.setText(ip)
self.timestamp_label.setText(timestamp)
self.log(f"系统信息已刷新 - CPU: {cpu}%, 内存: {memory.percent}%, 磁盘: {disk.percent}%")
except Exception as e:
self.log(f"获取系统信息失败: {str(e)}")
def get_system_content(self):
"""获取系统监控内容"""
info = self.get_system_info()
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
return f"[系统监控 {timestamp}] CPU使用率: {info['cpu']}%, 内存使用率: {info['memory']}%, 磁盘使用率: {info['disk']}%"
def auto_submit_content(self):
"""自动提交系统监控内容"""
content = self.get_system_content()
self.submit_summary(content)
def manual_submit(self):
"""手动提交"""
content = self.content_edit.toPlainText().strip()
if not content:
QMessageBox.warning(self, "警告", "请输入要提交的内容")
return
self.submit_summary(content)
self.content_edit.clear()
def get_csrf_token(self):
"""获取CSRF token"""
try:
session = requests.Session()
get_url = f"{self.server_url}/"
self.log(f"正在访问首页获取CSRF token: {get_url}")
response = session.get(get_url, timeout=10)
self.log(f"首页响应状态码: {response.status_code}")
cookies = session.cookies.get_dict()
self.log(f"收到的Cookies: {list(cookies.keys())}")
csrf_token = cookies.get('csrftoken')
if csrf_token:
self.log(f"获取CSRF token成功: {csrf_token[:20]}...")
return session, csrf_token
else:
self.log("警告: 未获取到CSRF tokencookie中可能没有csrftoken")
self.log(f"所有cookies: {cookies}")
return session, None
except Exception as e:
self.log(f"获取CSRF token失败: {str(e)}")
return None, None
def submit_summary(self, content):
"""提交汇总记录到家庭日报系统"""
submit_url = f"{self.server_url}/api/v1/summary/submit/"
try:
self.status_label.setText("正在提交...")
session, csrf_token = self.get_csrf_token()
if session is None:
self.log("错误: 无法建立会话,连接可能失败")
self.status_label.setText("连接失败")
QMessageBox.critical(self, "错误", "无法连接到服务器请检查URL是否正确")
return
headers = {
'Referer': self.server_url,
}
if csrf_token:
headers['X-CSRFToken'] = csrf_token
self.log(f"设置CSRF header: X-CSRFToken = {csrf_token[:20]}...")
self.log(f"发送POST请求到: {submit_url}")
response = session.post(submit_url, data={'content': content}, headers=headers, timeout=10)
self.log(f"服务器响应状态码: {response.status_code}")
self.log(f"响应Headers: {dict(response.headers)}")
self.log(f"响应内容: {response.text[:200]}...")
if response.status_code != 200:
error_msg = f"服务器返回错误: HTTP {response.status_code}"
self.log(error_msg)
self.status_label.setText(f"错误: {response.status_code}")
QMessageBox.critical(self, "错误", f"{error_msg}\n\n响应内容:\n{response.text[:500]}")
return
try:
result = response.json()
except json.JSONDecodeError as e:
error_msg = f"JSON解析失败: {str(e)}\n响应内容: {response.text[:200]}"
self.log(error_msg)
self.status_label.setText("JSON解析失败")
QMessageBox.critical(self, "错误", error_msg)
return
if result['success']:
self.log(f"提交成功记录ID: {result['id']}")
self.status_label.setText("提交成功")
QMessageBox.information(self, "成功", f"提交成功记录ID: {result['id']}")
else:
self.log(f"提交失败: {result['message']}")
self.status_label.setText(f"失败: {result['message']}")
QMessageBox.warning(self, "失败", f"提交失败: {result['message']}")
except requests.exceptions.ConnectionError as e:
error_msg = f"连接失败: 无法连接到 {submit_url}"
self.log(error_msg)
self.status_label.setText("连接失败")
QMessageBox.critical(self, "错误", error_msg)
except requests.exceptions.Timeout:
error_msg = "请求超时,请检查服务器是否正常运行"
self.log(error_msg)
self.status_label.setText("连接超时")
QMessageBox.critical(self, "错误", error_msg)
except Exception as e:
error_msg = f"请求异常: {str(e)}"
self.log(error_msg)
self.status_label.setText("请求异常")
QMessageBox.critical(self, "错误", error_msg)
def test_connection(self):
"""测试服务器连接"""
url = self.server_url.rstrip('/') + "/api/v1/summary/submit/"
try:
self.status_label.setText("测试连接中...")
response = requests.get(url.replace('/submit/', '/'), timeout=5)
self.log(f"连接测试: 服务器响应状态码 {response.status_code}")
self.status_label.setText("连接成功")
QMessageBox.information(self, "成功", "服务器连接成功")
except requests.exceptions.ConnectionError:
self.log("连接测试: 无法连接到服务器")
self.status_label.setText("连接失败")
QMessageBox.warning(self, "失败", "无法连接到服务器请检查URL是否正确")
except Exception as e:
self.log(f"连接测试: {str(e)}")
self.status_label.setText("测试异常")
QMessageBox.critical(self, "错误", f"测试失败: {str(e)}")
def get_system_info(self):
"""获取系统基本信息"""
try:
cpu_percent = psutil.cpu_percent(interval=1)
memory = psutil.virtual_memory()
disk = psutil.disk_usage('/')
return {
'cpu': cpu_percent,
'memory': memory.percent,
'disk': disk.percent
}
except Exception as e:
self.log(f"获取系统信息失败: {str(e)}")
return {'cpu': 0, 'memory': 0, 'disk': 0}
def log(self, message):
"""记录日志"""
timestamp = datetime.now().strftime('%H:%M:%S')
log_message = f"[{timestamp}] {message}"
self.log_edit.append(log_message)
print(log_message)
def on_url_changed(self, url):
"""URL改变处理"""
self.server_url = url
def on_auto_submit_toggled(self, checked):
"""自动提交开关处理"""
self.auto_submit = checked
if checked:
self.log("已启用自动提交")
else:
self.log("已禁用自动提交")
def on_interval_changed(self, value):
"""刷新间隔改变处理"""
self.submit_interval = value
self.timer.setInterval(value * 1000 if self.auto_submit else 5000)
self.log(f"刷新间隔已设置为 {value}")
def closeEvent(self, event):
"""关闭窗口事件"""
self.save_settings()
self.log("正在保存设置...")
event.accept()
def main():
app = QApplication(sys.argv)
app.setStyle('Fusion')
window = SubmitSummaryTool()
if window.auto_start:
window.show()
else:
window.showMinimized()
sys.exit(app.exec())
if __name__ == "__main__":
main()