Jelajahi Sumber

解密机大侠

PUGE 1 bulan lalu
induk
melakukan
c01a8b27ef
1 mengubah file dengan 670 tambahan dan 282 penghapusan
  1. 670 282
      解密机大侠.py

+ 670 - 282
解密机大侠.py

@@ -1,322 +1,710 @@
+import sys
 import requests
 import json
+import os
+import re
+import uuid
+import hashlib
 from Crypto.Cipher import AES
 from Crypto.Util.Padding import unpad
 from typing import Optional, List, Dict, Any
+from PyQt5.QtWidgets import *
+from PyQt5.QtCore import *
+from PyQt5.QtGui import *
 
-# --- 1. 解密函数 (从JS代码转换) ---
-def decrypt_order_data(hex_string):
-    """
-    使用AES-CBC模式解密订单详情数据
-    """
-    key = b"S9u978T13NLCGc5W"          # 密钥
-    iv = b"X83yWMD9iKhLxfwX"           # 偏移量 (IV)
-    
-    # 将十六进制字符串转换为字节
-    encrypted_data = bytes.fromhex(hex_string)
-    
-    # 创建AES-CBC解密器
-    cipher = AES.new(key, AES.MODE_CBC, iv)
-    
-    # 解密并去除填充 (PKCS7)
-    decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size)
-    
-    # 返回UTF-8字符串
-    return decrypted_data.decode('utf-8')
-
-# --- 2. 请求头配置 ---
-HEADERS = {
-    'Connection': 'keep-alive',
-    'content-type': 'application/json',
-    'Version': '2.50.0',
-    'timestamp': '1784094158706',
-    'Distinct-Id': '1784057137891-1059356-086b42dd38b0b98-24491897',
-    'vaccine': 'aa454c048e8843247cebf378d1a9a0fed759027f329caf68fd900654da4232d0',
-    'U-A': 'JiDaXiaWeApp/23958 (:)',
-    'x-version': 'ITC-77385',
-    'ahs-gate-language': 'zh_CN',
-    'APP-ID': 'jdx135624',
-    'platform': 'weapp',
-    'Register-Flow-Source': 'RECYCLER',
-    'ahs-language': 'zh-CN',
-    'access_token': 'jdx9ce52336abee4cf78db56567dc259512',
-    'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 26_5_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.75(0x18004b3c) NetType/WIFI Language/zh_CN',
-    'Referer': 'https://servicewechat.com/wx7e6573879e91b1ac/28/page-frame.html',
-}
-
-# --- 3. 获取待抢订单列表 ---
-def get_pending_order_list(page_size: int = 10) -> Optional[List[Dict[str, Any]]]:
-    """
-    获取待抢订单列表
-    
-    Args:
-        page_size: 每页数量,默认10条
+# --- 核心功能类 ---
+class OrderManager:
+    def __init__(self, access_token, ocr_url):
+        self.access_token = access_token
+        self.ocr_url = ocr_url
+        self.headers = {
+            'Connection': 'keep-alive',
+            'content-type': 'application/json',
+            'Version': '2.50.0',
+            'timestamp': '1784094158706',
+            'Distinct-Id': '1784057137891-1059356-086b42dd38b0b98-24491897',
+            'vaccine': 'aa454c048e8843247cebf378d1a9a0fed759027f329caf68fd900654da4232d0',
+            'U-A': 'JiDaXiaWeApp/23958 (:)',
+            'x-version': 'ITC-77385',
+            'ahs-gate-language': 'zh_CN',
+            'APP-ID': 'jdx135624',
+            'platform': 'weapp',
+            'Register-Flow-Source': 'RECYCLER',
+            'ahs-language': 'zh-CN',
+            'access_token': access_token,
+            'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 26_5_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.75(0x18004b3c) NetType/WIFI Language/zh_CN',
+            'Referer': 'https://servicewechat.com/wx7e6573879e91b1ac/28/page-frame.html',
+        }
+        self.key = b"S9u978T13NLCGc5W"
+        self.iv = b"X83yWMD9iKhLxfwX"
+
+    def decrypt_order_data(self, hex_string):
+        """解密订单数据"""
+        encrypted_data = bytes.fromhex(hex_string)
+        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
+        decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size)
+        return decrypted_data.decode('utf-8')
+
+    def get_pending_order_list(self, page_size=10):
+        """获取待抢订单列表"""
+        url = "https://wirelessgate.aihuishou.com/jdx-rc-bff-service/app/order/pendingGrab/list"
         
-    Returns:
-        订单列表,失败返回None
-    """
-    url = "https://wirelessgate.aihuishou.com/jdx-rc-bff-service/app/order/pendingGrab/list"
-    
-    payload = {
-        "pageSize": page_size,
-        "status": -1,
-        "isApplyForHandle": None,
-        "applyPhotoStatus": None,
-        "productIds": [265024, 225362, 225361, 225358, 225366, 173473, 161415, 161414, 161413, 161412, 121769, 121439, 121436, 121435, 98526, 98528, 98527, 98525, 43513, 43512, 43511, 43510, 36047, 36045, 36044, 36046, 32292, 32291, 32290, 27640, 27639, 27637, 25827, 25680, 25679, 23423, 23422, 66428, 34701, 20079, 17752, 17726, 17462, 17461, 17459, 17458, 17457, 17460, 17455, 2247, 2246],
-        "sourceIds": None,
-        "keyword": None,
-        "timeObj": None,
-        "rcOrderResult": None
-    }
-    
-    try:
-        response = requests.post(url, headers=HEADERS, json=payload)
-        response.raise_for_status()
+        payload = {
+            "pageSize": page_size,
+            "status": -1,
+            "isApplyForHandle": None,
+            "applyPhotoStatus": None,
+            "productIds": [265024, 225362, 225361, 225358, 225366, 173473, 161415, 161414, 161413, 161412, 121769, 121439, 121436, 121435, 98526, 98528, 98527, 98525, 43513, 43512, 43511, 43510, 36047, 36045, 36044, 36046, 32292, 32291, 32290, 27640, 27639, 27637, 25827, 25680, 25679, 23423, 23422, 66428, 34701, 20079, 17752, 17726, 17462, 17461, 17459, 17458, 17457, 17460, 17455, 2247, 2246],
+            "sourceIds": None,
+            "keyword": None,
+            "timeObj": None,
+            "rcOrderResult": None
+        }
         
