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 *
# --- 核心功能类 ---
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"
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=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}
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)
# 获取订单详情
detail_url = f"https://wirelessgate.aihuishou.com/jdx-qa-service/app/ka/v3/order/detail?orderNo={order_no}&biddingNo={bidding_no}"
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)
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
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)
recursive_search(json_data)
return list(set(notices)) # 去重
def ocr_by_url(self, image_url):
"""通过URL进行OCR识别"""
try:
# 构建请求数据
payload = {"url": image_url}
# 发送POST请求
response = requests.post(self.ocr_url, json=payload, timeout=60)
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
except Exception as e:
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 ''
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):
"""提取充电次数"""
# 匹配(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主窗口 ---
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.order_manager = None
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):
self.setWindowTitle('爱回收订单查询工具')
self.setGeometry(100, 100, 1200, 800)
# 设置样式
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;
}
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;
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;
}
QProgressBar {
border: 1px solid #ccc;
border-radius: 4px;
text-align: center;
}
QProgressBar::chunk {
background-color: #0078d7;
border-radius: 4px;
}
""")
# 中央部件
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
main_layout.setSpacing(10)
# --- 顶部配置区域 ---
config_group = QGroupBox("配置")
config_layout = QGridLayout()
# 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)
# 显示/隐藏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)
# OCR地址输入
config_layout.addWidget(QLabel("OCR地址:"), 1, 0)
self.ocr_input = QLineEdit()
self.ocr_input.setText("http://111.229.45.38:19100/ocr/url")
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)
# 一键获取所有充电次数按钮
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)
config_group.setLayout(config_layout)
main_layout.addWidget(config_group)
# --- 订单列表 ---
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)
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",
"PROGRESS": "#00bcd4"
}
color = color_map.get(level, "#d4d4d4")
html = f'[{timestamp}] [{level}] {message}
'
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.batch_btn.setEnabled(False)
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 on_orders_loaded(self, order_list):
"""订单列表加载完成"""
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}")
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)
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
if index >= len(self.order_list):
return
order_no = self.order_list[index].get('orderNo')
if not order_no:
return
self.log_message(f"开始查询订单 {order_no} 的充电次数", "INFO")
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()
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')
# 如果没有找到充电次数,输出详细信息
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}", "INFO")
else:
self.log_message(f"OCR文本为空", "WARNING")
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")
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} 未找到充电次数信息")
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(100)
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:
# 获取订单详情
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)
# 查找验机图片
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, "验机报告")
if not report_img:
# 没有找到图片,返回notice列表
self.finished.emit(self.index, None, None, image_notices)
return
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)
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')
# 设置应用图标
app.setWindowIcon(QIcon())
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()