From 7657e1b2fa251a2ea372710ad75cb395a3c0e374 Mon Sep 17 00:00:00 2001
From: hyb <kk_huangyangbo@163.com>
Date: Fri, 30 Jan 2026 07:15:55 +0000
Subject: [PATCH] feat: 新增将两种加密方式合并一个脚本、新增批量修改邮箱功能

---
 测试组/脚本/Change_password/数据库密码批量修改工具(合并版).py |  191 +++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 165 insertions(+), 26 deletions(-)

diff --git "a/\346\265\213\350\257\225\347\273\204/\350\204\232\346\234\254/Change_password/\346\225\260\346\215\256\345\272\223\345\257\206\347\240\201\346\211\271\351\207\217\344\277\256\346\224\271\345\267\245\345\205\267\357\274\210\345\220\210\345\271\266\347\211\210\357\274\211.py" "b/\346\265\213\350\257\225\347\273\204/\350\204\232\346\234\254/Change_password/\346\225\260\346\215\256\345\272\223\345\257\206\347\240\201\346\211\271\351\207\217\344\277\256\346\224\271\345\267\245\345\205\267\357\274\210\345\220\210\345\271\266\347\211\210\357\274\211.py"
index 90f2afa..2d0b0d5 100644
--- "a/\346\265\213\350\257\225\347\273\204/\350\204\232\346\234\254/Change_password/\346\225\260\346\215\256\345\272\223\345\257\206\347\240\201\346\211\271\351\207\217\344\277\256\346\224\271\345\267\245\345\205\267\357\274\210\345\220\210\345\271\266\347\211\210\357\274\211.py"
+++ "b/\346\265\213\350\257\225\347\273\204/\350\204\232\346\234\254/Change_password/\346\225\260\346\215\256\345\272\223\345\257\206\347\240\201\346\211\271\351\207\217\344\277\256\346\224\271\345\267\245\345\205\267\357\274\210\345\220\210\345\271\266\347\211\210\357\274\211.py"
@@ -198,14 +198,15 @@
     error_signal = pyqtSignal(str)
     export_finished_signal = pyqtSignal(str)
 
-    def __init__(self, excel_path, new_password, mode, hash_mode, user_filter=None, selected_projects=None):
+    def __init__(self, excel_path, new_value, mode, hash_mode, user_filter=None, selected_projects=None, modify_type='password'):
         super().__init__()
         self.excel_path = excel_path
-        self.new_password = new_password
+        self.new_value = new_value  # 新密码或新邮箱
         self.mode = mode  # 'all' 或 'specific'
         self.hash_mode = hash_mode  # 'bcrypt' 或 'argon2id'
         self.user_filter = user_filter
         self.selected_projects = selected_projects
+        self.modify_type = modify_type  # 'password' 或 'email'
         self.updaters = []
         self.log_records = []
         self.is_running = True
@@ -250,7 +251,7 @@
             for _, row in df_filtered.iterrows():
                 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.hash_mode)
+                updater = ProjectUpdater(project, host, database, user, password, port, self.hash_mode, self.modify_type)
                 self.updaters.append(updater)
 
             # 执行更新任务
@@ -262,10 +263,16 @@
                 self.log_signal.emit(f"正在处理项目: {updater.project}")
 
                 # 运行更新
-                success = updater.update_database(
-                    user_filter=self.user_filter if self.mode == 'specific' else None,
-                    new_password=self.new_password
-                )
+                if self.modify_type == 'password':
+                    success = updater.update_database(
+                        user_filter=self.user_filter if self.mode == 'specific' else None,
+                        new_password=self.new_value
+                    )
+                else:
+                    success = updater.update_email(
+                        user_filter=self.user_filter if self.mode == 'specific' else None,
+                        new_email=self.new_value
+                    )
 
                 if success:
                     self.log_records.extend(updater.log_records)
@@ -332,7 +339,7 @@
             conn = updater.connect()
             if conn:
                 cursor = conn.cursor()
-                success = updater.export_user_info(cursor, self.new_password)
+                success = updater.export_user_info(cursor, self.new_value)
                 cursor.close()
                 conn.close()
 
@@ -350,7 +357,7 @@
 class ProjectUpdater:
     """单个项目更新器"""
 