-        result = response.json()
+        try:
+            response = requests.post(url, headers=self.headers, json=payload, timeout=30)
+            response.raise_for_status()
+            result = response.json()
+            
+            if result.get('code') != 200:
+                return None, result.get('resultMessage', '未知错误')
+            
+            return result.get('data', []), None
+        except Exception as e:
+            return None, str(e)
+
+    def get_order_detail(self, order_no):
+        """获取订单详情"""
+        # 获取BiddingNo
+        snatch_url = "https://wirelessgate.aihuishou.com/jdx-rc-service/front/bid/snatch"
+        snatch_payload = {"orderNo": order_no}
         
-        if result.get('code') != 200:
-            print(f"获取订单列表失败: {result.get('resultMessage', '未知错误')}")
-            return None
+        try:
+            snatch_response = requests.post(snatch_url, headers=self.headers, json=snatch_payload, timeout=30)
+            snatch_response.raise_for_status()
+            snatch_data = snatch_response.json()
+            
+            if snatch_data.get('code') != 200:
+                return None, snatch_data.get('resultMessage', '获取BiddingNo失败')
+            
+            bidding_no = snatch_data.get('data')
+            if not bidding_no:
+                return None, "获取BiddingNo为空"
+                
+        except Exception as e:
+            return None, str(e)
         
-        order_list = result.get('data', [])
-        print(f"成功获取 {len(order_list)} 条待抢订单")
-        return order_list
+        # 获取订单详情
+        detail_url = f"https://wirelessgate.aihuishou.com/jdx-qa-service/app/ka/v3/order/detail?orderNo={order_no}&biddingNo={bidding_no}"
         
-    except requests.RequestException as e:
-        print(f"请求订单列表失败: {e}")
-        return None
-    except json.JSONDecodeError as e:
-        print(f"解析订单列表JSON失败: {e}")
-        return None
+        try:
+            detail_response = requests.get(detail_url, headers=self.headers, timeout=30)
+            detail_response.raise_for_status()
+            detail_data = detail_response.json()
+            
+            if detail_data.get('code') != 200:
+                return None, detail_data.get('resultMessage', '获取订单详情失败')
+            
+            encrypted_hex = detail_data.get('data')
+            if not encrypted_hex:
+                return None, "未获取到加密数据"
+            
+            decrypted_json_string = self.decrypt_order_data(encrypted_hex)
+            order_detail = json.loads(decrypted_json_string)
+            
+            return order_detail, None
+            
+        except Exception as e:
+            return None, str(e)
 
