PUGE 1 ay önce
ebeveyn
işleme
7fd0346f76
3 değiştirilmiş dosya ile 1137 ekleme ve 53 silme
  1. 906 0
      87总控.py
  2. 1 1
      test.py
  3. 230 52
      解密机大侠.py

+ 906 - 0
87总控.py

@@ -0,0 +1,906 @@
+import sys
+import time
+import win32gui
+import win32con
+import win32api
+import win32process
+import threading
+from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, 
+                             QHBoxLayout, QPushButton, QListWidget, QListWidgetItem,
+                             QMessageBox, QLabel, QLineEdit, QGroupBox, QTextEdit,
+                             QSplitter, QComboBox, QSpinBox, QCheckBox, QRadioButton,
+                             QButtonGroup)
+from PyQt5.QtCore import Qt, QTimer, pyqtSignal, QObject
+from PyQt5.QtGui import QFont
+
+
+class WorkerSignals(QObject):
+    """工作线程信号"""
+    status = pyqtSignal(str)
+    progress = pyqtSignal(int, int)  # 当前索引, 总数
+    finished = pyqtSignal()
+
+
+class WindowManagerApp(QMainWindow):
+    def __init__(self):
+        super().__init__()
+        self.window_handles = []
+        self.all_windows = []
+        self.is_running = False
+        self.should_stop = False  # 停止标志
+        self.initUI()
+        
+    def initUI(self):
+        """初始化界面"""
+        self.setWindowTitle('霸器窗口自动点击工具 - 多窗口批量执行')
+        self.setGeometry(100, 100, 950, 750)
+        
+        # 设置主窗口样式
+        self.setStyleSheet("""
+            QMainWindow {
+                background-color: #2b2b2b;
+            }
+            QGroupBox {
+                color: #ffffff;
+                border: 2px solid #555;
+                border-radius: 5px;
+                margin-top: 10px;
+                font-weight: bold;
+            }
+            QGroupBox::title {
+                subcontrol-origin: margin;
+                left: 10px;
+                padding: 0 5px 0 5px;
+            }
+            QPushButton {
+                background-color: #4a4a4a;
+                color: white;
+                border: 1px solid #555;
+                padding: 8px 16px;
+                border-radius: 4px;
+                font-weight: bold;
+                font-size: 12px;
+            }
+            QPushButton:hover {
+                background-color: #5a5a5a;
+            }
+            QPushButton:pressed {
+                background-color: #3a3a3a;
+            }
+            QPushButton#refreshBtn {
+                background-color: #0078d4;
+            }
+            QPushButton#refreshBtn:hover {
+                background-color: #1a8ad4;
+            }
+            QPushButton#startBtn {
+                background-color: #107c10;
+                font-size: 14px;
+                padding: 12px 24px;
+            }
+            QPushButton#startBtn:hover {
+                background-color: #1a8c1a;
+            }
+            QPushButton#startBtn:disabled {
+                background-color: #555;
+            }
+            QPushButton#stopBtn {
+                background-color: #d13438;
+                font-size: 14px;
+                padding: 12px 24px;
+            }
+            QPushButton#stopBtn:hover {
+                background-color: #e14448;
+            }
+            QListWidget {
+                background-color: #3c3c3c;
+                color: #ffffff;
+                border: 1px solid #555;
+                border-radius: 4px;
+                padding: 5px;
+            }
+            QListWidget::item {
+                padding: 8px;
+                border-bottom: 1px solid #444;
+            }
+            QListWidget::item:selected {
+                background-color: #0078d4;
+            }
+            QLabel {
+                color: #cccccc;
+            }
+            QCheckBox {
+                color: #ffffff;
+                font-size: 12px;
+                padding: 5px;
+            }
+            QCheckBox::indicator {
+                width: 18px;
+                height: 18px;
+            }
+            QCheckBox::indicator:unchecked {
+                background-color: #3c3c3c;
+                border: 2px solid #555;
+                border-radius: 3px;
+            }
+            QCheckBox::indicator:checked {
+                background-color: #0078d4;
+                border: 2px solid #0078d4;
+                border-radius: 3px;
+            }
+            QRadioButton {
+                color: #ffffff;
+                font-size: 12px;
+                padding: 5px;
+            }
+            QRadioButton::indicator {
+                width: 18px;
+                height: 18px;
+            }
+            QRadioButton::indicator:unchecked {
+                background-color: #3c3c3c;
+                border: 2px solid #555;
+                border-radius: 9px;
+            }
+            QRadioButton::indicator:checked {
+                background-color: #0078d4;
+                border: 2px solid #0078d4;
+                border-radius: 9px;
+            }
+            QLineEdit, QComboBox, QSpinBox {
+                background-color: #3c3c3c;
+                color: #ffffff;
+                border: 1px solid #555;
+                border-radius: 4px;
+                padding: 5px;
+            }
+            QTextEdit {
+                background-color: #1e1e1e;
+                color: #00ff00;
+                border: 1px solid #555;
+                border-radius: 4px;
+                font-family: 'Consolas', monospace;
+                font-size: 10pt;
+            }
+        """)
+        
+        # 创建中央窗口
+        central_widget = QWidget()
+        self.setCentralWidget(central_widget)
+        main_layout = QVBoxLayout(central_widget)
+        
+        # 标题
+        title_label = QLabel('霸器窗口自动点击工具 - 批量执行')
+        title_label.setAlignment(Qt.AlignCenter)
+        title_font = QFont('Arial', 18, QFont.Bold)
+        title_label.setFont(title_font)
+        title_label.setStyleSheet('color: #00b4d8; margin: 15px;')
+        main_layout.addWidget(title_label)
+        
+        # 控制区域
+        control_group = QGroupBox('控制面板')
+        control_layout = QHBoxLayout()
+        
+        self.refresh_btn = QPushButton('🔄 加载窗口')
+        self.refresh_btn.setObjectName('refreshBtn')
+        self.refresh_btn.clicked.connect(self.load_processes)
+        control_layout.addWidget(self.refresh_btn)
+        
+        self.filter_label = QLabel('筛选:')
+        control_layout.addWidget(self.filter_label)
+        
+        self.filter_input = QLineEdit()
+        self.filter_input.setPlaceholderText('输入标题关键词过滤...')
+        self.filter_input.textChanged.connect(self.filter_list)
+        control_layout.addWidget(self.filter_input)
+        
+        # 显示模式选择
+        self.show_mode_combo = QComboBox()
+        self.show_mode_combo.addItems(['所有窗口', '仅可见窗口', '仅隐藏窗口'])
+        self.show_mode_combo.currentTextChanged.connect(self.on_show_mode_changed)
+        control_layout.addWidget(QLabel('显示:'))
+        control_layout.addWidget(self.show_mode_combo)
+        
+        control_group.setLayout(control_layout)
+        main_layout.addWidget(control_group)
+        
+        # 复选框区域 - 功能选择
+        checkbox_group = QGroupBox('功能选择')
+        checkbox_layout = QHBoxLayout()
+        
+        self.cb_molong = QCheckBox('争夺魔龙之心')
+        self.cb_molong.setChecked(False)
+        checkbox_layout.addWidget(self.cb_molong)
+        
+        self.cb_feicui = QCheckBox('翡翠荣耀旗')
+        self.cb_feicui.setChecked(False)
+        checkbox_layout.addWidget(self.cb_feicui)
+        
+        self.cb_jinyan = QCheckBox('金岩霸者棋')
+        self.cb_jinyan.setChecked(False)
+        checkbox_layout.addWidget(self.cb_jinyan)
+        
+        self.cb_chiyan = QCheckBox('炽焰战神棋')
+        self.cb_chiyan.setChecked(False)
+        checkbox_layout.addWidget(self.cb_chiyan)
+        
+        checkbox_group.setLayout(checkbox_layout)
+        main_layout.addWidget(checkbox_group)
+        
+        # 单选按钮区域 - 皇宫占位
+        radio_group = QGroupBox('皇宫占位位置')
+        radio_layout = QHBoxLayout()
+        
+        self.radio_random = QRadioButton('随机')
+        self.radio_random.setChecked(True)
+        radio_layout.addWidget(self.radio_random)
+        
+        self.radio_door = QRadioButton('门口')
+        radio_layout.addWidget(self.radio_door)
+        
+        self.radio_corner = QRadioButton('角落')
+        radio_layout.addWidget(self.radio_corner)
+        
+        # 将单选按钮分组
+        self.radio_button_group = QButtonGroup()
+        self.radio_button_group.addButton(self.radio_random)
+        self.radio_button_group.addButton(self.radio_door)
+        self.radio_button_group.addButton(self.radio_corner)
+        
+        radio_group.setLayout(radio_layout)
+        main_layout.addWidget(radio_group)
+        
+        # 窗口列表 - 支持多选
+        list_group = QGroupBox('窗口列表 (霸器-开头) - 可多选')
+        list_layout = QVBoxLayout()
+        
+        self.window_list = QListWidget()
+        self.window_list.setSelectionMode(QListWidget.MultiSelection)  # 改为多选模式
+        self.window_list.itemDoubleClicked.connect(self.show_selected_window)
+        list_layout.addWidget(self.window_list)
+        
+        # 添加全选/取消全选按钮
+        select_layout = QHBoxLayout()
+        self.select_all_btn = QPushButton('全选')
+        self.select_all_btn.clicked.connect(self.select_all_items)
+        select_layout.addWidget(self.select_all_btn)
+        
+        self.deselect_all_btn = QPushButton('取消全选')
+        self.deselect_all_btn.clicked.connect(self.deselect_all_items)
+        select_layout.addWidget(self.deselect_all_btn)
+        
+        self.selected_count_label = QLabel('已选: 0 个窗口')
+        self.selected_count_label.setStyleSheet('color: #00b4d8;')
+        select_layout.addWidget(self.selected_count_label)
+        select_layout.addStretch()
+        
+        list_layout.addLayout(select_layout)
+        
+        list_group.setLayout(list_layout)
+        main_layout.addWidget(list_group)
+        
+        # 操作按钮区域
+        action_group = QGroupBox('操作')
+        action_layout = QHBoxLayout()
+        
+        self.start_btn = QPushButton('▶️ 开始批量执行')
+        self.start_btn.setObjectName('startBtn')
+        self.start_btn.clicked.connect(self.start_auto_click)
+        action_layout.addWidget(self.start_btn)
+        
+        self.stop_btn = QPushButton('⏹️ 停止')
+        self.stop_btn.setObjectName('stopBtn')
+        self.stop_btn.clicked.connect(self.stop_auto_click)
+        self.stop_btn.setEnabled(False)
+        action_layout.addWidget(self.stop_btn)
+        
+        self.show_btn = QPushButton('👁️ 显示选中窗口')
+        self.show_btn.setObjectName('showBtn')
+        self.show_btn.clicked.connect(self.show_selected_window)
+        action_layout.addWidget(self.show_btn)
+        
+        action_group.setLayout(action_layout)
+        main_layout.addWidget(action_group)
+        
+        # 日志区域
+        log_group = QGroupBox('运行日志')
+        log_layout = QVBoxLayout()
+        
+        self.log_text = QTextEdit()
+        self.log_text.setReadOnly(True)
+        self.log_text.setMaximumHeight(150)
+        log_layout.addWidget(self.log_text)
+        
+        log_group.setLayout(log_layout)
+        main_layout.addWidget(log_group)
+        
+        # 状态栏
+        self.status_label = QLabel('就绪')
+        self.status_label.setStyleSheet('color: #888; margin: 5px;')
+        main_layout.addWidget(self.status_label)
+        
+        # 自动加载
+        self.load_processes()
+        
+        # 工作线程信号
+        self.signals = WorkerSignals()
+        self.signals.status.connect(self.update_status)
+        self.signals.progress.connect(self.update_progress)
+        self.signals.finished.connect(self.on_finished)
+    
+    def select_all_items(self):
+        """全选所有窗口"""
+        for i in range(self.window_list.count()):
+            item = self.window_list.item(i)
+            if not item.isHidden():
+                item.setSelected(True)
+        self.update_selected_count()
+    
+    def deselect_all_items(self):
+        """取消全选"""
+        self.window_list.clearSelection()
+        self.update_selected_count()
+    
+    def update_selected_count(self):
+        """更新已选数量"""
+        count = len(self.window_list.selectedItems())
+        self.selected_count_label.setText(f'已选: {count} 个窗口')
+    
+    def get_window_title(self, hwnd):
+        """获取窗口标题"""
+        try:
+            return win32gui.GetWindowText(hwnd)
+        except:
+            return ''
+    
+    def is_window_visible(self, hwnd):
+        """检查窗口是否可见"""
+        try:
+            return win32gui.IsWindowVisible(hwnd)
+        except:
+            return False
+    
+    def enum_all_windows_callback(self, hwnd, windows_list):
+        """枚举所有窗口的回调函数(包括隐藏窗口)"""
+        if win32gui.IsWindow(hwnd):
+            title = self.get_window_title(hwnd)
+            if title:  # 只记录有标题的窗口
+                windows_list.append((hwnd, title))
+        return True
+    
+    def load_processes(self):
+        """加载所有进程窗口(包括隐藏的)"""
+        try:
+            self.window_list.clear()
+            self.window_handles = []
+            self.all_windows = []
+            
+            windows_list = []
+            win32gui.EnumWindows(self.enum_all_windows_callback, windows_list)
+            
+            self.all_windows = windows_list.copy()
+            
+            # 筛选以"霸器-"开头的窗口
+            baqi_windows = [(hwnd, title) for hwnd, title in windows_list if title.startswith('霸器-')]
+            
+            if not baqi_windows:
+                self.status_label.setText(f'未找到以"霸器-"开头的窗口 (共找到 {len(windows_list)} 个窗口)')
+                self.log_text.append(f'⚠️ 未找到霸器窗口,共找到 {len(windows_list)} 个窗口')
+                return
+            
+            # 按标题排序
+            baqi_windows.sort(key=lambda x: x[1])
+            
+            for hwnd, title in baqi_windows:
+                item = QListWidgetItem(title)
+                item.setData(Qt.UserRole, hwnd)
+                visible = self.is_window_visible(hwnd)
+                status_text = " ✓" if visible else " ✗"
+                item.setText(title + status_text)
+                item.setData(Qt.UserRole + 1, visible)
+                self.window_list.addItem(item)
+                self.window_handles.append(hwnd)
+            
+            visible_count = sum(1 for _, title in baqi_windows if self.is_window_visible(_))
+            hidden_count = len(baqi_windows) - visible_count
+            
+            self.status_label.setText(f'找到 {len(baqi_windows)} 个"霸器-"窗口 (可见: {visible_count}, 隐藏: {hidden_count})')
+            self.log_text.append(f'✅ 加载完成,找到 {len(baqi_windows)} 个霸器窗口')
+            
+            # 应用显示模式过滤
+            self.apply_show_mode()
+            self.update_selected_count()
+            
+        except Exception as e:
+            QMessageBox.critical(self, '错误', f'加载进程失败: {str(e)}')
+            self.status_label.setText('加载失败')
+            self.log_text.append(f'❌ 加载失败: {str(e)}')
+    
+    def apply_show_mode(self):
+        """应用显示模式过滤"""
+        mode = self.show_mode_combo.currentText()
+        for i in range(self.window_list.count()):
+            item = self.window_list.item(i)
+            visible = item.data(Qt.UserRole + 1)
+            
+            if mode == '所有窗口':
+                item.setHidden(False)
+            elif mode == '仅可见窗口':
+                item.setHidden(not visible)
+            elif mode == '仅隐藏窗口':
+                item.setHidden(visible)
+        self.update_selected_count()
+    
+    def on_show_mode_changed(self):
+        """显示模式改变时重新过滤"""
+        self.apply_show_mode()
+    
+    def filter_list(self):
+        """根据输入过滤列表"""
+        filter_text = self.filter_input.text().lower()
+        for i in range(self.window_list.count()):
+            item = self.window_list.item(i)
+            title = item.text().replace(' ✓', '').replace(' ✗', '')
+            if filter_text in title.lower():
+                item.setHidden(False)
+            else:
+                item.setHidden(True)
+        self.apply_show_mode()
+    
+    def get_selected_windows(self):
+        """获取所有选中的窗口"""
+        selected_items = self.window_list.selectedItems()
+        windows = []
+        for item in selected_items:
+            hwnd = item.data(Qt.UserRole)
+            title = item.text().replace(' ✓', '').replace(' ✗', '')
+            windows.append((hwnd, title))
+        return windows
+    
+    def show_selected_window(self):
+        """显示选中的窗口(只显示第一个选中的)"""
+        selected = self.get_selected_windows()
+        if not selected:
+            QMessageBox.warning(self, '警告', '请先选择窗口')
+            return
+        
+        hwnd, title = selected[0]
+        try:
+            win32gui.ShowWindow(hwnd, win32con.SW_SHOW)
+            win32gui.SetForegroundWindow(hwnd)
+            if win32gui.IsIconic(hwnd):
+                win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
+            
+            self.status_label.setText(f'已显示窗口: {title}')
+            self.log_text.append(f'👁️ 显示窗口: {title}')
+            self.refresh_window_visibility()
+            
+        except Exception as e:
+            QMessageBox.critical(self, '错误', f'显示窗口失败: {str(e)}')
+    
+    def refresh_window_visibility(self):
+        """刷新窗口中显示的可见状态"""
+        for i in range(self.window_list.count()):
+            item = self.window_list.item(i)
+            hwnd = item.data(Qt.UserRole)
+            title = item.text().replace(' ✓', '').replace(' ✗', '')
+            visible = self.is_window_visible(hwnd)
+            status_text = " ✓" if visible else " ✗"
+            item.setText(title + status_text)
+            item.setData(Qt.UserRole + 1, visible)
+        
+        self.apply_show_mode()
+    
+    def minimize_window(self, hwnd):
+        """最小化窗口"""
+        try:
+            win32gui.ShowWindow(hwnd, win32con.SW_MINIMIZE)
+            self.signals.status.emit(f'📉 已最小化窗口')
+            return True
+        except Exception as e:
+            self.signals.status.emit(f'❌ 最小化失败: {str(e)}')
+            return False
+    
+    def click_at_position(self, hwnd, x_offset, y_offset, button='left'):
+        """
+        封装的点击函数
+        :param hwnd: 窗口句柄
+        :param x_offset: X轴偏移量
+        :param y_offset: Y轴偏移量
+        :param button: 'left' 或 'right'
+        """
+        # 获取窗口位置
+        rect = win32gui.GetWindowRect(hwnd)
+        window_x = rect[0]
+        window_y = rect[1]
+        
+        # 计算点击位置
+        click_x = window_x + x_offset
+        click_y = window_y + y_offset
+        
+        # 移动鼠标到目标位置
+        win32api.SetCursorPos((click_x, click_y))
+        time.sleep(0.2)
+        
+        # 模拟鼠标点击
+        if button == 'left':
+            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, click_x, click_y, 0, 0)
+            time.sleep(0.1)
+            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, click_x, click_y, 0, 0)
+            self.signals.status.emit(f'🖱️ 左键点击: ({click_x}, {click_y})')
+        elif button == 'right':
+            win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN, click_x, click_y, 0, 0)
+            time.sleep(0.1)
+            win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP, click_x, click_y, 0, 0)
+            self.signals.status.emit(f'🖱️ 右键点击: ({click_x}, {click_y})')
+        
+        return click_x, click_y
+    
+    def get_pixel_color(self, hwnd, x_offset, y_offset):
+        try:
+            # 获取窗口位置
+            rect = win32gui.GetWindowRect(hwnd)
+            window_x = rect[0]
+            window_y = rect[1]
+            
+            # 计算屏幕坐标
+            screen_x = window_x + x_offset
+            screen_y = window_y + y_offset
+            
+            # 获取桌面DC
+            hdc = win32gui.GetDC(0)  # 0 表示桌面
+            
+            color_ref = win32gui.GetPixel(hdc, screen_x, screen_y)
+            
+            win32gui.ReleaseDC(0, hdc)
+            
+            red = color_ref & 0xFF
+            green = (color_ref >> 8) & 0xFF
+            blue = (color_ref >> 16) & 0xFF
+            
+            return f"{red:02X}{green:02X}{blue:02X}"
+            
+        except Exception as e:
+            self.log_text.append(f'❌ 取色失败: {str(e)}')
+            return "000000"
+    
+    def check_and_click(self, hwnd, check_x, check_y, target_color, 
+                        click_x, click_y, button='left', check_type='equal'):
+        """
+        检查颜色并执行点击
+        
+        :param hwnd: 窗口句柄
+        :param check_x: 检查颜色的X偏移
+        :param check_y: 检查颜色的Y偏移
+        :param target_color: 目标颜色 (如 "FFFFFF")
+        :param click_x: 点击的X偏移
+        :param click_y: 点击的Y偏移
+        :param button: 'left' 或 'right'
+        :param check_type: 'equal' 或 'not_equal'
+        :return: 是否执行了点击
+        """
+        # 获取当前颜色
+        current_color = self.get_pixel_color(hwnd, check_x, check_y)
+        
+        self.log_text.append(f'🎨 检测位置({check_x},{check_y})颜色: {current_color} (目标: {target_color})')
+        
+        should_click = False
+        if check_type == 'equal':
+            should_click = (current_color == target_color)
+        elif check_type == 'not_equal':
+            should_click = (current_color != target_color)
+        
+        if should_click:
+            self.log_text.append(f'✅ 条件满足,执行点击 ({click_x}, {click_y})')
+            self.click_at_position(hwnd, click_x, click_y, button)
+            return True
+        else:
+            self.log_text.append(f'❌ 条件不满足,跳过点击')
+            return False
+    
+    def start_auto_click(self):
+        """开始自动点击 - 批量执行"""
+        if self.is_running:
+            return
+        
+        # 获取所有选中的窗口
+        selected_windows = self.get_selected_windows()
+        if not selected_windows:
+            QMessageBox.warning(self, '警告', '请至少选择一个窗口')
+            return
+        
+        # 检查是否至少选择了一个功能
+        if not (self.cb_molong.isChecked() or self.cb_feicui.isChecked() or 
+                self.cb_jinyan.isChecked() or self.cb_chiyan.isChecked()):
+            QMessageBox.warning(self, '警告', '请至少选择一个功能')
+            return
+        
+        self.is_running = True
+        self.should_stop = False
+        self.start_btn.setEnabled(False)
+        self.stop_btn.setEnabled(True)
+        
+        # 记录选择的选项
+        selected = []
+        if self.cb_molong.isChecked(): selected.append('争夺魔龙之心')
+        if self.cb_feicui.isChecked(): selected.append('翡翠荣耀旗')
+        if self.cb_jinyan.isChecked(): selected.append('金岩霸者棋')
+        if self.cb_chiyan.isChecked(): selected.append('炽焰战神棋')
+        
+        # 记录皇宫占位选择
+        if self.radio_random.isChecked():
+            palace_pos = '随机'
+            palace_y = 444
+        elif self.radio_door.isChecked():
+            palace_pos = '门口'
+            palace_y = 457
+        else:  # corner
+            palace_pos = '角落'
+            palace_y = 470
+        
+        self.log_text.append(f'▶️ 开始批量执行,共 {len(selected_windows)} 个窗口')
+        self.log_text.append(f'📋 已选功能: {", ".join(selected)}')
+        self.log_text.append(f'🏰 皇宫占位: {palace_pos} (Y+{palace_y})')
+        self.log_text.append('=' * 50)
+        
+        # 在新线程中执行
+        thread = threading.Thread(target=self.batch_auto_click_worker, 
+                                 args=(selected_windows, palace_y))
+        thread.daemon = True
+        thread.start()
+    
+    def batch_auto_click_worker(self, selected_windows, palace_y):
+        """批量自动点击工作线程"""
+        total = len(selected_windows)
+        
+        for idx, (hwnd, title) in enumerate(selected_windows, 1):
+            # 检查是否被停止
+            if self.should_stop:
+                self.signals.status.emit(f'⏹️ 用户停止执行')
+                break
+            
+            self.signals.status.emit(f'📌 正在处理 [{idx}/{total}] {title}')
+            self.signals.progress.emit(idx, total)
+            
+            try:
+                # 执行单个窗口的点击流程
+                self.execute_single_window(hwnd, title, palace_y)
+                
+                # 等待5秒后最小化窗口
+                self.signals.status.emit(f'⏳ 等待5秒后最小化窗口...')
+                time.sleep(5)
+                
+                # 最小化窗口
+                self.signals.status.emit(f'📉 最小化窗口: {title}')
+                self.minimize_window(hwnd)
+                
+                # 窗口间间隔1秒
+                if idx < total and not self.should_stop:
+                    self.signals.status.emit(f'⏳ 等待1秒后处理下一个窗口...')
+                    time.sleep(1)
+                    
+            except Exception as e:
+                self.signals.status.emit(f'❌ 处理窗口失败: {str(e)}')
+                import traceback
+                self.log_text.append(traceback.format_exc())
+                # 出错后继续下一个窗口
+        
+        if not self.should_stop:
+            self.signals.status.emit(f'✅ 批量执行完成!共处理 {idx if idx < total else total} 个窗口')
+        self.signals.finished.emit()
+    
+    def execute_single_window(self, hwnd, title, palace_y):
+        """执行单个窗口的点击流程"""
+        # 1. 激活窗口
+        self.signals.status.emit(f'🔄 正在激活窗口: {title}')
+        
+        # 显示窗口
+        win32gui.ShowWindow(hwnd, win32con.SW_SHOW)
+        if win32gui.IsIconic(hwnd):
+            win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
+        
+        # 激活窗口
+        win32gui.SetForegroundWindow(hwnd)
+        time.sleep(2)  # 等待窗口激活
+        
+        # 步骤1: 左键点击 X+63, Y+81
+        self.click_at_position(hwnd, 29, 41, 'left')
+        time.sleep(1)
+        self.signals.status.emit(f'📍 步骤1: 左键点击 X+63, Y+81')
+        self.click_at_position(hwnd, 63, 81, 'left')
+        
+        # 等待2秒
+        self.signals.status.emit(f'⏳ 等待2秒...')
+        time.sleep(2)
+        
+        # 步骤2: 右键点击 X+413, Y+168
+        self.signals.status.emit(f'📍 步骤2: 右键点击 X+413, Y+168')
+        self.click_at_position(hwnd, 413, 168, 'right')
+        
+        # 等待6秒
+        self.signals.status.emit(f'⏳ 等待6秒...')
+        time.sleep(6)
+        
+        # 处理"争夺魔龙之心"
+        if self.cb_molong.isChecked():
+            self.signals.status.emit(f'📍 检查争夺魔龙之心')
+            self.check_and_click(
+                hwnd=hwnd,
+                check_x=642,
+                check_y=439,
+                target_color="FFFFFF",
+                click_x=642,
+                click_y=439,
+                button='left',
+                check_type='equal'
+            )
+        else:
+            self.signals.status.emit(f'📍 未选争夺魔龙之心,执行相反逻辑')
+            self.check_and_click(
+                hwnd=hwnd,
+                check_x=642,
+                check_y=437,
+                target_color="FFFFFF",
+                click_x=642,
+                click_y=437,
+                button='left',
+                check_type='not_equal'
+            )
+        
+        # 等待1秒
+        time.sleep(1)
+        
+        # 处理"翡翠荣耀旗"
+        if self.cb_feicui.isChecked():
+            self.signals.status.emit(f'📍 检查翡翠荣耀旗')
+            self.check_and_click(
+                hwnd=hwnd,
+                check_x=769,
+                check_y=386,
+                target_color="FFFFFF",
+                click_x=769,
+                click_y=386,
+                button='left',
+                check_type='equal'
+            )
+        else:
+            self.signals.status.emit(f'📍 未选翡翠荣耀旗,执行相反逻辑')
+            self.check_and_click(
+                hwnd=hwnd,
+                check_x=769,
+                check_y=386,
+                target_color="FFFFFF",
+                click_x=769,
+                click_y=386,
+                button='left',
+                check_type='not_equal'
+            )
+        
+        # 等待1秒
+        time.sleep(1)
+        
+        # 处理"金岩霸者棋"
+        if self.cb_jinyan.isChecked():
+            self.signals.status.emit(f'📍 检查金岩霸者棋')
+            self.check_and_click(
+                hwnd=hwnd,
+                check_x=769,
+                check_y=400,
+                target_color="FFFFFF",
+                click_x=769,
+                click_y=400,
+                button='left',
+                check_type='equal'
+            )
+        else:
+            self.signals.status.emit(f'📍 未选金岩霸者棋,执行相反逻辑')
+            self.check_and_click(
+                hwnd=hwnd,
+                check_x=769,
+                check_y=400,
+                target_color="FFFFFF",
+                click_x=769,
+                click_y=400,
+                button='left',
+                check_type='not_equal'
+            )
+        
+        # 等待1秒
+        time.sleep(1)
+        
+        # 处理"炽焰战神棋"
+        if self.cb_chiyan.isChecked():
+            self.signals.status.emit(f'📍 检查炽焰战神棋')
+            self.check_and_click(
+                hwnd=hwnd,
+                check_x=767,
+                check_y=415,
+                target_color="FFFFFF",
+                click_x=767,
+                click_y=415,
+                button='left',
+                check_type='equal'
+            )
+        else:
+            self.signals.status.emit(f'📍 未选炽焰战神棋,执行相反逻辑')
+            self.check_and_click(
+                hwnd=hwnd,
+                check_x=767,
+                check_y=415,
+                target_color="FFFFFF",
+                click_x=767,
+                click_y=415,
+                button='left',
+                check_type='not_equal'
+            )
+        
+        # 等待1秒
+        time.sleep(1)
+        
+        # 最后点击 X+871, Y+266
+        self.signals.status.emit(f'📍 最后点击: X+871, Y+266')
+        self.click_at_position(hwnd, 871, 266, 'left')
+
+        time.sleep(1)
+        self.click_at_position(hwnd, 671, 70, 'right')
+
+        time.sleep(1)
+        self.click_at_position(hwnd, 714, 426, 'left')
+
+        time.sleep(1)
+        
+        # 皇宫占位点击 - 根据选择的选项
+        self.signals.status.emit(f'🏰 皇宫占位点击: X+716, Y+{palace_y}')
+        self.click_at_position(hwnd, 716, palace_y, 'left')
+        
+        time.sleep(1)
+        self.click_at_position(hwnd, 901, 311, 'left')
+
+        time.sleep(1)
+        self.click_at_position(hwnd, 1133, 8, 'left')
+        
+        self.signals.status.emit(f'✅ 窗口 {title} 执行完成')
+    
+    def stop_auto_click(self):
+        """停止自动点击"""
+        self.should_stop = True
+        self.is_running = False
+        self.start_btn.setEnabled(True)
+        self.stop_btn.setEnabled(False)
+        self.status_label.setText('正在停止...')
+        self.log_text.append('⏹️ 正在停止执行...')
+    
+    def update_status(self, message):
+        """更新状态"""
+        self.status_label.setText(message)
+        self.log_text.append(message)
+        # 滚动到底部
+        self.log_text.verticalScrollBar().setValue(
+            self.log_text.verticalScrollBar().maximum()
+        )
+    
+    def update_progress(self, current, total):
+        """更新进度"""
+        self.status_label.setText(f'进度: {current}/{total}')
+    
+    def on_finished(self):
+        """完成回调"""
+        self.is_running = False
+        self.start_btn.setEnabled(True)
+        self.stop_btn.setEnabled(False)
+        self.status_label.setText('就绪')
+        self.log_text.append('=' * 50)
+
+
+def main():
+    app = QApplication(sys.argv)
+    app.setStyle('Fusion')
+    
+    window = WindowManagerApp()
+    window.show()
+    
+    sys.exit(app.exec_())
+
+
+if __name__ == '__main__':
+    main()

