| | |
| | | from datetime import datetime |
| | | from typing import List, Dict, Any, Optional |
| | | import re |
| | | import locale |
| | | from PyQt5 import QtWidgets, QtCore, QtGui |
| | | from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, |
| | | QLabel, QLineEdit, QPushButton, QTextEdit, QListWidget, |
| | | QListWidgetItem, QCheckBox, QFileDialog, QMessageBox, QProgressBar, |
| | | QGroupBox, QRadioButton, QButtonGroup, QTabWidget) |
| | | from PyQt5.QtCore import Qt, pyqtSignal, QThread |
| | | |
| | | # 【重要】在程序最开始就设置环境变量,避免任何pandas操作之前出现本地化问题 |
| | | # 强制设置为C语言环境,这是最安全的通用设置 |
| | | os.environ['LANG'] = 'C' |
| | | os.environ['LC_ALL'] = 'C' |
| | | os.environ['LC_CTYPE'] = 'C' |
| | | os.environ['LC_NUMERIC'] = 'C' |
| | | os.environ['LC_TIME'] = 'C' |
| | | os.environ['LC_COLLATE'] = 'C' |
| | | os.environ['LC_MONETARY'] = 'C' |
| | | os.environ['LC_MESSAGES'] = 'C' |
| | | os.environ['LC_PAPER'] = 'C' |
| | | os.environ['LC_NAME'] = 'C' |
| | | os.environ['LC_ADDRESS'] = 'C' |
| | | os.environ['LC_TELEPHONE'] = 'C' |
| | | os.environ['LC_MEASUREMENT'] = 'C' |
| | | os.environ['LC_IDENTIFICATION'] = 'C' |
| | | os.environ['PANDAS_USAGE_STATS'] = 'False' |
| | | |
| | | # 尝试设置locale,但如果失败也不影响,因为已经设置了环境变量 |
| | | try: |
| | | locale.setlocale(locale.LC_ALL, 'C') |
| | | except Exception: |
| | | pass |
| | | |
| | | # 不再设置pandas选项,避免因版本差异导致的错误 |
| | | # 只保留必要的环境变量设置,确保本地化不会出现问题 |
| | | |
| | | # 判断是否是打包后的可执行文件 |
| | | if getattr(sys, 'frozen', False): |
| | |
| | | # 遍历所有数据库并刷新 |
| | | for db_index in range(db_count): |
| | | try: |
| | | # 切换到指定数据库 |
| | | temp_client = self.redis_client.connection_pool.get_connection() |
| | | temp_client.send_command('SELECT', db_index) |
| | | temp_client.read_response() |
| | | |
| | | # 创建一个临时Redis客户端来操作指定数据库 |
| | | import redis |
| | | temp_client = redis.Redis( |
| | | host=REDIS_HOST, |
| | | port=REDIS_PORT, |
| | | password=REDIS_PASSWORD, |
| | | db=db_index, |
| | | decode_responses=True |
| | | ) |
| | | |
| | | # 获取当前数据库的key数量 |
| | | temp_client.send_command('DBSIZE') |
| | | key_count = temp_client.read_response() |
| | | key_count = temp_client.dbsize() |
| | | |
| | | if key_count > 0: |
| | | # 清空当前数据库 |
| | | temp_client.send_command('FLUSHDB') |
| | | temp_client.read_response() |
| | | temp_client.flushdb() |
| | | refreshed_dbs += 1 |
| | | total_keys += key_count |
| | | print(f"已刷新数据库 {db_index}: 清除了 {key_count} 个键") |
| | | |
| | | self.redis_client.connection_pool.release(temp_client) |
| | | |
| | | except Exception as e: |
| | | print(f"刷新数据库 {db_index} 时出错: {str(e)}") |
| | |
| | | def run(self): |
| | | """主运行方法""" |
| | | try: |
| | | # 保存日志时可能会出现本地化问题,这里临时设置环境变量 |
| | | original_lang = os.environ.get('LANG') |
| | | original_lc_all = os.environ.get('LC_ALL') |
| | | |
| | | # 强制设置为C语言环境,避免pandas本地化问题 |
| | | os.environ['LANG'] = 'C' |
| | | os.environ['LC_ALL'] = 'C' |
| | | |
| | | # 读取 Excel 数据 |
| | | try: |
| | | df = pd.read_excel(self.excel_path) |
| | |
| | | # 创建数据库更新器实例 |
| | | self.updaters = [] |
| | | for _, row in df_filtered.iterrows(): |
| | | project, host, database, user, password = row[:5] |
| | | self.log_signal.emit(f"准备处理项目:{project} | 数据库:{database}") |
| | | updater = ProjectUpdater(project, host, database, user, password) |
| | | project, host, port, database, user, password = row[:6] |
| | | self.log_signal.emit(f"准备处理项目:{project} | 数据库:{database} | 端口:{port}") |
| | | updater = ProjectUpdater(project, host, database, user, password, port) |
| | | self.updaters.append(updater) |
| | | |
| | | # 执行更新任务 |
| | |
| | | |
| | | # 保存日志 |
| | | if self.log_records: |
| | | pd.DataFrame(self.log_records).to_csv(DEFAULT_LOG_CSV_PATH, index=False, encoding='utf-8-sig') |
| | | self.log_signal.emit(f"所有更新日志已保存至 {DEFAULT_LOG_CSV_PATH}") |
| | | try: |
| | | pd.DataFrame(self.log_records).to_csv(DEFAULT_LOG_CSV_PATH, index=False, encoding='utf-8-sig') |
| | | self.log_signal.emit(f"所有更新日志已保存至 {DEFAULT_LOG_CSV_PATH}") |
| | | except Exception as e: |
| | | self.log_signal.emit(f"保存日志失败:{str(e)}") |
| | | else: |
| | | self.log_signal.emit("无任何更新记录生成") |
| | | |
| | | # 恢复原始环境变量 |
| | | if original_lang: |
| | | os.environ['LANG'] = original_lang |
| | | else: |
| | | os.environ.pop('LANG', None) |
| | | |
| | | if original_lc_all: |
| | | os.environ['LC_ALL'] = original_lc_all |
| | | else: |
| | | os.environ.pop('LC_ALL', None) |
| | | |
| | | # 数据库更新完成后,自动刷新Redis缓存 |
| | | self.log_signal.emit("开始刷新Redis缓存...") |
| | |
| | | class ProjectUpdater: |
| | | """单个项目更新器""" |
| | | |
| | | def __init__(self, project, host, database, user, password): |
| | | def __init__(self, project, host, database, user, password, port=3306): |
| | | self.project = project |
| | | self.host = host |
| | | self.database = database |
| | | self.db_user = user |
| | | self.db_password = password |
| | | self.port = port |
| | | self.updated_users = [] |
| | | self.log_records = [] |
| | | |
| | |
| | | try: |
| | | conn = mysql.connector.connect( |
| | | host=self.host, |
| | | port=3306, |
| | | port=self.port, |
| | | user=self.db_user, |
| | | password=self.db_password, |
| | | database=self.database, |