-# --- 4. 显示订单列表 ---
-def display_order_list(order_list: List[Dict[str, Any]]):
-    """
-    美化显示订单列表
-    """
-    if not order_list:
-        print("暂无待抢订单")
-        return
-    
-    print("\n" + "="*80)
-    print("待抢订单列表:")
-    print("="*80)
-    
-    for idx, order in enumerate(order_list, 1):
-        print(f"\n[{idx}] 订单号: {order.get('orderNo', 'N/A')}")
-        print(f"    商品: {order.get('brandInfo', 'N/A')}")
-        print(f"    IMEI: {order.get('imei', 'N/A')}")
-        print(f"    预估价格: {order.get('price', '待定')}")
-        print(f"    门店: {order.get('title', 'N/A')}")
-        print(f"    截止时间: {order.get('biddingDeadlineDt', 'N/A')}")
-        
-        # 显示标签
-        labels = order.get('labels', [])
-        if labels:
-            label_names = [label.get('labelName', '') for label in labels]
-            print(f"    标签: {', '.join(label_names)}")
-        
-        # 显示提示
-        tips = order.get('tips', {})
-        if tips:
-            print(f"    提示: {tips.get('tipStr', 'N/A')}")
-    
-    print("\n" + "="*80)
+    def find_original_image_by_notice(self, json_data, notice_keyword):
+        """查找图片链接"""
+        if isinstance(json_data, str):
+            try:
+                json_data = json.loads(json_data)
+            except json.JSONDecodeError:
+                return None
 
-# --- 5. 从订单列表中提取订单号 ---
-def select_order_by_index(order_list: List[Dict[str, Any]], index: int) -> Optional[str]:
-    """
-    根据索引从订单列表中提取订单号
-    
-    Args:
-        order_list: 订单列表
-        index: 索引(从1开始)
-        
-    Returns:
-        订单号,失败返回None
-    """
-    if not order_list:
-        print("订单列表为空")
-        return None
-    
-    if index < 1 or index > len(order_list):
-        print(f"索引超出范围,请输入1-{len(order_list)}之间的数字")
-        return None
-    
-    order_no = order_list[index - 1].get('orderNo')
-    if not order_no:
-        print(f"第{index}个订单缺少订单号")
-        return None
-    
-    print(f"已选择订单: {order_no}")
-    return order_no
-
-# --- 6. 获取订单详情(原有功能) ---
-def get_order_detail(order_no: str) -> Optional[Dict[str, Any]]:
-    """
-    获取订单详情
-    
-    Args:
-        order_no: 订单号
-        
-    Returns:
-        解密后的订单详情,失败返回None
-    """
-    # 第一步:获取BiddingNo
-    snatch_url = "https://wirelessgate.aihuishou.com/jdx-rc-service/front/bid/snatch"
-    snatch_payload = {"orderNo": order_no}
-    
-    print(f"\n正在获取订单 {order_no} 的BiddingNo...")
-    try:
-        snatch_response = requests.post(snatch_url, headers=HEADERS, json=snatch_payload)
-        snatch_response.raise_for_status()
-        snatch_data = snatch_response.json()
-        
-        if snatch_data.get('code') != 200:
-            print(f"获取BiddingNo失败: {snatch_data.get('resultMessage', '未知错误')}")
+        def recursive_search(obj):
+            if isinstance(obj, dict):
+                if 'notice' in obj and 'originalImage' in obj:
+                    if notice_keyword.lower() in obj['notice'].lower():
+                        return obj['originalImage']
+                
+                for value in obj.values():
+                    result = recursive_search(value)
+                    if result:
+                        return result
+            
+            elif isinstance(obj, list):
+                for item in obj:
+                    result = recursive_search(item)
+                    if result:
+                        return result
+            
             return None