+ 1 - 1
test.py

@@ -11,7 +11,7 @@ headers = {
     "referer": "https://cppaidan.com/paidan/system/user"
 }
 
-password = 10303
+password = 67745
 while password < 1000000:
     try:
         response = requests.post(

+ 230 - 52
解密机大侠.py

@@ -163,38 +163,18 @@ class OrderManager:
         recursive_search(json_data)
         return list(set(notices))  # 去重
 
-    def download_and_ocr_image(self, image_url):
-        """下载图片并OCR识别"""
+    def ocr_by_url(self, image_url):
+        """通过URL进行OCR识别"""
         try:
-            # 下载图片
-            response = requests.get(image_url, timeout=30)
-            response.raise_for_status()
-            
-            # 创建temp目录
-            os.makedirs('./temp', exist_ok=True)
-            
-            # 保存临时文件
-            url_path = image_url.split('?')[0]
-            file_ext = os.path.splitext(url_path)[1]
-            if not file_ext:
-                file_ext = '.jpg'
-            random_filename = f"{uuid.uuid4().hex}{file_ext}"
-            temp_path = os.path.join('./temp', random_filename)
+            # 构建请求数据
+            payload = {"url": image_url}
             
-            with open(temp_path, 'wb') as f:
-                f.write(response.content)
+            # 发送POST请求
+            response = requests.post(self.ocr_url, json=payload, timeout=60)
             
-            # 发送到OCR服务
-            with open(temp_path, 'rb') as f:
-                files = {'image': (random_filename, f, 'image/jpeg')}
-                ocr_response = requests.post(self.ocr_url, files=files, timeout=60)
-            
-            # 清理临时文件
-            if os.path.exists(temp_path):
-                os.remove(temp_path)
-            
-            if ocr_response.status_code == 200:
-                ocr_result = ocr_response.json()
+            if response.status_code == 200:
+                ocr_result = response.json()
+                print(f"OCR完整返回: {json.dumps(ocr_result)}")
                 if ocr_result.get('success'):
                     return ocr_result
             return None
@@ -203,6 +183,7 @@ class OrderManager:
             return None
 
     def extract_text_from_ocr_result(self, ocr_result):
+        print(ocr_result)
         """提取OCR文本"""
         if not ocr_result or not ocr_result.get('texts'):
             return ''
@@ -217,10 +198,24 @@ class OrderManager:
 
     def extract_charge_count(self, text):
         """提取充电次数"""
-        pattern = r'充电次数(\d+)次'
-        match = re.search(pattern, text)
+        # 匹配(232次循环)格式
+        pattern1 = r'[((]\s*(\d+)\s*次\s*循环\s*[))]'
+        match = re.search(pattern1, text)
+        if match:
+            return int(match.group(1))
+        
+        # 匹配充电次数123次格式
+        pattern2 = r'充电次数(\d+)次'
+        match = re.search(pattern2, text)
+        if match:
+            return int(match.group(1))
+        
+        # 匹配单独的 数字+次 格式(如 71477次)
+        pattern3 = r'(\d+)次'
+        match = re.search(pattern3, text)
         if match:
             return int(match.group(1))
+        
         return None
 
 # --- GUI主窗口 ---
@@ -231,6 +226,9 @@ class MainWindow(QMainWindow):
         self.order_list = []
         self.order_details_cache = {}  # 缓存订单详情
         self.charge_counts = {}  # 缓存充电次数
+        self.is_batch_processing = False
+        self.batch_queue = []
+        self.current_batch_index = 0
         self.init_ui()
 
     def init_ui(self):
@@ -268,6 +266,15 @@ class MainWindow(QMainWindow):
             QPushButton:disabled {
                 background-color: #cccccc;
             }
+            QPushButton#batch_btn {
+                background-color: #28a745;
+            }
+            QPushButton#batch_btn:hover {
+                background-color: #218838;
+            }
+            QPushButton#batch_btn:disabled {
+                background-color: #cccccc;
+            }
             QLineEdit, QTextEdit {
                 border: 1px solid #ccc;
                 border-radius: 4px;
@@ -297,6 +304,15 @@ class MainWindow(QMainWindow):
                 font-family: 'Consolas', 'Courier New', monospace;
                 font-size: 11px;
             }
