|
@@ -8,12 +8,13 @@ import uuid
|
|
|
import time
|
|
import time
|
|
|
import os
|
|
import os
|
|
|
import configparser
|
|
import configparser
|
|
|
|
|
+import re
|
|
|
|
|
|
|
|
class PhoneQueryApp:
|
|
class PhoneQueryApp:
|
|
|
def __init__(self, root):
|
|
def __init__(self, root):
|
|
|
self.root = root
|
|
self.root = root
|
|
|
self.root.title("手机数据查询系统")
|
|
self.root.title("手机数据查询系统")
|
|
|
- self.root.geometry("1300x850")
|
|
|
|
|
|
|
+ self.root.geometry("1300x920") # 增加高度以容纳新控件
|
|
|
|
|
|
|
|
# 配置文件
|
|
# 配置文件
|
|
|
self.config_file = "config.ini"
|
|
self.config_file = "config.ini"
|
|
@@ -26,13 +27,31 @@ class PhoneQueryApp:
|
|
|
self.total_pages = 0
|
|
self.total_pages = 0
|
|
|
self.page_size = 30
|
|
self.page_size = 30
|
|
|
self.current_keyword = ""
|
|
self.current_keyword = ""
|
|
|
|
|
+ self.current_sort = "sort_composite" # 默认综合排序
|
|
|
|
|
+
|
|
|
|
|
+ # 自动检测相关变量
|
|
|
|
|
+ self.auto_detect_running = False
|
|
|
|
|
+ self.auto_detect_stop = False
|
|
|
|
|
+ self.auto_detect_page = 0
|
|
|
|
|
+ self.auto_detect_products = []
|
|
|
|
|
+ self.auto_detect_thread = None
|
|
|
|
|
+ self.auto_collect_count = 0
|
|
|
|
|
+ self.auto_check_count = 0
|
|
|
|
|
+
|
|
|
|
|
+ # 排序选项映射
|
|
|
|
|
+ self.sort_map = {
|
|
|
|
|
+ "综合排序": "sort_composite",
|
|
|
|
|
+ "价格从低到高": "sort_price_asc",
|
|
|
|
|
+ "价格从高到低": "sort_price_desc"
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
# 筛选选项映射
|
|
# 筛选选项映射
|
|
|
self.memory_map = {
|
|
self.memory_map = {
|
|
|
"1T": 187,
|
|
"1T": 187,
|
|
|
"512G": 192,
|
|
"512G": 192,
|
|
|
"256G": 209,
|
|
"256G": 209,
|
|
|
- "128G": 210
|
|
|
|
|
|
|
+ "128G": 210,
|
|
|
|
|
+ "64G": 217,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
self.battery_map = {
|
|
self.battery_map = {
|
|
@@ -118,7 +137,7 @@ class PhoneQueryApp:
|
|
|
self.root.columnconfigure(0, weight=1)
|
|
self.root.columnconfigure(0, weight=1)
|
|
|
self.root.rowconfigure(0, weight=1)
|
|
self.root.rowconfigure(0, weight=1)
|
|
|
main_frame.columnconfigure(0, weight=1)
|
|
main_frame.columnconfigure(0, weight=1)
|
|
|
- main_frame.rowconfigure(5, weight=1)
|
|
|
|
|
|
|
+ main_frame.rowconfigure(6, weight=1) # 调整行索引
|
|
|
|
|
|
|
|
# Token设置区域
|
|
# Token设置区域
|
|
|
token_frame = ttk.LabelFrame(main_frame, text="Token设置", padding="10")
|
|
token_frame = ttk.LabelFrame(main_frame, text="Token设置", padding="10")
|
|
@@ -137,14 +156,26 @@ class PhoneQueryApp:
|
|
|
query_frame = ttk.LabelFrame(main_frame, text="查询条件", padding="10")
|
|
query_frame = ttk.LabelFrame(main_frame, text="查询条件", padding="10")
|
|
|
query_frame.grid(row=1, column=0, sticky=(tk.W, tk.E), pady=(0, 10))
|
|
query_frame.grid(row=1, column=0, sticky=(tk.W, tk.E), pady=(0, 10))
|
|
|
query_frame.columnconfigure(1, weight=1)
|
|
query_frame.columnconfigure(1, weight=1)
|
|
|
|
|
+ query_frame.columnconfigure(3, weight=1)
|
|
|
|
|
|
|
|
|
|
+ # 机型输入
|
|
|
ttk.Label(query_frame, text="机型:", font=("Arial", 11)).grid(row=0, column=0, sticky=tk.W, padx=(0, 10))
|
|
ttk.Label(query_frame, text="机型:", font=("Arial", 11)).grid(row=0, column=0, sticky=tk.W, padx=(0, 10))
|
|
|
- self.model_entry = ttk.Entry(query_frame, width=50, font=("Arial", 11))
|
|
|
|
|
|
|
+ self.model_entry = ttk.Entry(query_frame, width=35, font=("Arial", 11))
|
|
|
self.model_entry.grid(row=0, column=1, sticky=(tk.W, tk.E), padx=(0, 10))
|
|
self.model_entry.grid(row=0, column=1, sticky=(tk.W, tk.E), padx=(0, 10))
|
|
|
self.model_entry.insert(0, "iPhone 15 Pro")
|
|
self.model_entry.insert(0, "iPhone 15 Pro")
|
|
|
|
|
|
|
|
|
|
+ # 排序选择
|
|
|
|
|
+ ttk.Label(query_frame, text="排序方式:", font=("Arial", 11)).grid(row=0, column=2, sticky=tk.W, padx=(10, 10))
|
|
|
|
|
+ self.sort_var = tk.StringVar(value="综合排序")
|
|
|
|
|
+ self.sort_combo = ttk.Combobox(query_frame, textvariable=self.sort_var,
|
|
|
|
|
+ values=["综合排序", "价格从低到高", "价格从高到低", "最新上架", "人气最高"],
|
|
|
|
|
+ width=15, state="readonly", font=("Arial", 10))
|
|
|
|
|
+ self.sort_combo.grid(row=0, column=3, sticky=(tk.W, tk.E), padx=(0, 10))
|
|
|
|
|
+ self.sort_combo.bind('<<ComboboxSelected>>', self.on_sort_changed)
|
|
|
|
|
+
|
|
|
|
|
+ # 搜索按钮
|
|
|
self.search_btn = ttk.Button(query_frame, text="搜索", command=self.search_products, width=15)
|
|
self.search_btn = ttk.Button(query_frame, text="搜索", command=self.search_products, width=15)
|
|
|
- self.search_btn.grid(row=0, column=2)
|
|
|
|
|
|
|
+ self.search_btn.grid(row=0, column=4)
|
|
|
|
|
|
|
|
# ==================== 筛选区域 ====================
|
|
# ==================== 筛选区域 ====================
|
|
|
# 第一行:内存 + 电池效率(各占一半)
|
|
# 第一行:内存 + 电池效率(各占一半)
|
|
@@ -211,9 +242,39 @@ class PhoneQueryApp:
|
|
|
cb = ttk.Checkbutton(condition_frame, text=tag_name, variable=var)
|
|
cb = ttk.Checkbutton(condition_frame, text=tag_name, variable=var)
|
|
|
cb.grid(row=row, column=col, sticky=tk.W, padx=10, pady=3)
|
|
cb.grid(row=row, column=col, sticky=tk.W, padx=10, pady=3)
|
|
|
|
|
|
|
|
|
|
+ # ==================== 自动检测区域 ====================
|
|
|
|
|
+ auto_detect_frame = ttk.LabelFrame(main_frame, text="自动检测与收藏", padding="10")
|
|
|
|
|
+ auto_detect_frame.grid(row=4, column=0, sticky=(tk.W, tk.E), pady=(0, 10))
|
|
|
|
|
+ auto_detect_frame.columnconfigure(2, weight=1)
|
|
|
|
|
+
|
|
|
|
|
+ # 循环次数阈值设置
|
|
|
|
|
+ ttk.Label(auto_detect_frame, text="循环次数少于:", font=("Arial", 10)).grid(row=0, column=0, sticky=tk.W, padx=(0, 5))
|
|
|
|
|
+ self.cycle_threshold_var = tk.StringVar(value="100")
|
|
|
|
|
+ self.cycle_threshold_entry = ttk.Entry(auto_detect_frame, textvariable=self.cycle_threshold_var, width=10)
|
|
|
|
|
+ self.cycle_threshold_entry.grid(row=0, column=1, sticky=tk.W, padx=(0, 10))
|
|
|
|
|
+ ttk.Label(auto_detect_frame, text="次", font=("Arial", 10)).grid(row=0, column=2, sticky=tk.W, padx=(0, 20))
|
|
|
|
|
+
|
|
|
|
|
+ # 启动按钮
|
|
|
|
|
+ self.start_auto_btn = ttk.Button(auto_detect_frame, text="🚀 启动自动检测", command=self.start_auto_detect, width=18)
|
|
|
|
|
+ self.start_auto_btn.grid(row=0, column=3, padx=(0, 10))
|
|
|
|
|
+
|
|
|
|
|
+ # 停止按钮
|
|
|
|
|
+ self.stop_auto_btn = ttk.Button(auto_detect_frame, text="⏹ 停止", command=self.stop_auto_detect, width=12, state="disabled")
|
|
|
|
|
+ self.stop_auto_btn.grid(row=0, column=4, padx=(0, 20))
|
|
|
|
|
+
|
|
|
|
|
+ # 自动检测状态显示(使用Label而不是StringVar)
|
|
|
|
|
+ self.auto_status_label = ttk.Label(auto_detect_frame, text="自动检测未启动", font=("Arial", 9))
|
|
|
|
|
+ self.auto_status_label.grid(row=0, column=5, sticky=tk.W)
|
|
|
|
|
+
|
|
|
|
|
+ # 统计信息
|
|
|
|
|
+ self.auto_stats_var = tk.StringVar()
|
|
|
|
|
+ self.auto_stats_var.set("检测: 0 | 收藏: 0")
|
|
|
|
|
+ stats_label = ttk.Label(auto_detect_frame, textvariable=self.auto_stats_var, font=("Arial", 9))
|
|
|
|
|
+ stats_label.grid(row=0, column=6, sticky=tk.W, padx=(20, 0))
|
|
|
|
|
+
|
|
|
# ==================== 结果显示区域 ====================
|
|
# ==================== 结果显示区域 ====================
|
|
|
result_frame = ttk.LabelFrame(main_frame, text="查询结果(可多选商品,点击批量收藏)", padding="10")
|
|
result_frame = ttk.LabelFrame(main_frame, text="查询结果(可多选商品,点击批量收藏)", padding="10")
|
|
|
- result_frame.grid(row=4, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
|
|
|
|
|
|
|
+ result_frame.grid(row=5, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
|
|
|
result_frame.columnconfigure(0, weight=1)
|
|
result_frame.columnconfigure(0, weight=1)
|
|
|
result_frame.rowconfigure(0, weight=1)
|
|
result_frame.rowconfigure(0, weight=1)
|
|
|
|
|
|
|
@@ -246,7 +307,7 @@ class PhoneQueryApp:
|
|
|
|
|
|
|
|
# ==================== 底部按钮栏 ====================
|
|
# ==================== 底部按钮栏 ====================
|
|
|
bottom_frame = ttk.Frame(main_frame)
|
|
bottom_frame = ttk.Frame(main_frame)
|
|
|
- bottom_frame.grid(row=5, column=0, sticky=(tk.W, tk.E), pady=(10, 5))
|
|
|
|
|
|
|
+ bottom_frame.grid(row=6, column=0, sticky=(tk.W, tk.E), pady=(10, 5))
|
|
|
|
|
|
|
|
self.check_price_btn = ttk.Button(bottom_frame, text="获取循环次数", command=self.check_prices, width=18)
|
|
self.check_price_btn = ttk.Button(bottom_frame, text="获取循环次数", command=self.check_prices, width=18)
|
|
|
self.check_price_btn.pack(side=tk.LEFT, padx=(0, 10))
|
|
self.check_price_btn.pack(side=tk.LEFT, padx=(0, 10))
|
|
@@ -260,7 +321,7 @@ class PhoneQueryApp:
|
|
|
|
|
|
|
|
# ==================== 分页栏 ====================
|
|
# ==================== 分页栏 ====================
|
|
|
pagination_frame = ttk.Frame(main_frame)
|
|
pagination_frame = ttk.Frame(main_frame)
|
|
|
- pagination_frame.grid(row=6, column=0, sticky=(tk.W, tk.E), pady=(0, 5))
|
|
|
|
|
|
|
+ pagination_frame.grid(row=7, column=0, sticky=(tk.W, tk.E), pady=(0, 5))
|
|
|
|
|
|
|
|
self.prev_btn = ttk.Button(pagination_frame, text="上一页", command=self.prev_page, width=10)
|
|
self.prev_btn = ttk.Button(pagination_frame, text="上一页", command=self.prev_page, width=10)
|
|
|
self.prev_btn.pack(side=tk.LEFT, padx=(0, 10))
|
|
self.prev_btn.pack(side=tk.LEFT, padx=(0, 10))
|
|
@@ -283,7 +344,7 @@ class PhoneQueryApp:
|
|
|
|
|
|
|
|
# ==================== 状态栏 ====================
|
|
# ==================== 状态栏 ====================
|
|
|
status_frame = ttk.Frame(main_frame)
|
|
status_frame = ttk.Frame(main_frame)
|
|
|
- status_frame.grid(row=7, column=0, sticky=(tk.W, tk.E), pady=(5, 0))
|
|
|
|
|
|
|
+ status_frame.grid(row=8, column=0, sticky=(tk.W, tk.E), pady=(5, 0))
|
|
|
|
|
|
|
|
self.status_var = tk.StringVar()
|
|
self.status_var = tk.StringVar()
|
|
|
self.status_var.set("就绪")
|
|
self.status_var.set("就绪")
|
|
@@ -292,6 +353,11 @@ class PhoneQueryApp:
|
|
|
|
|
|
|
|
self.update_pagination_buttons()
|
|
self.update_pagination_buttons()
|
|
|
|
|
|
|
|
|
|
+ def on_sort_changed(self, event=None):
|
|
|
|
|
+ """排序方式改变时自动搜索"""
|
|
|
|
|
+ if self.model_entry.get().strip():
|
|
|
|
|
+ self.search_products()
|
|
|
|
|
+
|
|
|
def get_selected_memory(self):
|
|
def get_selected_memory(self):
|
|
|
"""获取选中的内存PPV ID列表"""
|
|
"""获取选中的内存PPV ID列表"""
|
|
|
selected = []
|
|
selected = []
|
|
@@ -349,6 +415,8 @@ class PhoneQueryApp:
|
|
|
|
|
|
|
|
self.current_keyword = keyword
|
|
self.current_keyword = keyword
|
|
|
self.current_page = page
|
|
self.current_page = page
|
|
|
|
|
+ # 获取当前选中的排序方式
|
|
|
|
|
+ self.current_sort = self.sort_map.get(self.sort_var.get(), "sort_composite")
|
|
|
|
|
|
|
|
for item in self.result_tree.get_children():
|
|
for item in self.result_tree.get_children():
|
|
|
self.result_tree.delete(item)
|
|
self.result_tree.delete(item)
|
|
@@ -376,7 +444,7 @@ class PhoneQueryApp:
|
|
|
condition_tags = self.get_selected_condition_tags()
|
|
condition_tags = self.get_selected_condition_tags()
|
|
|
|
|
|
|
|
request_data = {
|
|
request_data = {
|
|
|
- "sortValue": "sort_composite",
|
|
|
|
|
|
|
+ "sortValue": self.current_sort, # 使用当前选中的排序方式
|
|
|
"scene": "search",
|
|
"scene": "search",
|
|
|
"keyword": keyword,
|
|
"keyword": keyword,
|
|
|
"sirReq": False,
|
|
"sirReq": False,
|
|
@@ -497,7 +565,8 @@ class PhoneQueryApp:
|
|
|
'info': info
|
|
'info': info
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
- self.status_var.set(f"第 {page + 1} 页,共找到 {len(data)} 条结果")
|
|
|
|
|
|
|
+ sort_name = self.sort_var.get()
|
|
|
|
|
+ self.status_var.set(f"第 {page + 1} 页,排序: {sort_name},共找到 {len(data)} 条结果")
|
|
|
self.update_pagination_buttons()
|
|
self.update_pagination_buttons()
|
|
|
|
|
|
|
|
def update_pagination_buttons(self):
|
|
def update_pagination_buttons(self):
|
|
@@ -711,8 +780,264 @@ class PhoneQueryApp:
|
|
|
self.status_var.set(f"✗ 收藏失败: {msg}")
|
|
self.status_var.set(f"✗ 收藏失败: {msg}")
|
|
|
messagebox.showerror("收藏失败", f"收藏失败\n{product['info']['name']}\n错误: {msg}")
|
|
messagebox.showerror("收藏失败", f"收藏失败\n{product['info']['name']}\n错误: {msg}")
|
|
|
return
|
|
return
|
|
|
|
|
+
|
|
|
|
|
+ # ==================== 自动检测功能 ====================
|
|
|
|
|
+ def start_auto_detect(self):
|
|
|
|
|
+ """启动自动检测"""
|
|
|
|
|
+ # 检查是否已启动
|
|
|
|
|
+ if self.auto_detect_running:
|
|
|
|
|
+ messagebox.showinfo("提示", "自动检测已在运行中")
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ # 检查是否有搜索关键词
|
|
|
|
|
+ keyword = self.model_entry.get().strip()
|
|
|
|
|
+ if not keyword:
|
|
|
|
|
+ messagebox.showwarning("警告", "请先输入要搜索的机型")
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ # 获取阈值
|
|
|
|
|
+ try:
|
|
|
|
|
+ threshold = int(self.cycle_threshold_var.get().strip())
|
|
|
|
|
+ if threshold < 0:
|
|
|
|
|
+ raise ValueError("阈值不能为负数")
|
|
|
|
|
+ except ValueError:
|
|
|
|
|
+ messagebox.showerror("错误", "请输入有效的循环次数阈值(正整数)")
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ # 确认启动
|
|
|
|
|
+ result = messagebox.askyesno("确认启动",
|
|
|
|
|
+ f"将自动检测所有符合条件的商品\n"
|
|
|
|
|
+ f"机型: {keyword}\n"
|
|
|
|
|
+ f"循环次数阈值: {threshold} 次\n\n"
|
|
|
|
|
+ f"检测到的商品将自动收藏,是否继续?")
|
|
|
|
|
+ if not result:
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ # 重置状态
|
|
|
|
|
+ self.auto_detect_running = True
|
|
|
|
|
+ self.auto_detect_stop = False
|
|
|
|
|
+ self.auto_detect_page = 0
|
|
|
|
|
+ self.auto_detect_products = []
|
|
|
|
|
+ self.auto_collect_count = 0
|
|
|
|
|
+ self.auto_check_count = 0
|
|
|
|
|
+
|
|
|
|
|
+ # 更新UI状态
|
|
|
|
|
+ self.start_auto_btn.config(state="disabled")
|
|
|
|
|
+ self.stop_auto_btn.config(state="normal")
|
|
|
|
|
+ self.auto_status_label.config(text="🔄 正在检测中...", foreground="blue")
|
|
|
|
|
+ self.auto_stats_var.set("检测: 0 | 收藏: 0")
|
|
|
|
|
+
|
|
|
|
|
+ # 清空当前显示
|
|
|
|
|
+ for item in self.result_tree.get_children():
|
|
|
|
|
+ self.result_tree.delete(item)
|
|
|
|
|
+ self.current_products.clear()
|
|
|
|
|
+
|
|
|
|
|
+ # 启动检测线程
|
|
|
|
|
+ self.auto_detect_thread = threading.Thread(target=self.auto_detect_loop, args=(keyword, threshold))
|
|
|
|
|
+ self.auto_detect_thread.daemon = True
|
|
|
|
|
+ self.auto_detect_thread.start()
|
|
|
|
|
+
|
|
|
|
|
+ def stop_auto_detect(self):
|
|
|
|
|
+ """停止自动检测"""
|
|
|
|
|
+ if self.auto_detect_running:
|
|
|
|
|
+ self.auto_detect_stop = True
|
|
|
|
|
+ self.auto_status_label.config(text="⏹ 正在停止...", foreground="orange")
|
|
|
|
|
+ self.stop_auto_btn.config(state="disabled")
|
|
|
|
|
+
|
|
|
|
|
+ def auto_detect_loop(self, keyword, threshold):
|
|
|
|
|
+ """自动检测循环"""
|
|
|
|
|
+ page = 0
|
|
|
|
|
+ total_collected = 0
|
|
|
|
|
+ total_checked = 0
|
|
|
|
|
+
|
|
|
|
|
+ while not self.auto_detect_stop:
|
|
|
|
|
+ try:
|
|
|
|
|
+ # 搜索商品
|
|
|
|
|
+ self.root.after(0, lambda: self.auto_status_label.config(
|
|
|
|
|
+ text=f"🔄 正在检测第 {page + 1} 页...", foreground="blue"))
|
|
|
|
|
+
|
|
|
|
|
+ # 执行搜索
|
|
|
|
|
+ memory_ids = self.get_selected_memory()
|
|
|
|
|
+ battery_ids = self.get_selected_battery()
|
|
|
|
|
+ fineness_ids = self.get_selected_fineness()
|
|
|
|
|
+ condition_tags = self.get_selected_condition_tags()
|
|
|
|
|
+
|
|
|
|
|
+ request_data = {
|
|
|
|
|
+ "sortValue": "sort_composite",
|
|
|
|
|
+ "scene": "search",
|
|
|
|
|
+ "keyword": keyword,
|
|
|
|
|
+ "sirReq": False,
|
|
|
|
|
+ "cityId": 324,
|
|
|
|
|
+ "pageIndex": page,
|
|
|
|
|
+ "pageSize": self.page_size
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if memory_ids:
|
|
|
|
|
+ request_data["gaeaSkuPpvIds"] = {"22": memory_ids}
|
|
|
|
|
+ if battery_ids:
|
|
|
|
|
+ request_data["gaeaPricePpvIds"] = {"473": battery_ids}
|
|
|
|
|
+ if fineness_ids:
|
|
|
|
|
+ request_data["gaeaFinenessIds"] = fineness_ids
|
|
|
|
|
+ if condition_tags:
|
|
|
|
|
+ request_data["conditionTagList"] = condition_tags
|
|
|
|
|
+
|
|
|
|
|
+ url = "https://dubai-mp.aihuishou.com/ahs-yanxuan-service/products/search-goods-v2"
|
|
|
|
|
+ response = requests.post(url, json=request_data, headers=self.get_headers(), timeout=30)
|
|
|
|
|
+ result = response.json()
|
|
|
|
|
+
|
|
|
|
|
+ if result.get('code') != 0:
|
|
|
|
|
+ self.root.after(0, lambda: self.show_error(f"搜索失败: {result.get('resultMessage', '未知错误')}"))
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ data = result.get('data', [])
|
|
|
|
|
+ total_count = result.get('totalCount', 0)
|
|
|
|
|
+
|
|
|
|
|
+ # 计算总页数
|
|
|
|
|
+ if total_count > 0:
|
|
|
|
|
+ total_pages = (total_count + self.page_size - 1) // self.page_size
|
|
|
|
|
+ else:
|
|
|
|
|
+ total_pages = page + 1 if len(data) < self.page_size else page + 2
|
|
|
|
|
+
|
|
|
|
|
+ # 如果没有数据,结束
|
|
|
|
|
+ if not data:
|
|
|
|
|
+ self.root.after(0, lambda: self.auto_status_label.config(
|
|
|
|
|
+ text="✅ 检测完成,没有更多商品", foreground="green"))
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ # 处理当前页商品
|
|
|
|
|
+ page_collected = 0
|
|
|
|
|
+ for product in data:
|
|
|
|
|
+ if self.auto_detect_stop:
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ total_checked += 1
|
|
|
|
|
+
|
|
|
|
|
+ # 获取商品信息
|
|
|
|
|
+ sale_goods_no = product.get('saleGoodsNo', '')
|
|
|
|
|
+ product_no = product.get('productNo', '')
|
|
|
|
|
+ name = product.get('name', '')
|
|
|
|
|
+
|
|
|
|
|
+ # 获取循环次数
|
|
|
|
|
+ cycle_count = self.get_cycle_count(sale_goods_no)
|
|
|
|
|
+
|
|
|
|
|
+ # 解析循环次数为数字
|
|
|
|
|
+ cycle_num = 0
|
|
|
|
|
+ if cycle_count:
|
|
|
|
|
+ try:
|
|
|
|
|
+ # 尝试提取数字
|
|
|
|
|
+ numbers = re.findall(r'\d+', cycle_count)
|
|
|
|
|
+ if numbers:
|
|
|
|
|
+ cycle_num = int(numbers[0])
|
|
|
|
|
+ except:
|
|
|
|
|
+ pass
|
|
|
|
|
+
|
|
|
|
|
+ # 判断是否满足条件
|
|
|
|
|
+ if cycle_num > 0 and cycle_num <= threshold:
|
|
|
|
|
+ # 满足条件,收藏
|
|
|
|
|
+ item_no = product_no or sale_goods_no
|
|
|
|
|
+ success, msg = self.add_to_collection(item_no)
|
|
|
|
|
+
|
|
|
|
|
+ if success:
|
|
|
|
|
+ total_collected += 1
|
|
|
|
|
+ page_collected += 1
|
|
|
|
|
+ # 在列表中显示
|
|
|
|
|
+ self.root.after(0, lambda p=product, c=cycle_count: self.display_auto_collected(p, c))
|
|
|
|
|
+ else:
|
|
|
|
|
+ # 收藏失败,记录日志
|
|
|
|
|
+ print(f"自动收藏失败: {name} - {msg}")
|
|
|
|
|
+
|
|
|
|
|
+ # 更新统计
|
|
|
|
|
+ self.root.after(0, lambda tc=total_checked, tl=total_collected:
|
|
|
|
|
+ self.auto_stats_var.set(f"检测: {tc} | 收藏: {tl}"))
|
|
|
|
|
+
|
|
|
|
|
+ # 延时避免请求过快
|
|
|
|
|
+ time.sleep(0.2)
|
|
|
|
|
+
|
|
|
|
|
+ # 更新页面信息
|
|
|
|
|
+ self.root.after(0, lambda p=page+1, pc=page_collected, tc=total_checked, tl=total_collected:
|
|
|
|
|
+ self.auto_status_label.config(
|
|
|
|
|
+ text=f"🔄 第 {p} 页完成,本页收藏 {pc} 个", foreground="blue"))
|
|
|
|
|
+
|
|
|
|
|
+ # 检查是否到达最后一页
|
|
|
|
|
+ if page >= total_pages - 1 or len(data) < self.page_size:
|
|
|
|
|
+ self.root.after(0, lambda: self.auto_status_label.config(
|
|
|
|
|
+ text="✅ 检测完成!已检测所有页面", foreground="green"))
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ page += 1
|
|
|
|
|
+
|
|
|
|
|
+ # 检查是否被停止
|
|
|
|
|
+ if self.auto_detect_stop:
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ # 页面间延时
|
|
|
|
|
+ time.sleep(0.5)
|
|
|
|
|
+
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ self.root.after(0, lambda: self.show_error(f"自动检测出错: {e}"))
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ # 完成或停止
|
|
|
|
|
+ self.root.after(0, self.finish_auto_detect, total_checked, total_collected)
|
|
|
|
|
+
|
|
|
|
|
+ def display_auto_collected(self, product, cycle_count):
|
|
|
|
|
+ """显示自动收藏的商品(高亮标记)"""
|
|
|
|
|
+ info = self.parse_product_info(product)
|
|
|
|
|
+ item_id = self.result_tree.insert("", tk.END, values=(
|
|
|
|
|
+ info['name'],
|
|
|
|
|
+ f"¥{info['price']}",
|
|
|
|
|
+ info['battery_efficiency'],
|
|
|
|
|
+ cycle_count,
|
|
|
|
|
+ info['fineness'],
|
|
|
|
|
+ info['memory'],
|
|
|
|
|
+ info['color'],
|
|
|
|
|
+ info['network']
|
|
|
|
|
+ ))
|
|
|
|
|
+
|
|
|
|
|
+ # 标记为已收藏(绿色背景)
|
|
|
|
|
+ self.result_tree.tag_configure('collected', background='#90EE90')
|
|
|
|
|
+ self.result_tree.item(item_id, tags=('collected',))
|
|
|
|
|
+
|
|
|
|
|
+ # 保存到当前商品列表
|
|
|
|
|
+ self.current_products.append({
|
|
|
|
|
+ 'item_id': item_id,
|
|
|
|
|
+ 'saleGoodsNo': info['saleGoodsNo'],
|
|
|
|
|
+ 'productNo': info['productNo'],
|
|
|
|
|
+ 'info': info
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ def finish_auto_detect(self, total_checked, total_collected):
|
|
|
|
|
+ """完成自动检测"""
|
|
|
|
|
+ self.auto_detect_running = False
|
|
|
|
|
+ self.start_auto_btn.config(state="normal")
|
|
|
|
|
+ self.stop_auto_btn.config(state="disabled")
|
|
|
|
|
+
|
|
|
|
|
+ if self.auto_detect_stop:
|
|
|
|
|
+ self.auto_status_label.config(
|
|
|
|
|
+ text=f"⏹ 已停止 - 检测: {total_checked} | 收藏: {total_collected}",
|
|
|
|
|
+ foreground="orange")
|
|
|
|
|
+ else:
|
|
|
|
|
+ self.auto_status_label.config(
|
|
|
|
|
+ text=f"✅ 完成 - 检测: {total_checked} | 收藏: {total_collected}",
|
|
|
|
|
+ foreground="green")
|
|
|
|
|
+
|
|
|
|
|
+ self.auto_stats_var.set(f"检测: {total_checked} | 收藏: {total_collected}")
|
|
|
|
|
+
|
|
|
|
|
+ # 显示完成消息
|
|
|
|
|
+ if total_collected > 0:
|
|
|
|
|
+ messagebox.showinfo("自动检测完成",
|
|
|
|
|
+ f"检测完成!\n\n"
|
|
|
|
|
+ f"共检测商品: {total_checked} 个\n"
|
|
|
|
|
+ f"成功收藏: {total_collected} 个")
|
|
|
|
|
+ else:
|
|
|
|
|
+ if not self.auto_detect_stop:
|
|
|
|
|
+ messagebox.showinfo("自动检测完成",
|
|
|
|
|
+ f"检测完成!\n\n"
|
|
|
|
|
+ f"共检测商品: {total_checked} 个\n"
|
|
|
|
|
+ f"没有找到符合条件的商品")
|
|
|
|
|
|
|
|
def show_error(self, error_msg):
|
|
def show_error(self, error_msg):
|
|
|
|
|
+ """显示错误信息"""
|
|
|
self.search_btn.config(state="normal")
|
|
self.search_btn.config(state="normal")
|
|
|
self.jump_btn.config(state="normal")
|
|
self.jump_btn.config(state="normal")
|
|
|
self.status_var.set(f"查询失败: {error_msg}")
|
|
self.status_var.set(f"查询失败: {error_msg}")
|