+
+        return recursive_search(json_data)
+
+    def get_all_image_notices(self, json_data):
+        """获取所有图片的notice信息"""
+        notices = []
+        
+        def recursive_search(obj):
+            if isinstance(obj, dict):
+                if 'notice' in obj and 'image' in obj:
+                    notices.append(obj['notice'])
+                for value in obj.values():
+                    recursive_search(value)
+            elif isinstance(obj, list):
+                for item in obj:
+                    recursive_search(item)
         
-        bidding_no = snatch_data.get('data')
-        if not bidding_no:
-            print("获取BiddingNo为空")
+        recursive_search(json_data)
+        return list(set(notices))  # 去重
+
+    def download_and_ocr_image(self, image_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)
+            
+            with open(temp_path, 'wb') as f:
+                f.write(response.content)
+            
+            # 发送到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 ocr_result.get('success'):
+                    return ocr_result
             return None
             
-        print(f"成功获取 BiddingNo: {bidding_no}")
+        except Exception as e:
+            return None
+
+    def extract_text_from_ocr_result(self, ocr_result):
+        """提取OCR文本"""
+        if not ocr_result or not ocr_result.get('texts'):
+            return ''
         
-    except requests.RequestException as e:
-        print(f"请求BiddingNo失败: {e}")
-        return None
-    except json.JSONDecodeError as e:
-        print(f"解析BiddingNo响应失败: {e}")
+        texts = ''
+        for item in ocr_result['texts']:
+            rec_texts = item.get('rec_texts', [])
+            for text in rec_texts:
+                texts = texts + text
+        
+        return texts
+
+    def extract_charge_count(self, text):
+        """提取充电次数"""
+        pattern = r'充电次数(\d+)次'
+        match = re.search(pattern, text)
+        if match:
+            return int(match.group(1))
         return None
-    
-    # 第二步:请求订单详情(加密数据)
-    detail_url = f"https://wirelessgate.aihuishou.com/jdx-qa-service/app/ka/v3/order/detail?orderNo={order_no}&biddingNo={bidding_no}"
-    
-    print("正在请求订单详情...")
-    try:
-        detail_response = requests.get(detail_url, headers=HEADERS)
-        detail_response.raise_for_status()
-        detail_data = detail_response.json()
-        
-        if detail_data.get('code') != 200:
-            print(f"请求订单详情失败: {detail_data.get('resultMessage', '未知错误')}")
-            return None
+
+# --- GUI主窗口 ---
+class MainWindow(QMainWindow):
+    def __init__(self):
+        super().__init__()
+        self.order_manager = None
+        self.order_list = []
+        self.order_details_cache = {}  # 缓存订单详情
+        self.charge_counts = {}  # 缓存充电次数
+        self.init_ui()
+
+    def init_ui(self):
+        self.setWindowTitle('爱回收订单查询工具')
+        self.setGeometry(100, 100, 1200, 800)
         
-        encrypted_hex = detail_data.get('data')
-        if not encrypted_hex:
-            print("未获取到加密数据")
-            return None
+        # 设置样式
+        self.setStyleSheet("""
+            QMainWindow {
+                background-color: #f0f0f0;
+            }
+            QGroupBox {
+                font-weight: bold;
+                border: 1px solid #ccc;
+                border-radius: 5px;
+                margin-top: 10px;
+                padding-top: 10px;
+            }
+            QGroupBox::title {
+                subcontrol-origin: margin;
+                left: 10px;
+                padding: 0 5px 0 5px;
+            }
+            QPushButton {
+                background-color: #0078d7;
+                color: white;
+                border: none;
+                padding: 8px 16px;
+                border-radius: 4px;
+                font-weight: bold;
+            }
+            QPushButton:hover {
+                background-color: #005a9e;
+            }
+            QPushButton:disabled {
+                background-color: #cccccc;
+            }
+            QLineEdit, QTextEdit {
+                border: 1px solid #ccc;
+                border-radius: 4px;
+                padding: 5px;
+            }
+            QTableWidget {
+                border: 1px solid #ccc;
+                border-radius: 4px;
+                gridline-color: #e0e0e0;
+            }
+            QTableWidget::item {
+                padding: 5px;
+            }
+            QHeaderView::section {
+                background-color: #e8e8e8;
+                padding: 5px;
+                border: 1px solid #ccc;
+                font-weight: bold;
+            }
+            QStatusBar {
+                background-color: #f0f0f0;
+                color: #333;
+            }
+            #log_text {
+                background-color: #1e1e1e;
+                color: #d4d4d4;
+                font-family: 'Consolas', 'Courier New', monospace;
+                font-size: 11px;
+            }
+        """)
+
+        # 中央部件
+        central_widget = QWidget()
+        self.setCentralWidget(central_widget)
+        main_layout = QVBoxLayout(central_widget)
+        main_layout.setSpacing(10)
+
+        # --- 顶部配置区域 ---
+        config_group = QGroupBox("配置")
+        config_layout = QGridLayout()
         