+            QProgressBar {
+                border: 1px solid #ccc;
+                border-radius: 4px;
+                text-align: center;
+            }
+            QProgressBar::chunk {
+                background-color: #0078d7;
+                border-radius: 4px;
+            }
         """)
 
         # 中央部件
@@ -325,7 +341,7 @@ class MainWindow(QMainWindow):
         # OCR地址输入
         config_layout.addWidget(QLabel("OCR地址:"), 1, 0)
         self.ocr_input = QLineEdit()
-        self.ocr_input.setText("http://192.168.0.110:10001/ocr")
+        self.ocr_input.setText("http://111.229.45.38:19100/ocr/url")
         config_layout.addWidget(self.ocr_input, 1, 1, 1, 2)
         
         # 操作按钮
@@ -340,6 +356,14 @@ class MainWindow(QMainWindow):
         self.refresh_btn.setFixedHeight(35)
         btn_layout.addWidget(self.refresh_btn)
         
+        # 一键获取所有充电次数按钮
+        self.batch_btn = QPushButton("📊 一键获取所有充电次数")
+        self.batch_btn.setObjectName("batch_btn")
+        self.batch_btn.clicked.connect(self.batch_check_charge_counts)
+        self.batch_btn.setFixedHeight(35)
+        self.batch_btn.setEnabled(False)
+        btn_layout.addWidget(self.batch_btn)
+        
         btn_layout.addStretch()
         config_layout.addLayout(btn_layout, 2, 0, 1, 3)
         
@@ -350,6 +374,11 @@ class MainWindow(QMainWindow):
         list_group = QGroupBox("订单列表")
         list_layout = QVBoxLayout()
         
+        # 进度条
+        self.progress_bar = QProgressBar()
+        self.progress_bar.setVisible(False)
+        list_layout.addWidget(self.progress_bar)
+        
         # 表格
         self.table = QTableWidget()
         self.table.setColumnCount(7)
@@ -412,7 +441,8 @@ class MainWindow(QMainWindow):
             "INFO": "#d4d4d4",
             "WARNING": "#ffa500",
             "ERROR": "#ff4444",
-            "SUCCESS": "#4caf50"
+            "SUCCESS": "#4caf50",
+            "PROGRESS": "#00bcd4"
         }
         color = color_map.get(level, "#d4d4d4")
         html = f'<span style="color: #888888;">[{timestamp}]</span> <span style="color: {color};">[{level}]</span> {message}<br>'
@@ -446,6 +476,7 @@ class MainWindow(QMainWindow):
         # 清空缓存
         self.order_details_cache = {}
         self.charge_counts = {}
+        self.batch_btn.setEnabled(False)
         
         self.status_bar.showMessage("正在获取订单列表...")
         self.search_btn.setEnabled(False)
@@ -468,12 +499,14 @@ class MainWindow(QMainWindow):
         self.order_list = order_list
         self.display_orders()
         self.search_btn.setEnabled(True)
+        self.batch_btn.setEnabled(True)
         self.status_bar.showMessage(f"成功加载 {len(order_list)} 条订单")
         self.log_message(f"成功加载 {len(order_list)} 条订单", "SUCCESS")
 
     def on_error(self, error_msg):
         """错误处理"""
         self.search_btn.setEnabled(True)
+        self.batch_btn.setEnabled(False)
         self.status_bar.showMessage("加载失败")
         self.log_message(f"获取订单列表失败: {error_msg}", "ERROR")
         QMessageBox.critical(self, "错误", f"获取订单列表失败:\n{error_msg}")
@@ -540,13 +573,6 @@ class MainWindow(QMainWindow):
         
         self.log_message(f"开始查询订单 {order_no} 的充电次数", "INFO")
         
-        # 检查是否已缓存
-        if order_no in self.charge_counts:
-            count = self.charge_counts[order_no]
-            self.update_charge_display(index, count)
-            self.log_message(f"订单 {order_no} 充电次数: {count} (来自缓存)", "INFO")
-            return
-        
         self.status_bar.showMessage(f"正在查询订单 {order_no} 的充电次数...")
         
         # 禁用按钮
@@ -561,6 +587,141 @@ class MainWindow(QMainWindow):
         self.charge_worker.error.connect(self.on_charge_error)
         self.charge_worker.start()
 
+    def batch_check_charge_counts(self):
+        """一键获取所有订单的充电次数"""
+        if not self.order_list:
+            QMessageBox.warning(self, "提示", "请先搜索订单")
+            return
+        
+        if self.is_batch_processing:
+            return
+        
+        # 检查哪些订单还没查询
+        pending_indices = []
+        for i, order in enumerate(self.order_list):
+            order_no = order.get('orderNo')
+            if order_no not in self.charge_counts:
+                pending_indices.append(i)
+        
+        if not pending_indices:
+            self.log_message("所有订单已查询完成", "SUCCESS")
+            QMessageBox.information(self, "提示", "所有订单已查询完成")
+            return
+        
+        self.is_batch_processing = True
+        self.batch_queue = pending_indices
+        self.current_batch_index = 0
+        
+        # ===== 添加以下代码 =====
+        # 禁用相关按钮
+        self.batch_btn.setEnabled(False)
+        self.search_btn.setEnabled(False)
+        self.refresh_btn.setEnabled(False)
+        
+        # 显示进度条
+        self.progress_bar.setVisible(True)
+        self.progress_bar.setMaximum(len(pending_indices))
+        self.progress_bar.setValue(0)
+        
+        self.log_message(f"开始批量查询 {len(pending_indices)} 个订单的充电次数", "PROGRESS")
+        
+        # 开始处理第一个
+        self.process_next_batch()
+
+    def process_next_batch(self):
+        """处理下一个批量查询"""
+        if self.current_batch_index >= len(self.batch_queue):
+            # 全部完成
+            self.on_batch_complete()
+            return
+        
+        index = self.batch_queue[self.current_batch_index]
+        order_no = self.order_list[index].get('orderNo')
+        
+        # 更新进度
+        self.progress_bar.setValue(self.current_batch_index + 1)
+        self.status_bar.showMessage(f"批量处理中: {self.current_batch_index + 1}/{len(self.batch_queue)} - 订单 {order_no}")
+        
+        # 禁用该行的查询按钮
+        btn = self.findChild(QPushButton, f"check_btn_{index}")
+        if btn:
+            btn.setEnabled(False)
+            btn.setText("查询中")
+        
+        # 创建worker处理
+        self.batch_worker = ChargeQueryWorker(self.order_manager, order_no, index)
+        self.batch_worker.finished.connect(self.on_batch_item_complete)
+        self.batch_worker.error.connect(self.on_batch_item_error)
+        self.batch_worker.start()
+
+    def on_batch_item_complete(self, index, charge_count, ocr_result, image_notices):
+        """批量查询单个完成"""
+        order_no = self.order_list[index].get('orderNo')
+        
+        # 更新显示
+        self.charge_counts[order_no] = charge_count
+        self.update_charge_display(index, charge_count)
+        
+        # 恢复按钮
+        btn = self.findChild(QPushButton, f"check_btn_{index}")
+        if btn:
+            btn.setEnabled(True)
+            btn.setText("查询")
+        
+        # 日志
+        if charge_count is not None:
+            self.log_message(f"[{self.current_batch_index + 1}/{len(self.batch_queue)}] 订单 {order_no} 充电次数: {charge_count}", "SUCCESS")
+        else:
+            self.log_message(f"[{self.current_batch_index + 1}/{len(self.batch_queue)}] 订单 {order_no} 未找到充电次数", "WARNING")
+            if ocr_result:
+                ocr_text = self.order_manager.extract_text_from_ocr_result(ocr_result)
+                if ocr_text:
+                    self.log_message(f"  OCR文本: {ocr_text}", "INFO")
+            if image_notices:
+                self.log_message(f"  图片notice: {', '.join(image_notices[:5])}", "INFO")
+        
+        # 处理下一个
+        self.current_batch_index += 1
+        QTimer.singleShot(500, self.process_next_batch)  # 延迟500ms防止请求过快
+
+    def on_batch_item_error(self, index, error_msg):
+        """批量查询单个错误"""
+        order_no = self.order_list[index].get('orderNo')
+        self.log_message(f"[{self.current_batch_index + 1}/{len(self.batch_queue)}] 订单 {order_no} 查询失败: {error_msg}", "ERROR")
+        
+        # 恢复按钮
+        btn = self.findChild(QPushButton, f"check_btn_{index}")
+        if btn:
+            btn.setEnabled(True)
+            btn.setText("查询")
+        
+        # 处理下一个
+        self.current_batch_index += 1
+        QTimer.singleShot(500, self.process_next_batch)
+
+    def on_batch_complete(self):
+        """批量查询完成"""
+        self.is_batch_processing = False
+        self.batch_queue = []
+        
+        # 恢复按钮
+        self.batch_btn.setEnabled(True)
+        self.search_btn.setEnabled(True)
+        self.refresh_btn.setEnabled(True)
+        
+        # 隐藏进度条
+        self.progress_bar.setVisible(False)
+        
+        self.status_bar.showMessage(f"批量查询完成,共处理 {len(self.charge_counts)} 个订单")
+        self.log_message("批量查询完成", "SUCCESS")
+        
+        # 统计结果
+        success_count = sum(1 for v in self.charge_counts.values() if v is not None)
+        total_count = len(self.charge_counts)
+        self.log_message(f"统计: 成功 {success_count}/{total_count} 个订单找到充电次数", "INFO")
+        
+        QMessageBox.information(self, "完成", f"批量查询完成!\n\n成功找到充电次数: {success_count}/{total_count}")
+
     def on_charge_queried(self, index, charge_count, ocr_result, image_notices):
         """充电次数查询完成"""
         order_no = self.order_list[index].get('orderNo')
@@ -571,15 +732,27 @@ class MainWindow(QMainWindow):
                 self.log_message(f"订单 {order_no} 未找到充电次数,OCR识别结果:", "WARNING")
                 ocr_text = self.order_manager.extract_text_from_ocr_result(ocr_result)
                 if ocr_text:
-                    self.log_message(f"OCR文本: {ocr_text[:200]}...", "INFO")
+                    self.log_message(f"OCR文本: {ocr_text}", "INFO")
                 else:
                     self.log_message(f"OCR文本为空", "WARNING")
             else:
-                self.log_message(f"订单 {order_no} OCR识别失败", "ERROR")
-            
-            if image_notices:
-                self.log_message(f"订单 {order_no} 找到的图片notice: {', '.join(image_notices)}", "INFO")
-            else:
+                # 重新获取订单详情来输出图片信息
+                order_detail, _ = self.order_manager.get_order_detail(order_no)
+                if order_detail:
+                    self.log_message(f"订单 {order_no} 所有图片信息:", "INFO")
+                    # 递归获取所有图片
+                    def print_images(obj):
+                        if isinstance(obj, dict):
+                            if 'notice' in obj and 'originalImage' in obj:
+                                self.log_message(f"  {obj['notice']}: {obj['originalImage']}", "INFO")
+                            for value in obj.values():
+                                print_images(value)
+                        elif isinstance(obj, list):
+                            for item in obj:
+                                print_images(item)
+                    print_images(order_detail)
+            
+            if not image_notices:
                 self.log_message(f"订单 {order_no} 未找到验机图片", "ERROR")
         else:
             self.log_message(f"订单 {order_no} 充电次数: {charge_count}", "SUCCESS")
@@ -634,7 +807,7 @@ class OrderListWorker(QThread):
 
     def run(self):
         try:
-            order_list, error = self.order_manager.get_pending_order_list()
+            order_list, error = self.order_manager.get_pending_order_list(100)
             if error:
                 self.error.emit(error)
             else:
@@ -665,20 +838,25 @@ class ChargeQueryWorker(QThread):
             
             # 查找验机图片
             report_img = self.order_manager.find_original_image_by_notice(order_detail, "苹果沙漏验机报告")
+            
+            if report_img is None:
+                report_img = self.order_manager.find_original_image_by_notice(order_detail, "沙漏图")
+            if report_img is None:
+                report_img = self.order_manager.find_original_image_by_notice(order_detail, "苹果验机软件")
             if report_img is None:
                 report_img = self.order_manager.find_original_image_by_notice(order_detail, "苹果沙漏验机基本信息")
             if report_img is None:
                 report_img = self.order_manager.find_original_image_by_notice(order_detail, "验机照片")
             if report_img is None:
-                report_img = self.order_manager.find_original_image_by_notice(order_detail, "苹果验机软件")
-            
+                report_img = self.order_manager.find_original_image_by_notice(order_detail, "验机报告")
             if not report_img:
                 # 没有找到图片,返回notice列表
                 self.finished.emit(self.index, None, None, image_notices)
                 return
-            
-            # OCR识别
-            ocr_result = self.order_manager.download_and_ocr_image(report_img)
+            else:
+                print("找到图片:" + report_img)
+            # OCR识别(使用URL方式)
+            ocr_result = self.order_manager.ocr_by_url(report_img)
             if not ocr_result:
                 # OCR失败,返回notice列表
                 self.finished.emit(self.index, None, None, image_notices)