-    def __init__(self, project, host, database, user, password, port=3306, hash_mode='bcrypt'):
+    def __init__(self, project, host, database, user, password, port=3306, hash_mode='bcrypt', modify_type='password'):
         self.project = project
         self.host = host
         self.database = database
@@ -358,6 +365,7 @@
         self.db_password = password
         self.port = port
         self.hash_mode = hash_mode  # 'bcrypt' 或 'argon2id'
+        self.modify_type = modify_type  # 'password' 或 'email'
         self.updated_users = []
         self.log_records = []
 
@@ -448,7 +456,7 @@
         except Error:
             return "获取失败"
 
-    def export_user_info(self, cursor, new_password):
+    def export_user_info(self, cursor, new_value):
         """导出用户信息到Excel"""
         try:
             if not self.updated_users:
@@ -469,21 +477,32 @@
             # 准备导出数据
             export_data = []
             for user in self.updated_users:
-                export_data.append({
-                    '用户名': user['login_name'],
-                    '密码': new_password,
-                    '姓名': user['name'],
-                    '角色名称': role_name_map.get(user['role_id'], '无角色')
-                })
+                if self.modify_type == 'password':
+                    export_data.append({
+                        '用户名': user['login_name'],
+                        '密码': new_value,
+                        '姓名': user['name'],
+                        '角色名称': role_name_map.get(user['role_id'], '无角色')
+                    })
+                else:  # 修改邮箱
+                    export_data.append({
+                        '用户名': user['login_name'],
+                        '邮箱': new_value,
+                        '姓名': user['name'],
+                        '角色名称': role_name_map.get(user['role_id'], '无角色')
+                    })
 
             # 创建DataFrame并导出
             df_export = pd.DataFrame(export_data)
 
-            # 按照要求格式化文件名:项目名称测试环境账号密码_年月日
-            safe_project_name = re.sub(r'[\\/*?:"<>|]', "", self.project)
+            # 按照要求格式化文件名
+            safe_project_name = re.sub(r'[\/*?:"<>|]', "", self.project)
             safe_project_name = safe_project_name.replace(" ", "_")
             date_str = datetime.now().strftime("%Y%m%d")
-            filename = f"{safe_project_name}测试环境账号密码_{date_str}.xlsx"
+            if self.modify_type == 'password':
+                filename = f"{safe_project_name}测试环境账号密码_{date_str}.xlsx"
+            else:  # 修改邮箱
+                filename = f"{safe_project_name}测试环境账号邮箱_{date_str}.xlsx"
             filepath = os.path.join(DEFAULT_EXPORT_DIR, filename)
 
             df_export.to_excel(filepath, index=False)
@@ -555,6 +574,72 @@
             if conn:
                 conn.close()
 
+    def update_email(self, user_filter=None, new_email=''):
+        """更新数据库中的用户邮箱"""
+        conn = None
+        cursor = None
+        try:
+            conn = self.connect()
+            if not conn:
+                return False
+
+            # 使用同步方式创建游标
+            cursor = conn.cursor()
+
+            # 获取需要更新的用户
+            users = self.get_users_to_update(cursor, user_filter)
+
+            if not users:
+                return False
+
+            # 更新每个用户的邮箱
+            for uid, login_name, name, current_role_id in users:
+                success = self.update_user_email(cursor, uid, login_name, new_email)
+
+                if success:
+                    # 记录更新成功的用户信息
+                    self.updated_users.append({
+                        'id': uid,
+                        'login_name': login_name,
+                        'name': name,
+                        'role_id': current_role_id
+                    })
+
+                    # 写入日志
+                    self.log_records.append({
+                        '项目': self.project,
+                        '数据库': self.database,
+                        '用户ID': uid,
+                        '用户名': login_name,
+                        '新邮箱': new_email
+                    })
+
+            # 提交事务
+            conn.commit()
+            return True
+
+        except Error:
+            return False
+        finally:
+            if cursor:
+                cursor.close()
+            if conn:
+                conn.close()
+
+    def update_user_email(self, cursor, user_id, login_name, new_email):
+        """更新用户邮箱"""
+        try:
+            # 构造更新 SQL
+            update_sql = """
+                UPDATE sys_user
+                SET email = %s
+                WHERE id = %s
+            """
+            cursor.execute(update_sql, (new_email, user_id))
+            return True
+        except Error:
+            return False
+
 
 class PasswordUpdaterApp(QMainWindow):
     """主应用程序窗口"""