-        # 第三步:解密数据
-        print("正在解密数据...")
-        decrypted_json_string = decrypt_order_data(encrypted_hex)
-        order_detail = json.loads(decrypted_json_string)
+        # Token输入
+        config_layout.addWidget(QLabel("Access Token:"), 0, 0)
+        self.token_input = QLineEdit()
+        self.token_input.setText("jdx9ce52336abee4cf78db56567dc259512")
+        self.token_input.setEchoMode(QLineEdit.Password)
+        config_layout.addWidget(self.token_input, 0, 1)
         
-        return order_detail
+        # 显示/隐藏Token按钮
+        self.show_token_btn = QPushButton("显示")
+        self.show_token_btn.setFixedWidth(60)
+        self.show_token_btn.clicked.connect(self.toggle_token_visibility)
+        config_layout.addWidget(self.show_token_btn, 0, 2)
         
-    except requests.RequestException as e:
-        print(f"请求订单详情失败: {e}")
-        return None
-    except json.JSONDecodeError as e:
-        print(f"解析订单详情JSON失败: {e}")
-        return None
-    except Exception as e:
-        print(f"解密或解析失败: {e}")
-        return None
+        # OCR地址输入
+        config_layout.addWidget(QLabel("OCR地址:"), 1, 0)
+        self.ocr_input = QLineEdit()
+        self.ocr_input.setText("http://192.168.0.110:10001/ocr")
+        config_layout.addWidget(self.ocr_input, 1, 1, 1, 2)
+        
+        # 操作按钮
+        btn_layout = QHBoxLayout()
+        self.search_btn = QPushButton("🔍 搜索订单")
+        self.search_btn.clicked.connect(self.search_orders)
+        self.search_btn.setFixedHeight(35)
+        btn_layout.addWidget(self.search_btn)
+        
+        self.refresh_btn = QPushButton("🔄 刷新")
+        self.refresh_btn.clicked.connect(self.refresh_orders)
+        self.refresh_btn.setFixedHeight(35)
+        btn_layout.addWidget(self.refresh_btn)
+        
+        btn_layout.addStretch()
+        config_layout.addLayout(btn_layout, 2, 0, 1, 3)
+        
+        config_group.setLayout(config_layout)
+        main_layout.addWidget(config_group)
 
