|
|
@@ -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()
|