#!/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) source_layout = QHBoxLayout() source_layout.addWidget(QLabel("来源:")) self.source_edit = QLineEdit() self.source_edit.setPlaceholderText("留空则自动生成") source_layout.addWidget(self.source_edit) submit_btn = QPushButton("提交汇总记录") submit_btn.clicked.connect(self.manual_submit) layout.addWidget(self.content_edit) layout.addLayout(source_layout) 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, source=None) def manual_submit(self): """手动提交""" content = self.content_edit.toPlainText().strip() if not content: QMessageBox.warning(self, "警告", "请输入要提交的内容") return source = self.source_edit.text().strip() self.submit_summary(content, source) 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 token,cookie中可能没有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, source=""): """提交汇总记录到家庭日报系统""" 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}") post_data = {'content': content} if source: post_data['source'] = source self.log(f"提交来源: {source}") response = session.post(submit_url, data=post_data, 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()