-# --- 7. 查找图片链接(原有功能) ---
-def find_original_image_by_notice(json_data, notice_keyword):
-    """
-    在复杂的嵌套JSON中,根据notice字段的关键词查找并返回对应的originalImage链接
-    """
-    if isinstance(json_data, str):
-        try:
-            json_data = json.loads(json_data)
-        except json.JSONDecodeError:
-            print("错误:输入的字符串不是有效的JSON格式。")
-            return None
+        # --- 订单列表 ---
+        list_group = QGroupBox("订单列表")
+        list_layout = QVBoxLayout()
+        
+        # 表格
+        self.table = QTableWidget()
+        self.table.setColumnCount(7)
+        self.table.setHorizontalHeaderLabels(["序号", "订单号", "商品信息", "IMEI", "预估价格", "门店", "充电次数"])
+        self.table.setColumnWidth(0, 50)
+        self.table.setColumnWidth(1, 200)
+        self.table.setColumnWidth(2, 250)
+        self.table.setColumnWidth(3, 150)
+        self.table.setColumnWidth(4, 100)
+        self.table.setColumnWidth(5, 200)
+        self.table.setColumnWidth(6, 100)
+        self.table.horizontalHeader().setStretchLastSection(True)
+        self.table.verticalHeader().setVisible(False)
+        
+        list_layout.addWidget(self.table)
+        list_group.setLayout(list_layout)
+        main_layout.addWidget(list_group)
+
+        # --- 日志区域 ---
+        log_group = QGroupBox("日志")
+        log_layout = QVBoxLayout()
+        
+        # 日志文本框
+        self.log_text = QTextEdit()
+        self.log_text.setObjectName("log_text")
+        self.log_text.setReadOnly(True)
+        self.log_text.setMaximumHeight(200)
+        log_layout.addWidget(self.log_text)
+        
+        # 日志控制按钮
+        log_btn_layout = QHBoxLayout()
+        self.clear_log_btn = QPushButton("清空日志")
+        self.clear_log_btn.clicked.connect(self.clear_log)
+        log_btn_layout.addWidget(self.clear_log_btn)
+        
+        log_btn_layout.addStretch()
+        log_layout.addLayout(log_btn_layout)
+        
+        log_group.setLayout(log_layout)
+        main_layout.addWidget(log_group)
+
+        # --- 底部状态栏 ---
+        self.status_bar = QStatusBar()
+        self.setStatusBar(self.status_bar)
+        self.status_bar.showMessage("就绪")
+
+    def toggle_token_visibility(self):
+        """切换Token显示/隐藏"""
+        if self.token_input.echoMode() == QLineEdit.Password:
+            self.token_input.setEchoMode(QLineEdit.Normal)
+            self.show_token_btn.setText("隐藏")
+        else:
+            self.token_input.setEchoMode(QLineEdit.Password)
+            self.show_token_btn.setText("显示")
+
+    def log_message(self, message, level="INFO"):
+        """添加日志消息"""
+        timestamp = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
+        color_map = {
+            "INFO": "#d4d4d4",
+            "WARNING": "#ffa500",
+            "ERROR": "#ff4444",
+            "SUCCESS": "#4caf50"
+        }
+        color = color_map.get(level, "#d4d4d4")
+        html = f'<span style="color: #888888;">[{timestamp}]</span> <span style="color: {color};">[{level}]</span> {message}<br>'
+        self.log_text.append(html)
+        # 滚动到底部
+        scrollbar = self.log_text.verticalScrollBar()
+        scrollbar.setValue(scrollbar.maximum())
+
+    def clear_log(self):
+        """清空日志"""
+        self.log_text.clear()
+
+    def search_orders(self):
+        """搜索订单"""
+        access_token = self.token_input.text().strip()
+        ocr_url = self.ocr_input.text().strip()
+        
+        if not access_token:
+            QMessageBox.warning(self, "提示", "请输入Access Token")
+            return
+        
+        if not ocr_url:
+            QMessageBox.warning(self, "提示", "请输入OCR地址")
+            return
+        
+        self.log_message("开始搜索订单...", "INFO")
+        
+        # 初始化订单管理器
+        self.order_manager = OrderManager(access_token, ocr_url)
+        
+        # 清空缓存
+        self.order_details_cache = {}
+        self.charge_counts = {}
+        
+        self.status_bar.showMessage("正在获取订单列表...")
+        self.search_btn.setEnabled(False)
+        
+        # 在后台线程执行
+        self.worker = OrderListWorker(self.order_manager)
+        self.worker.finished.connect(self.on_orders_loaded)
+        self.worker.error.connect(self.on_error)
+        self.worker.start()
+
+    def refresh_orders(self):
+        """刷新订单列表"""
+        if self.order_manager:
+            self.search_orders()
+        else:
+            QMessageBox.warning(self, "提示", "请先搜索订单")
 