@@ -593,6 +678,24 @@
         excel_layout.addWidget(excel_browse_btn)
         config_layout.addWidget(excel_group)
 
+        # 修改类型选择
+        modify_type_group = QGroupBox("修改类型")
+        modify_type_layout = QVBoxLayout(modify_type_group)
+        
+        self.modify_type_group = QButtonGroup()
+        self.modify_password_radio = QRadioButton("修改密码")
+        self.modify_email_radio = QRadioButton("修改邮箱")
+        
+        # 默认选择修改密码
+        self.modify_password_radio.setChecked(True)
+        
+        self.modify_type_group.addButton(self.modify_password_radio)
+        self.modify_type_group.addButton(self.modify_email_radio)
+        
+        modify_type_layout.addWidget(self.modify_password_radio)
+        modify_type_layout.addWidget(self.modify_email_radio)
+        config_layout.addWidget(modify_type_group)
+
         # 新密码设置
         password_group = QGroupBox("新密码设置")
         password_layout = QHBoxLayout(password_group)
@@ -601,6 +704,16 @@
         password_layout.addWidget(QLabel("新密码:"))
         password_layout.addWidget(self.password_edit)
         config_layout.addWidget(password_group)
+
+        # 新邮箱设置
+        email_group = QGroupBox("新邮箱设置")
+        email_layout = QHBoxLayout(email_group)
+        self.email_edit = QLineEdit()
+        self.email_edit.setPlaceholderText("请输入新邮箱")
+        self.email_edit.setEnabled(False)  # 默认禁用
+        email_layout.addWidget(QLabel("新邮箱:"))
+        email_layout.addWidget(self.email_edit)
+        config_layout.addWidget(email_group)
 
         # 加密方式选择
         hash_group = QGroupBox("加密方式选择")
@@ -647,6 +760,10 @@
             lambda: self.usernames_edit.setEnabled(not self.all_users_radio.isChecked()))
         self.specific_users_radio.toggled.connect(
             lambda: self.usernames_edit.setEnabled(self.specific_users_radio.isChecked()))
+        
+        # 修改类型选择信号
+        self.modify_password_radio.toggled.connect(self.on_modify_type_changed)
+        self.modify_email_radio.toggled.connect(self.on_modify_type_changed)
 
         mode_layout.addWidget(self.all_users_radio)
         mode_layout.addWidget(self.specific_users_radio)
@@ -742,20 +859,31 @@
                 return
             user_filter = [name.strip() for name in usernames.replace(',', ',').split(',')]
 
-        # 获取新密码
-        new_password = self.password_edit.text()
-        if not new_password:
-            QMessageBox.warning(self, "错误", "请输入新密码")
-            return
+        # 获取修改类型
+        modify_type = 'password' if self.modify_password_radio.isChecked() else 'email'
+        
+        # 获取新密码或新邮箱
+        new_value = ''
+        if modify_type == 'password':
+            new_value = self.password_edit.text()
+            if not new_value:
+                QMessageBox.warning(self, "错误", "请输入新密码")
+                return
+        else:
+            new_value = self.email_edit.text()
+            if not new_value:
+                QMessageBox.warning(self, "错误", "请输入新邮箱")
+                return
 
         # 创建并启动更新线程
         self.updater_thread = DatabaseUpdater(
             self.excel_path_edit.text(),
-            new_password,
+            new_value,
             mode,
             hash_mode,
             user_filter,
-            selected_projects
+            selected_projects,
+            modify_type
         )
 
         # 连接信号
@@ -801,6 +929,17 @@
             self.log_text.append(f"开始导出项目 {project_name} 的用户信息...")
             self.updater_thread.export_user_info(project_name)
 
+    def on_modify_type_changed(self):
+        """修改类型变更时的处理"""
+        is_modify_password = self.modify_password_radio.isChecked()
+        # 启用或禁用密码相关控件
+        self.password_edit.setEnabled(is_modify_password)
+        # 启用或禁用邮箱相关控件
+        self.email_edit.setEnabled(not is_modify_password)
+        # 启用或禁用加密方式选择
+        self.bcrypt_radio.setEnabled(is_modify_password)
+        self.argon2id_radio.setEnabled(is_modify_password)
+
     def show_error(self, error_msg):
         """显示错误信息"""
         QMessageBox.critical(self, "错误", error_msg)

--
Gitblit v1.9.1