-    def recursive_search(obj):
-        if isinstance(obj, dict):
-            if 'notice' in obj and 'originalImage' in obj:
-                if notice_keyword.lower() in obj['notice'].lower():
-                    return obj['originalImage']
+    def on_orders_loaded(self, order_list):
+        """订单列表加载完成"""
+        self.order_list = order_list
+        self.display_orders()
+        self.search_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.status_bar.showMessage("加载失败")
+        self.log_message(f"获取订单列表失败: {error_msg}", "ERROR")
+        QMessageBox.critical(self, "错误", f"获取订单列表失败:\n{error_msg}")
+
+    def display_orders(self):
+        """显示订单列表"""
+        self.table.setRowCount(len(self.order_list))
+        
+        for i, order in enumerate(self.order_list):
+            # 序号
+            self.table.setItem(i, 0, QTableWidgetItem(str(i + 1)))
+            
+            # 订单号
+            order_no = order.get('orderNo', '')
+            self.table.setItem(i, 1, QTableWidgetItem(order_no))
+            
+            # 商品信息
+            brand_info = order.get('brandInfo', '')
+            self.table.setItem(i, 2, QTableWidgetItem(brand_info))
+            
+            # IMEI
+            imei = order.get('imei', '')
+            self.table.setItem(i, 3, QTableWidgetItem(imei))
+            
+            # 预估价格
+            price = order.get('price', '')
+            price_str = str(price) if price else '待定'
+            self.table.setItem(i, 4, QTableWidgetItem(price_str))
+            
+            # 门店
+            title = order.get('title', '')
+            self.table.setItem(i, 5, QTableWidgetItem(title))
+            
+            # 充电次数(初始为空,显示"查询"按钮)
+            charge_widget = QWidget()
+            charge_layout = QHBoxLayout(charge_widget)
+            charge_layout.setContentsMargins(5, 2, 5, 2)
+            charge_layout.setSpacing(5)
+            
+            charge_label = QLabel("未查询")
+            charge_label.setObjectName(f"charge_label_{i}")
+            charge_layout.addWidget(charge_label)
             
-            for value in obj.values():
-                result = recursive_search(value)
-                if result:
-                    return result
+            check_btn = QPushButton("查询")
+            check_btn.setFixedSize(50, 25)
+            check_btn.setObjectName(f"check_btn_{i}")
+            check_btn.clicked.connect(lambda checked, idx=i: self.check_charge_count(idx))
+            charge_layout.addWidget(check_btn)
+            
+            charge_widget.setLayout(charge_layout)
+            self.table.setCellWidget(i, 6, charge_widget)
+
+    def check_charge_count(self, index):
+        """查询充电次数"""
+        if not self.order_manager:
+            return
         
-        elif isinstance(obj, list):
-            for item in obj:
-                result = recursive_search(item)
-                if result:
-                    return result
+        if index >= len(self.order_list):
+            return
         
-        return None
+        order_no = self.order_list[index].get('orderNo')
+        if not order_no:
+            return
+        
+        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} 的充电次数...")
+        
+        # 禁用按钮
+        btn = self.findChild(QPushButton, f"check_btn_{index}")
+        if btn:
+            btn.setEnabled(False)
+            btn.setText("查询中")
+        
+        # 在后台线程执行
+        self.charge_worker = ChargeQueryWorker(self.order_manager, order_no, index)
+        self.charge_worker.finished.connect(self.on_charge_queried)
+        self.charge_worker.error.connect(self.on_charge_error)
+        self.charge_worker.start()
 
-    return recursive_search(json_data)
+    def on_charge_queried(self, index, charge_count, ocr_result, image_notices):
+        """充电次数查询完成"""
+        order_no = self.order_list[index].get('orderNo')
+        
+        # 如果没有找到充电次数,输出详细信息
+        if charge_count is None:
+            if ocr_result:
+                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")
+                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:
+                self.log_message(f"订单 {order_no} 未找到验机图片", "ERROR")
+        else:
+            self.log_message(f"订单 {order_no} 充电次数: {charge_count}", "SUCCESS")
+        
+        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.status_bar.showMessage(f"订单 {order_no} 充电次数: {charge_count}")
+        else:
+            self.status_bar.showMessage(f"订单 {order_no} 未找到充电次数信息")
 
-# --- 8. 主流程(新增列表获取功能) ---
-def main():
-    # 步骤1:获取待抢订单列表
-    print("正在获取待抢订单列表...")
-    order_list = get_pending_order_list(page_size=10)
-    
-    if not order_list:
-        print("无法获取订单列表,程序退出")
-        return
-    
-    # 步骤2:显示列表
-    display_order_list(order_list)
-    
-    # 步骤3:让用户选择要查看的订单
-    while True:
+    def on_charge_error(self, index, error_msg):
+        """充电次数查询错误"""
+        order_no = self.order_list[index].get('orderNo')
+        self.log_message(f"订单 {order_no} 查询失败: {error_msg}", "ERROR")
+        
+        btn = self.findChild(QPushButton, f"check_btn_{index}")
+        if btn:
+            btn.setEnabled(True)
+            btn.setText("查询")
+        
+        self.status_bar.showMessage(f"查询失败: {error_msg}")
+        QMessageBox.warning(self, "查询失败", f"获取订单详情失败:\n{error_msg}")
+
+    def update_charge_display(self, index, charge_count):
+        """更新充电次数显示"""
+        widget = self.table.cellWidget(index, 6)
+        if widget:
+            label = widget.findChild(QLabel)
+            if label:
+                if charge_count is not None:
+                    label.setText(f"{charge_count} 次")
+                    label.setStyleSheet("color: #28a745; font-weight: bold;")
+                else:
+                    label.setText("未找到")
+                    label.setStyleSheet("color: #dc3545;")
+
+# --- 后台工作线程 ---
+class OrderListWorker(QThread):
+    finished = pyqtSignal(list)
+    error = pyqtSignal(str)
+
+    def __init__(self, order_manager):
+        super().__init__()
+        self.order_manager = order_manager
+
+    def run(self):
+        try:
+            order_list, error = self.order_manager.get_pending_order_list()
+            if error:
+                self.error.emit(error)
+            else:
+                self.finished.emit(order_list)
+        except Exception as e:
+            self.error.emit(str(e))
+
+class ChargeQueryWorker(QThread):
+    finished = pyqtSignal(int, object, object, list)  # index, charge_count, ocr_result, image_notices
+    error = pyqtSignal(int, str)
+
+    def __init__(self, order_manager, order_no, index):
+        super().__init__()
+        self.order_manager = order_manager
+        self.order_no = order_no
+        self.index = index
+
+    def run(self):
         try:
-            choice = input("\n请输入要查看详情的订单序号 (1-{},输入0退出): ".format(len(order_list)))
-            choice = int(choice.strip())
+            # 获取订单详情
+            order_detail, error = self.order_manager.get_order_detail(self.order_no)
+            if error:
+                self.error.emit(self.index, error)
+                return
+            
+            # 查找所有图片的notice
+            image_notices = self.order_manager.get_all_image_notices(order_detail)
             
-            if choice == 0:
-                print("程序退出")
+            # 查找验机图片
+            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 not report_img:
+                # 没有找到图片,返回notice列表
+                self.finished.emit(self.index, None, None, image_notices)
                 return
             
-            if 1 <= choice <= len(order_list):
-                break
-            else:
-                print(f"请输入1-{len(order_list)}之间的数字")
-        except ValueError:
-            print("请输入有效的数字")
-        except KeyboardInterrupt:
-            print("\n程序被中断")
-            return
-    
-    # 步骤4:获取选中的订单号
-    order_no = select_order_by_index(order_list, choice)
-    if not order_no:
-        print("获取订单号失败")
-        return
-    
-    # 步骤5:获取订单详情
-    order_detail = get_order_detail(order_no)
-    if not order_detail:
-        print("获取订单详情失败")
-        return
+            # OCR识别
+            ocr_result = self.order_manager.download_and_ocr_image(report_img)
+            if not ocr_result:
+                # OCR失败,返回notice列表
+                self.finished.emit(self.index, None, None, image_notices)
+                return
+            
+            # 提取充电次数
+            ocr_text = self.order_manager.extract_text_from_ocr_result(ocr_result)
+            charge_count = self.order_manager.extract_charge_count(ocr_text)
+            
+            self.finished.emit(self.index, charge_count, ocr_result, image_notices)
+            
+        except Exception as e:
+            self.error.emit(self.index, str(e))
+
+# --- 主程序入口 ---
+def main():
+    app = QApplication(sys.argv)
+    app.setStyle('Fusion')
     
-    # 步骤6:输出结果
-    print("\n=== 解密后的订单详情 ===")
-    print(json.dumps(order_detail, indent=2, ensure_ascii=False))
+    # 设置应用图标
+    app.setWindowIcon(QIcon())
     
-    # 步骤7:查找图片链接
-    report_img = find_original_image_by_notice(order_detail, "苹果沙漏验机报告")
-    if report_img is None:
-        report_img = find_original_image_by_notice(order_detail, "验机照片")
+    window = MainWindow()
+    window.show()
     
-    if report_img:
-        print(f"\n找到验机报告图片: {report_img}")
-    else:
-        print("\n未找到验机报告图片")
+    sys.exit(app.exec_())
 
 if __name__ == "__main__":
     main()