diff --git a/app/amazon/__pycache__/approve.cpython-39.pyc b/app/amazon/__pycache__/approve.cpython-39.pyc index 42e8fe4..d75c697 100644 Binary files a/app/amazon/__pycache__/approve.cpython-39.pyc and b/app/amazon/__pycache__/approve.cpython-39.pyc differ diff --git a/app/amazon/__pycache__/asin_status.cpython-39.pyc b/app/amazon/__pycache__/asin_status.cpython-39.pyc new file mode 100644 index 0000000..a4ef2a0 Binary files /dev/null and b/app/amazon/__pycache__/asin_status.cpython-39.pyc differ diff --git a/app/amazon/__pycache__/detail_spider.cpython-39.pyc b/app/amazon/__pycache__/detail_spider.cpython-39.pyc new file mode 100644 index 0000000..9a8f5b8 Binary files /dev/null and b/app/amazon/__pycache__/detail_spider.cpython-39.pyc differ diff --git a/app/amazon/__pycache__/main.cpython-39.pyc b/app/amazon/__pycache__/main.cpython-39.pyc index 46346d6..667b4bc 100644 Binary files a/app/amazon/__pycache__/main.cpython-39.pyc and b/app/amazon/__pycache__/main.cpython-39.pyc differ diff --git a/app/amazon/__pycache__/match_action.cpython-39.pyc b/app/amazon/__pycache__/match_action.cpython-39.pyc index 33ee517..39ebc21 100644 Binary files a/app/amazon/__pycache__/match_action.cpython-39.pyc and b/app/amazon/__pycache__/match_action.cpython-39.pyc differ diff --git a/app/amazon/__pycache__/price_match.cpython-39.pyc b/app/amazon/__pycache__/price_match.cpython-39.pyc index e5afa4b..95e7dc2 100644 Binary files a/app/amazon/__pycache__/price_match.cpython-39.pyc and b/app/amazon/__pycache__/price_match.cpython-39.pyc differ diff --git a/app/amazon/approve.py b/app/amazon/approve.py index a16c8db..54d8e1e 100644 --- a/app/amazon/approve.py +++ b/app/amazon/approve.py @@ -483,8 +483,8 @@ class AmzoneApprove(AmamzonBase): load_ele = self.tab.eles("xpath://div[contains(@class,'Loader-module__loader')]",timeout=5) if len(load_ele) > 0: load_ele[0].wait.deleted(timeout=3, raise_err=False) - time.sleep(0.5) + time.sleep(0.5) # 获取当前页码 try: page_pamel = self.tab.eles('xpath://kat-pagination',timeout=5) @@ -1040,7 +1040,8 @@ class ApproveTask: for country_code in country_codes: # 检查是否收到暂停请求 if task_id in runing_task and runing_task[task_id].get("stop_requested", False): - self.log(f"检测到任务 {task_id} 的暂停请求,停止处理国家", "WARNING") + self.log(f"检测到任务 {task_id} 的暂停请求,停止处理国家", "ERROR") + driver.close_store() break # 打开店铺 @@ -1058,12 +1059,14 @@ class ApproveTask: import traceback self.log(f"处理国家 {country_code} 失败: {str(e)}", "ERROR") self.log(traceback.format_exc(), "ERROR") - if "与页面的连接已断开" in e: + if "与页面的连接已断开" in str(e): iskill = True # 更新已处理国家数 if task_id in runing_task: runing_task[task_id]["processed_countries"] += 1 + + self.log(f"{task_id}任务处理完成") # 最后回传,标记完成 try: self.post_result(task_id, shop_name, country_code, "", "", is_done=True) diff --git a/app/amazon/asin_status.py b/app/amazon/asin_status.py index e69de29..9160f21 100644 --- a/app/amazon/asin_status.py +++ b/app/amazon/asin_status.py @@ -0,0 +1,714 @@ +import json +import sys +import os +import io +# sys.stdout.reconfigure(encoding='utf-8') + +import time +import re +import traceback +from datetime import datetime +from DrissionPage import Chromium, ChromiumOptions +import requests + +from amazon.del_brand import AmamzonBase, kill_process +from amazon.tool import show_notification, get_shop_info, remove_special_characters, split_currency_values + +from config import runing_task, runing_shop, base_dir, DELETE_BRAND_API_BASE + + +class AmzonePStatus(AmamzonBase): + mark_name = "状态查询" + + def SwitchPage(self): + """ + 切换至 管理所有库存页面 + 1、等待 //navigation-favorites-bar[@class="hydrated"] 出现 + """ + navigation = self.tab.ele('xpath://navigation-favorites-bar[@class="hydrated"]') + navigation.wait.displayed(raise_err=False) + page_btn = navigation.sr('xpath://internal-fav-bar-links[@data-internal="navigation"]').sr( + 'xpath://a[@data-page-id="ezdpc-gui-inventory-mons"]') + page_btn.wait.displayed(raise_err=False) + page_btn.click(timeout=5) + + self.tab.wait.doc_loaded() + # 等待搜索框出现 + search_region = self.tab.ele('xpath://div[@id="searchBoxContainer"]//kat-input-group') + search_region.wait.displayed(raise_err=False, timeout=60) + + def search_asin(self, asin): + search_region = self.tab.ele('xpath://div[@id="searchBoxContainer"]//kat-input-group') + search_region.wait.displayed(raise_err=False) + time.sleep(0.6) + search_input = self.tab.ele("xpath://kat-input[contains(@class,'SearchBox-module__searchInput')]").sr( + 'xpath://span[@class="container"]//input[@part="input"]') + search_input.input(asin, clear=True) + sku_ls = [] + for _ in range(3): + search_btn = self.tab.ele("xpath://kat-icon[@name='search']") + search_btn.click() + + load_ele = self.tab.ele("xpath://div[contains(@class,'Loader-module__loader')]") + # load_ele.wait.hidden(timeout=3, raise_err=False) + load_ele.wait.deleted(timeout=3, raise_err=False) + time.sleep(0.5) + + sku_ls = self.tab.eles("xpath://div[@data-sku]", timeout=3) + if len(sku_ls) > 0: + break + return sku_ls + + def search_asin_action(self, asin: str): + load_ele = self.tab.eles("xpath://div[contains(@class,'Loader-module__loader')]", timeout=5) + if len(load_ele) > 0: + load_ele[0].wait.deleted(timeout=3, raise_err=False) + time.sleep(0.5) + + sku_ls = self.search_asin(asin=asin) + print(f"【{self.mark_name}】{asin} 搜索到 {len(sku_ls)} 个SKU") + + def clear_tab(self): + all_tab = self.browser.get_tabs() + close_tab = [] + for tab in all_tab: + tab_id = tab if isinstance(tab, str) else tab.tab_id + if self.tab.tab_id == tab_id: + continue + close_tab.append(tab) + print("需要关闭的标签页", close_tab) + print("当前操作的tab_id", self.tab.tab_id) + self.browser.close_tabs(close_tab) + + def run_page_action(self, appoint_asin: str = None): + """ + + miniprice_info : + { + "B0DSJGJBWV" : "19.81" # asin : 最低价 + } + """ + print(f"【{self.mark_name}】,开始执行") + num = 0 + retry_num = 0 + already_asin = set() + get_page_faild = 0 + + while retry_num < 3: # 最多重试3次 + try: + print(self.mark_name, "指定asin操作", appoint_asin) + self.search_asin_action(asin=appoint_asin) + + load_ele = self.tab.eles("xpath://div[contains(@class,'Loader-module__loader')]", timeout=5) + if len(load_ele) > 0: + load_ele[0].wait.deleted(timeout=3, raise_err=False) + time.sleep(0.5) + + # 获取当前页码 + try: + page_pamel = self.tab.eles('xpath://kat-pagination', timeout=5) + if len(page_pamel) > 0: + current_page = page_pamel[0].sr('xpath:.//ul[@class="pages"]//li[@aria-current="true"]').text + + # 总页数 + total_page = page_pamel[0].sr.eles( + 'xpath:.//ul[@class="pages"]//span[@class="page__inner"][last()]') + if len(total_page) > 0: + total_page = total_page[-1].text + else: + total_page = 0 + print(f"【{self.mark_name}】当前页码: {current_page} / 总页数: {total_page}") + get_page_faild = 0 + except Exception as e: + print("【{self.mark_name}】", "获取页码失败", e) + get_page_faild += 1 + if get_page_faild > 2: + show_notification(f"【{self.mark_name}】获取页码失败超3次停止任务!") + break + + sku_ls = self.tab.eles("xpath://div[@data-sku]", timeout=10) + print(f"【{self.mark_name}】获取到 {len(sku_ls)}") + # for sku_ele in sku_ls[0:2]: + if len(sku_ls) == 0: + yield (appoint_asin,"查询不到") + break + + for sku_ele in sku_ls: + asin = sku_ele.ele( + 'xpath:.//div[contains(@class,"JanusSplitBox-module__container")]//div[contains(@class,"JanusSplitBox-module__panel--") and contains(string(.),"ASIN")]/..//div[last()]', + timeout=3).text + print(f"【{self.mark_name}】ASIN {asin} 找到....") + if asin in already_asin: + print(f"【{self.mark_name}】{asin} 已经处理过了,跳过") + continue + + # 状态 + status_ele = sku_ele.eles('xpath:.//div[contains(@class,"Status-module__container")]//kat-label') + if len(status_ele) > 0: + statu = status_ele[0].attr("emphasis") + else: + statu = "未获取到状态" + + already_asin.add(asin) + yield (asin,statu) + print(f"【{self.mark_name}】",(asin,statu)) + + # 判断是否存在需要翻页的情况 + page_pamel = self.tab.eles('xpath://kat-pagination', timeout=5) + if len(page_pamel) == 0: + break + next_page_btn = page_pamel[0].sr('xpath:.//span[@part="pagination-nav-right"]') + class_str = next_page_btn.attr('class') + if "end" in class_str: + break + next_page_btn.click() + num += 1 + print(f"【{self.mark_name}】【程序计算】正在翻页,已翻 {num} 页...") + already_asin = set() + + except Exception as e: + print(f"【{self.mark_name}】处理跟价操作异常", e) + traceback.print_exc() + retry_num += 1 + self.tab.refresh() + self.tab.wait.doc_loaded(raise_err=False, timeout=120) + + +class StatusTask: + country_info = { + "DE": "德国", + "FR": "法国", + "ES": "西班牙", + "IT": "意大利", + "UK": "英国" + } + + def __init__(self, user_info: dict = None): + """初始化审批任务处理器 + + Args: + user_info: 用户信息字典,包含 company, username, password + """ + self.user_info = user_info or {} + self.running = True + + def log(self, message: str, level: str = "INFO"): + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + if level == "ERROR": + show_notification(message, "error") + print(f"[{timestamp}] [PriceTask] [{level}] {message}") + + def process_task(self, task_data: dict): + """处理审批任务主入口 + + Args: + task_data: 任务数据 + """ + try: + data = task_data.get("data", {}) + task_id = data.get("taskId") + items = data.get("items", [])[0] + shop_name = items.get("shop_name") + queryAsins = items.get("queryAsins", []) + + user_id = data.get("user_id") + stage_index = data.get("stage_index") + final_stage = bool(data.get("final_stage", True)) + + # 用于测试 + limit = data.get("limit", None) + + if not task_id: + self.log("任务ID为空,跳过", "WARNING") + return + + # if not items: + # self.log("店铺列表为空,跳过", "WARNING") + # return + + if not queryAsins: + self.log("queryAsins 列表为空,跳过", "WARNING") + return + + self.log(f"开始处理审批任务 {task_id},共 1 个店铺,{len(queryAsins)} 个国家") + + from config import runing_task + runing_task[task_id] = { + "status": "running", + "start_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + "total_shops": 1, + "processed_shops": 0, + "total_countries": len(queryAsins), + "processed_countries": 0, + "total_asins": 0, + "processed_asins": 0, + "success_count": 0, + "failed_count": 0, + "stop_requested": False + } + + # 检查是否收到暂停请求 + if task_id in runing_task and runing_task[task_id].get("stop_requested", False): + self.log(f"检测到任务 {task_id} 的暂停请求,停止处理", "WARNING") + runing_task[task_id]["status"] = "stopped" + return + + self.log(f"开始处理店铺: {shop_name}") + show_notification(f"开始处理店铺: {shop_name}", "info") + + try: + self.process_shop(items, queryAsins, task_id, user_id, stage_index, + final_stage, limit=limit) + + # self.process_shop(shop_item, country_codes, task_id,risk_listing_filter) + # 更新已处理店铺数 + if task_id in runing_task: + runing_task[task_id]["processed_shops"] += 1 + except Exception as e: + import traceback + self.log(f"处理店铺 {shop_name} 失败: {str(e)}", "ERROR") + self.log(traceback.format_exc(), "ERROR") + + # 更新任务状态 + if task_id in runing_task: + if runing_task[task_id].get("stop_requested", False): + runing_task[task_id]["status"] = "stopped" + self.log(f"任务 {task_id} 已被暂停!") + else: + runing_task[task_id]["status"] = "completed" + self.log(f"任务 {task_id} 处理完成!") + + except Exception as e: + import traceback + self.log(f"任务处理失败: {traceback.format_exc()}", "ERROR") + if task_id: + from config import runing_task + if task_id in runing_task: + runing_task[task_id]["status"] = "failed" + runing_task[task_id]["error"] = str(e) + + def open_shop(self, max_retries, company_name, shop_name, iskill=False): + error_info = "" + driver = None + for retry in range(max_retries): + try: + self.log(f"尝试打开店铺 {shop_name} (第 {retry + 1}/{max_retries} 次)") + + if iskill: + self.log("重试前先杀掉浏览器进程...") + kill_process("v6") + kill_process("v5") + time.sleep(2) + + # 组装用户信息并创建驱动 + user_info = { + **self.user_info, + "company": company_name + } + driver = AmzonePStatus(user_info) + browser = driver.open_shop(shop_name) + + if browser and browser != "店铺不存在": + self.log(f"成功打开店铺 {shop_name}") + else: + self.log(f"打开店铺失败: {browser}", "WARNING") + driver = None + continue + + # 判断是否需要登录 + need_login = driver.need_login() + print("【是否需要登录】:", need_login) + if need_login: + self.log(f"店铺 {shop_name} 需要登录,正在登录...") + # 获取店铺凭证 + response = get_shop_info(shop_name) + print("【获取店铺凭证返回】:", response.text) + shop_data = response.json() + if not shop_data: + mes = f"获取店铺凭证失败,响应数据: {shop_data.get('message', '未知错误')}" + self.log(mes, "ERROR") + show_notification(mes, "ERROR") + continue + + password = shop_data["data"]["password"] + + login_success = driver.login(password) + if login_success: + self.log(f"店铺 {shop_name} 登录成功,正在重新打开店铺...") + browser = driver.open_shop(shop_name) + if browser and browser != "店铺不存在": + self.log(f"成功打开店铺 {shop_name} 登录后") + break + else: + self.log(f"登录后打开店铺失败: {browser}", "WARNING") + driver = None + else: + self.log(f"店铺 {shop_name} 登录失败", "WARNING") + driver = None + else: + break + + except Exception as e: + import traceback + self.log(f"打开店铺异常: {traceback.format_exc()}", "INFO") + driver = None + error_info = str(e) + time.sleep(10) + + # 如果还有重试机会,等待后继续 + if retry < max_retries - 1: + time.sleep(3) + + # 检查是否成功打开 + if not driver or not browser or browser == "店铺不存在": + error_msg = f"店铺 {shop_name} 打开失败,已重试 {max_retries} 次,跳过该店铺,{error_info}" + self.log(error_msg, "ERROR") + # 从执行列表中移除 + if shop_name in runing_shop: + del runing_shop[shop_name] + return driver + return driver + + def process_shop(self, shop_item: dict, country_codes: list, task_id: int, + user_id=None, stage_index=None, final_stage: bool = True, limit: str = None): + """处理单个店铺 + + Args: + shop_item: 店铺信息 + country_codes: 国家代码列表 + task_id: 任务ID + risk_listing_filter: 风险商品筛选条件 + """ + shop_name = shop_item.get("shopName", "未知店铺") + company_name = shop_item.get("companyName", "") + + + if not company_name: + self.log(f"店铺 {shop_name} 的公司名称为空,跳过", "WARNING") + return + + if task_id in runing_task: + runing_task[task_id]["current_shop"] = shop_name + + # 将店铺添加到正在执行中的店铺列表 + start_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + runing_shop[shop_name] = start_time + self.log(f"店铺 {shop_name} 已添加到执行列表,账号: {company_name},开始时间: {start_time}") + + # 店铺打开重试最多3次 + max_retries = 3 + iskill = False + # 处理每个国家 + for value in country_codes: + country_code = value.get("country") + all_asin = value.get("asins") + # 打开店铺 + driver = self.open_shop(max_retries=max_retries, company_name=company_name, + shop_name=shop_name, iskill=iskill) + if driver is None: + self.log(f"任务 {task_id} 启动店铺失败,结束任务", "ERROR") + for country_code in country_codes: + self.post_result(task_id, shop_name, country_code, "", "", is_done=True) + return + + # 检查是否收到暂停请求 + if task_id in runing_task and runing_task[task_id].get("stop_requested", False): + self.log(f"检测到任务 {task_id} 的暂停请求,停止处理国家", "ERROR") + driver.close_store() + break + try: + self.process_country(driver, country_code, task_id, shop_name,all_asin=all_asin ) + except Exception as e: + import traceback + self.log(f"处理国家 {country_code} 失败: {str(e)}", "ERROR") + self.log(traceback.format_exc(), "ERROR") + if "与页面的连接已断开" in str(e): + iskill = True + + # 更新已处理国家数 + if task_id in runing_task: + runing_task[task_id]["processed_countries"] += 1 + + # 关闭店铺 + driver.close_store() + + self.log(f"{task_id}任务处理完成") + + # 最后回传,标记完成 + try: + # self.post_result(task_id, shop_name, country_code, "", "", is_done=True) + if final_stage: + self.post_result(task_id, shop_name, country_code, "", "", is_done=True) + else: + self.post_stage_finished(task_id, user_id, stage_index) + except Exception as e: + self.log(f"回传结果失败: {str(e)}", "ERROR") + + # 从正在执行中的店铺列表中移除 + if shop_name in runing_shop: + del runing_shop[shop_name] + self.log(f"店铺 {shop_name} 已从执行列表中移除") + + def process_country(self, driver: AmzonePStatus, country_code: str, task_id: int, shop_name: str, + all_asin:list, + limit: str = None): + """处理单个国家的审批任务 + + Args: + driver: AmzoneApprove驱动实例 + country_code: 国家代码(如 UK, DE, FR 等) + task_id: 任务ID + shop_name: 店铺名称 + risk_listing_filter: 风险商品筛选条件 + """ + + # 转换国家代码为中文名称 + country_name = self.country_info.get(country_code, country_code) + info_mes = f"开始处理国家: {country_name} ({country_code})" + self.log(info_mes) + show_notification(info_mes, "info") + + # 更新当前处理的国家 + if task_id in runing_task: + runing_task[task_id]["current_country"] = country_name + + # 切换国家,最多重试3次 + max_retries = 3 + switch_success = False + + for retry in range(max_retries): + try: + self.log(f"尝试切换到国家 {country_name} (第 {retry + 1}/{max_retries} 次)") + if retry > 1: + # 刷新不行就重新打开店铺 + self.log("重试前重新打开店铺...") + try: + driver.close_store() + time.sleep(3) + driver.open_shop(shop_name) + except Exception as e: + self.log(f"关闭重新打开店铺: {str(e)}", "WARNING") + # 如果不是第一次尝试,先刷新页面 + if retry > 0: + self.log("重试前刷新页面...") + try: + driver.tab.refresh() + time.sleep(3) + except Exception as e: + self.log(f"刷新页面失败: {str(e)}", "WARNING") + + switch_success = driver.SwitchingCountries(country_name) + if switch_success: + self.log(f"成功切换到国家 {country_name}") + break + else: + self.log(f"切换到国家 {country_name} 失败", "WARNING") + + except Exception as e: + import traceback + self.log(f"切换国家 {country_name} 异常: {str(e)}", "ERROR") + self.log(traceback.format_exc(), "ERROR") + + # 如果还有重试机会,等待后继续 + if retry < max_retries - 1: + time.sleep(2) + + # 如果切换失败,直接返回 + if not switch_success: + error_message = f"切换到国家 {country_name} 失败,已重试 {max_retries} 次,跳过该国家" + self.log(error_message, "ERROR") + if task_id in runing_task: + runing_task[task_id]["processed_countries"] += 1 + return + + # 切换到库存管理页面 + for retry in range(max_retries): + try: + driver.SwitchPage() + self.log(f"已切换到库存管理页面") + except Exception as e: + import traceback + self.log(f"切换页面失败: {str(e)}", "ERROR") + self.log(traceback.format_exc(), "ERROR") + + if retry >= max_retries - 1: + if task_id in runing_task: + runing_task[task_id]["processed_countries"] += 1 + self.log(f"切换页面失败重试退出", "ERROR") + return + + + + # 处理所有需要审批的商品(通过yield获取结果) + + # 指定 asin + for ap_asin in all_asin: + print(f"【{driver.mark_name}】开始处理 ->",ap_asin) + for asin, status in driver.run_page_action( + appoint_asin=ap_asin + ): + # 检查是否收到暂停请求 + if task_id in runing_task and runing_task[task_id].get("stop_requested", False): + self.log(f"检测到任务 {task_id} 的暂停请求,停止处理ASIN", "WARNING") + break + + self.log(f"ASIN {asin} 处理结果: {status}") + + # 更新任务状态 + if task_id in runing_task: + runing_task[task_id]["current_asin"] = asin + runing_task[task_id]["processed_asins"] += 1 + + runing_task[task_id]["failed_count"] += 1 + + # 回传结果到API + try: + self.post_result(task_id, shop_name, country_code, asin, status) + except Exception as e: + self.log(f"回传结果失败: {str(e)}", "ERROR") + + self.log(f"国家 {country_name} 处理完成") + + def post_stage_finished(self, task_id: int, user_id, stage_index): + # import requests + # from config import DELETE_BRAND_API_BASE + + if user_id in (None, "", 0): + raise ValueError("user_id is required for stage completion callback") + if stage_index is None: + raise ValueError("stage_index is required for stage completion callback") + + url = f"{DELETE_BRAND_API_BASE}/api/shop-match/tasks/{task_id}/stage-finished" + payload = {"stage_index": stage_index} + params = {"user_id": user_id} + + max_retries = 3 + for retry in range(max_retries): + try: + self.log(f"Attempting stage completion callback ({retry + 1}/{max_retries})") + response = requests.post( + url, + params=params, + json=payload, + headers={"Content-Type": "application/json"}, + timeout=30, + verify=False, + ) + self.log(f"Stage completion callback response: {response.text}") + data = response.json() if response.text else {} + if response.status_code == 200 and isinstance(data, dict) and data.get("success"): + self.log(f"Stage completion callback succeeded: task={task_id}, stage={stage_index}") + return + self.log(f"Stage completion callback failed, status={response.status_code}", "WARNING") + except Exception as e: + self.log(f"Stage completion callback exception: {str(e)}", "ERROR") + if retry < max_retries - 1: + time.sleep(2) + + raise RuntimeError(f"Stage completion callback failed after retries: task={task_id}, stage={stage_index}") + + def post_result(self, task_id: int, shop_name: str, country_code: str, asin: str, status: dict, + is_done: bool = False): + """回传处理结果到API + + Args: + task_id: 任务ID + shop_name: 店铺名称 + country_code: 国家代码 + asin: ASIN + status: 处理状态 + """ + + url = f"{DELETE_BRAND_API_BASE}/api/query-asin/tasks/{task_id}/result" + + payload = { + "shops": [ + { + "shopName": shop_name, + "countryResults": [ + { + "country": country_code, + "items": [ + { + "asin": asin, + "status": status + } + ] + } + ], + "shopDone": is_done, + "submissionId": f"{int(time.time())}" + } + ] + } + if is_done: + payload["shops"][0]["success"] = is_done + + max_retries = 3 + for retry in range(max_retries): + try: + print("================【跟价】=====================") + self.log(f"尝试回传结果 (第 {retry + 1}/{max_retries} 次)") + self.log(f"回传URL: {url}") + self.log(f"回传数据: {payload}") + response = requests.post( + url, + json=payload, + headers={"Content-Type": "application/json"}, + timeout=30, + verify=False + ) + self.log(f"回传结果: {response.text}") + data = response.json() if response.text else {} + if response.status_code == 200 and isinstance(data, dict) and data.get("success"): + self.log(f"结果回传成功: {asin} - {status}") + return + else: + self.log(f"结果回传失败,状态码: {response.status_code}", "WARNING") + print("=====================================") + + except Exception as e: + self.log(f"调用API异常: {str(e)}", "ERROR") + print("=====================================") + + # 如果还有重试机会,等待后继续 + if retry < max_retries - 1: + time.sleep(2) + + self.log(f"已达到最大重试次数,结果回传最终失败", "ERROR") + raise RuntimeError("已达到最大重试次数,结果回传最终失败") + + +if __name__ == '__main__': + # 使用示例 + user_info = { + "company": "rongchuang123", + "username": "自动化_Robot", + "password": "#20zsg25" + } + shop_name = "魏振峰" + country = "德国" + kill_process('v6') + driver = AmzonePStatus(user_info) + browser = driver.open_shop(shop_name) + sw_suc = driver.SwitchingCountries(country) + driver.SwitchPage() + risk_listing_filter = "Active" + _shopMallName = "WEIZHENFENG168" + ap_asin = "B0F1N18XFW" + skip_asin = [] + for _ in range(3): + try: + sku_ls = driver.search(filter_type=risk_listing_filter) + break + except Exception as e: + print(e) + driver.tab.refresh() + if len(sku_ls) > 0: + print("有数据,开始操作") + for asin, status in driver.run_page_action( + current_shop_name=_shopMallName, + appoint_asin=ap_asin, skip_asin=skip_asin + ): + print(f"ASIN {asin} 的处理结果: {status}") + print("已完成操作") diff --git a/app/amazon/detail_spider.py b/app/amazon/detail_spider.py new file mode 100644 index 0000000..0558bbb --- /dev/null +++ b/app/amazon/detail_spider.py @@ -0,0 +1,6907 @@ +import json +import sys +import os +import io +# sys.stdout.reconfigure(encoding='utf-8') + +import time +import re +import traceback +from datetime import datetime +from DrissionPage import Chromium, ChromiumOptions +import requests + +from amazon.del_brand import AmamzonBase, kill_process +from amazon.tool import show_notification,get_shop_info,remove_special_characters,split_currency_values + +from config import runing_task, runing_shop,base_dir,DELETE_BRAND_API_BASE + + +class ChromeAmzone: + mark_name = "亚马逊详情采集" + country_info = { + "英国": { + "url": "https://www.amazon.co.uk/dp/B0CJ8SNXXV", + "zip_code": "SW1A 1AA", + "mark": "SW1A 1" + }, + "德国": { + "url": "https://www.amazon.de/dp/B0CC8CW9G2?th=1", + "zip_code": "10115" + }, + "法国": { + "url": "https://www.amazon.fr/dp/B0FRG1MJ8H?th=1", + "zip_code": "75001" + }, + "西班牙": { + "url": "https://www.amazon.es/dp/B08ZXVNYNN", + "zip_code": "28001" + }, + "意大利": { + "url": "https://www.amazon.it/dp/B0D1P17T2Q", + "zip_code": "20121" + } + } + + def __init__(self): + """ + 杀死当前谷歌浏览器进程,并使用 drissionpage 启动谷歌浏览器,使用系统安装的浏览器默认用户文件夹 + """ + # 杀死现有的Chrome进程 + print("正在关闭现有的chromium浏览器进程...") + os.system('taskkill /f /t /im chrome.exe') + time.sleep(2) + + print("正在启动chromium浏览器...") + # 配置浏览器选项 + co = ChromiumOptions() + user_data_path = os.path.join(base_dir, "user_data", "chrome_data") + if not os.path.exists(user_data_path): + os.makedirs(user_data_path, exist_ok=True) + co.set_user_data_path(user_data_path) + co.set_local_port(port=19897) + self.browser = Chromium(co) + self.tab = self.browser.latest_tab + print("Chrome浏览器启动成功") + + def close_init_popup(self): + """ + 关闭所有的初始化弹窗 + """ + self.tab.wait.doc_loaded(timeout=60, raise_err=True) + footbar = self.tab.eles('xpath://footer[@class="el-dialog__footer"]', timeout=5) + if len(footbar) > 0: + do_not_remind = footbar[0].eles('xpath:.//input[@class="el-checkbox__original"]') + if len(do_not_remind) > 0: + do_not_remind[0].check() + resume_immediately = footbar[0].eles('xpath:.//button') + if len(resume_immediately) > 0: + resume_immediately[0].click() + + self.tab.wait.doc_loaded(timeout=60, raise_err=True) + accept_btn = self.tab.eles('xpath://input[@id="sp-cc-accept"]', timeout=5) + if len(accept_btn) > 0: + accept_btn[0].click() + + def run(self, country, asin): + """ + 运行亚马逊详情采集任务 + + Args: + country: 国家名称(如:英国、德国、法国、西班牙、意大利) + asin: 亚马逊商品ASIN码 + + Returns: + dict: 包含采集到的数据 + """ + try: + # 验证国家是否支持 + if country not in self.country_info: + error_msg = f"不支持的国家: {country},支持的国家有: {list(self.country_info.keys())}" + print(error_msg) + show_notification(error_msg, "error") + return None + + # 获取国家配置 + country_config = self.country_info[country] + zip_code = country_config["zip_code"] + mark = country_config.get("mark") + + # 1. 根据国家和ASIN拼接链接 + base_url = country_config["url"] + # 提取域名部分 + domain = base_url.split("/dp/")[0] + # 拼接新的URL + product_url = f"{domain}/dp/{asin}" + print(f"正在访问: {product_url}") + + # 打开链接 + self.tab.get(product_url) + time.sleep(3) # 等待页面初步加载 + self.tab.wait.doc_loaded(timeout=30, raise_err=False) + + self.close_init_popup() + # 2. 切换国家/设置邮编 + print(f"正在检查并设置邮编: {zip_code},标识: {mark}") + self._set_zip_code(zip_code, mark) + + # self.tab.wait.doc_loaded(timeout=5, raise_err=False) + + # 3. 抓取数据 + print("正在抓取商品数据...") + data = self._scrape_data() + + # 添加基本信息 + data['country'] = country + data['asin'] = asin + data['url'] = product_url + data['timestamp'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + + print(f"数据抓取完成: {json.dumps(data)}") + return data + + except Exception as e: + error_msg = f"运行出错: {traceback.format_exc()}" + print(error_msg) + show_notification(f"采集失败: {str(e)}", "error") + return None + + def _set_zip_code(self, zip_code, mark=None): + """ + 设置邮编 + + Args: + zip_code: 目标邮编 + """ + try: + # 检查当前邮编 + zip_display = self.tab.ele('xpath://div[@id="glow-ingress-block"]', timeout=10) + + if zip_display: + current_text = zip_display.text + # print(f"当前地址信息: {current_text}") + # 先检查标识 + if mark is not None and mark in current_text: + print(f"邮编检测到标识: {mark},无需修改") + return True + # 检查是否已经包含目标邮编 + if zip_code in current_text: + print(f"邮编已经设置为: {zip_code},无需修改") + return True + + # 需要设置邮编 + print(f"正在设置邮编为: {zip_code}") + + # 点击地址选择按钮 + location_link = self.tab.ele('xpath://a[@id="nav-global-location-popover-link"]', timeout=10) + if not location_link: + print("找不到地址设置按钮") + return False + + location_link.click() + time.sleep(1) + + # 等待邮编输入框出现 + zip_input = self.tab.ele('xpath://input[@id="GLUXZipUpdateInput"]', timeout=10) + if not zip_input: + print("找不到邮编输入框") + return False + + # 输入邮编 + zip_input.input(zip_code, clear=True) + time.sleep(0.5) + + # 点击提交按钮 + submit_btn = self.tab.ele('xpath://input[@aria-labelledby="GLUXZipUpdate-announce"]', timeout=10) + if not submit_btn: + print("找不到提交按钮") + return False + + submit_btn.click() + + continue_btn = self.tab.eles('xpath://div[@class="a-popover-footer"]//input[@id="GLUXConfirmClose"]', + timeout=10) + if len(continue_btn) > 0: + continue_btn[0].click() + + # 等待提交按钮消失(表示请求已发送) + print("等待邮编更新...") + time.sleep(2) + + # 等待页面加载完成 + self.tab.wait.doc_loaded(timeout=30, raise_err=False) + time.sleep(2) + + # 验证邮编是否设置成功 + zip_display_after = self.tab.ele('xpath://div[@id="glow-ingress-block"]', timeout=10) + if zip_display_after: + updated_text = zip_display_after.text + # print(f"更新后的地址信息: {updated_text}") + + if zip_code in updated_text: + print(f"邮编设置成功: {zip_code}") + return True + else: + # print(f"邮编设置可能失败,当前显示: {updated_text}") + return False + + return True + + except Exception as e: + print(f"设置邮编时出错: {traceback.format_exc()}") + return False + + def _scrape_data(self): + """ + 抓取商品数据 + + Returns: + dict: 抓取到的数据 + """ + data = { + 'image_url': "", + 'title': "" + } + + try: + # 等待页面加载 + # time.sleep(3) + title_ele = self.tab.ele('xpath://h1[@id="title"]',timeout=30) + title = title_ele.text + data["title"] = title + imge_ele = self.tab.ele('xpath://div[@id="imgTagWrapperId"]//img',timeout=20) + image_url = imge_ele.attr("src") + data["image_url"] = image_url + return data + + except Exception as e: + print(f"抓取数据时出错: {traceback.format_exc()}") + return data + + def close(self): + """关闭浏览器""" + try: + if self.browser: + self.browser.quit() + print("浏览器已关闭") + except Exception as e: + print(f"关闭浏览器时出错: {str(e)}") + + +class SpiderTask: + mark_name = "亚马逊采集" + + def __init__(self, user_info: dict = None): + """初始化审批任务处理器 + + Args: + user_info: 用户信息字典,包含 company, username, password + """ + self.user_info = user_info or {} + self.running = True + + def log(self, message: str, level: str = "INFO"): + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + if level == "ERROR": + show_notification(message, "error") + print(f"[{timestamp}] [PriceTask] [{level}] {message}") + + def process_task(self, task_data: dict): + """处理审批任务主入口 + + Args: + task_data: 任务数据 + """ + try: + data = task_data.get("data", {}) + task_id = data.get("taskId") + items = data.get("rows", []) + + # 用于测试 + limit = data.get("limit", None) + + if not task_id: + self.log("任务ID为空,跳过", "WARNING") + return + + + self.log(f"开始处理爬取任务 {task_id},{len(items)} 个任务") + + from config import runing_task + runing_task[task_id] = { + "status": "running", + "start_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + "total_shops": 1, + "processed_shops": 0, + "total_countries": len(items) , + "processed_countries": 0, + "total_asins": 0, + "processed_asins": 0, + "success_count": 0, + "failed_count": 0, + "stop_requested": False + } + + # 检查是否收到暂停请求 + if task_id in runing_task and runing_task[task_id].get("stop_requested", False): + self.log(f"检测到任务 {task_id} 的暂停请求,停止处理", "WARNING") + runing_task[task_id]["status"] = "stopped" + return + max_retry = 3 + show_notification(f"开始爬取数据", "info") + chrome = ChromeAmzone() + try: + for index,i in enumerate(items): + asin = i.get("asin") + country = i.get("country") + return_data = None + for _ in range(max_retry): + try: + return_data = chrome.run(country, asin) + self.log(f"抓取结果->{return_data}") + break + except Exception as e: + if "与页面的连接已断开" in str(e): + chrome = ChromeAmzone() + # 提交结果 + # 'image_url': "", + # 'title': "" + + item_data = { + "id": i.get("id"), + "asin": asin, + "country": country, + "url": return_data.get("image_url"), + "title": return_data.get("title"), + } + # task_id: int, chunkIndex:int,chunkTotal: int, country_code: str, asin: str, status: dict,error:str="", + # item_data:dict={}, + is_done = index == len(items)-1 + self.post_result(task_id=task_id,chunkIndex=index+1,chunkTotal=len(items), + asin=asin,item_data=item_data,is_done=is_done) + + try: + chrome.close() + except Exception as e: + print("退出浏览器出错",e) + # 更新已处理店铺数 + if task_id in runing_task: + runing_task[task_id]["processed_shops"] += 1 + except Exception as e: + import traceback + self.log(f"处理店铺 {task_id} 失败: {str(e)}", "ERROR") + self.log(traceback.format_exc(), "ERROR") + + # 更新任务状态 + if task_id in runing_task: + if runing_task[task_id].get("stop_requested", False): + runing_task[task_id]["status"] = "stopped" + self.log(f"任务 {task_id} 已被暂停!") + else: + runing_task[task_id]["status"] = "completed" + self.log(f"任务 {task_id} 处理完成!") + + except Exception as e: + import traceback + self.log(f"任务处理失败: {traceback.format_exc()}", "ERROR") + if task_id: + from config import runing_task + if task_id in runing_task: + runing_task[task_id]["status"] = "failed" + runing_task[task_id]["error"] = str(e) + + def post_result(self, task_id: int, chunkIndex:int,chunkTotal: int, asin: str, error:str="", + item_data:dict={}, + is_done: bool = False): + """回传处理结果到API + """ + + url = f"{DELETE_BRAND_API_BASE}/api/appearance-patent/tasks/{task_id}/result" + + payload ={ + "submissionId": f"{int(time.time())}", + "chunkIndex": chunkIndex, + "chunkTotal": chunkTotal, + "error": error, + "items": [ + item_data + ], + "done": is_done + } + + max_retries = 3 + for retry in range(max_retries): + try: + print("================【详情采集】=====================") + self.log(f"尝试回传结果 (第 {retry + 1}/{max_retries} 次)") + self.log(f"回传URL: {url}") + self.log(f"回传数据: {payload}") + response = requests.post( + url, + json=payload, + headers={"Content-Type": "application/json"}, + timeout=30, + verify=False + ) + self.log(f"回传结果: {response.text}") + data = response.json() if response.text else {} + if response.status_code == 200 and isinstance(data, dict) and data.get("success"): + self.log(f"结果回传成功: {asin} - {item_data}") + return + else: + self.log(f"结果回传失败,状态码: {response.status_code}", "WARNING") + print("=====================================") + + except Exception as e: + self.log(f"调用API异常: {str(e)}", "ERROR") + print("=====================================") + + # 如果还有重试机会,等待后继续 + if retry < max_retries - 1: + time.sleep(2) + + self.log(f"已达到最大重试次数,结果回传最终失败", "ERROR") + raise RuntimeError("已达到最大重试次数,结果回传最终失败") + +if __name__ == '__main__': + spide = SpiderTask() + task_data = { + "success": True, + "message": "操作成功", + "data": { + "taskId": 4188, + "sourceFilename": "17.xlsx", + "totalRows": 1601, + "acceptedRows": 716, + "droppedRows": 885, + "aiPrompt": "请帮我排查以下亚马逊商品在英国及欧洲地区是否存在知识产权侵权风险。 请直接给出明确结论(有侵权风险 或 未发现明显侵权风险),并严格按照以下三个维度提供精简的排查理由: 外观维度: 评估产品外形、图案设计是否与欧洲/英国常见外观专利雷同。 专利维度: 评估产品的核心技术或物理结构是否存在侵权可能。 标题维度: 排查标题中是否包含大牌商标、敏感词或版权保护词汇。 结论:XX", + "items": [ + { + "rowIndex": 2, + "sourceId": "1", + "displayId": "1", + "asin": "B0D792ND9V", + "country": "英国", + "url": "", + "title": "低" + }, + { + "rowIndex": 3, + "sourceId": "2_1", + "displayId": "2_1", + "asin": "B0D14L34S7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 7, + "sourceId": "3_1", + "displayId": "3_1", + "asin": "B0CWQFZMGY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 9, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B0CX87XXWJ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 10, + "sourceId": "5_1", + "displayId": "5_1", + "asin": "B0CR3PMR8L", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 11, + "sourceId": "6", + "displayId": "6", + "asin": "B0DK3L6FD4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 12, + "sourceId": "8", + "displayId": "8", + "asin": "B0D9QNV6FT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 13, + "sourceId": "10_1", + "displayId": "10_1", + "asin": "B0DBZG716J", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 14, + "sourceId": "11_1", + "displayId": "11_1", + "asin": "B0CX8K4F8Z", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 15, + "sourceId": "12_1", + "displayId": "12_1", + "asin": "B0C4KXJWW1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 28, + "sourceId": "13", + "displayId": "13", + "asin": "B0D62LNNKQ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 29, + "sourceId": "14", + "displayId": "14", + "asin": "B0DK3K3GF5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 30, + "sourceId": "15_1", + "displayId": "15_1", + "asin": "B0C1HN8GY6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 57, + "sourceId": "16_1", + "displayId": "16_1", + "asin": "B0B71WMDDF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 58, + "sourceId": "18_1", + "displayId": "18_1", + "asin": "B0DSZNF73N", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 60, + "sourceId": "19", + "displayId": "19", + "asin": "B0897Y5QDC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 61, + "sourceId": "22_1", + "displayId": "22_1", + "asin": "B0FNCLNS68", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 62, + "sourceId": "23_1", + "displayId": "23_1", + "asin": "B009U2SCMW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 67, + "sourceId": "24", + "displayId": "24", + "asin": "B0FBLY2ZRD", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 68, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B08LP7DW3M", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 69, + "sourceId": "28_1", + "displayId": "28_1", + "asin": "B0FPBZLD6R", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 80, + "sourceId": "30", + "displayId": "30", + "asin": "B09LV1TNHK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 81, + "sourceId": "1_1", + "displayId": "1_1", + "asin": "B0DSKS214Y", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 86, + "sourceId": "2_1", + "displayId": "2_1", + "asin": "B0BZBW8KL5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 88, + "sourceId": "3", + "displayId": "3", + "asin": "B0CR3LS3R7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 89, + "sourceId": "4", + "displayId": "4", + "asin": "B097TS2MNQ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 90, + "sourceId": "5", + "displayId": "5", + "asin": "B09LV4WGTR", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 91, + "sourceId": "6_1", + "displayId": "6_1", + "asin": "B0916ZQP1V", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 93, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B0C9WHZ67N", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 96, + "sourceId": "9", + "displayId": "9", + "asin": "B0F8QKVS1D", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 97, + "sourceId": "10", + "displayId": "10", + "asin": "B0D49974HV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 98, + "sourceId": "11", + "displayId": "11", + "asin": "B0F2DXMKVF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 99, + "sourceId": "12_1", + "displayId": "12_1", + "asin": "B08YX48NZ2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 100, + "sourceId": "14", + "displayId": "14", + "asin": "B0BGM3HF9C", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 101, + "sourceId": "15", + "displayId": "15", + "asin": "B0CJJM9KZV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 102, + "sourceId": "16_1", + "displayId": "16_1", + "asin": "B09HDSTGT4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 103, + "sourceId": "17", + "displayId": "17", + "asin": "B0CX9HK5NL", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 104, + "sourceId": "18", + "displayId": "18", + "asin": "B0C2BV83D3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 105, + "sourceId": "19_1", + "displayId": "19_1", + "asin": "B0D5WDK7GW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 107, + "sourceId": "20", + "displayId": "20", + "asin": "B09NR1PZYD", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 108, + "sourceId": "21", + "displayId": "21", + "asin": "B0DC45N1Y8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 109, + "sourceId": "23", + "displayId": "23", + "asin": "B01AVHJQY2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 110, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0F3VSJ9Q2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 117, + "sourceId": "27", + "displayId": "27", + "asin": "B0CLXCXW6W", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 118, + "sourceId": "28", + "displayId": "28", + "asin": "B07PSPN1XH", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 119, + "sourceId": "29_1", + "displayId": "29_1", + "asin": "B09PHQYR6Z", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 122, + "sourceId": "30", + "displayId": "30", + "asin": "B0CT2H94WV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 123, + "sourceId": "1", + "displayId": "1", + "asin": "B0FRRK9V73", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 124, + "sourceId": "3_1", + "displayId": "3_1", + "asin": "B0B3RNHXV8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 125, + "sourceId": "4", + "displayId": "4", + "asin": "B09FF115TW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 126, + "sourceId": "5", + "displayId": "5", + "asin": "B0CYGXDWBT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 127, + "sourceId": "6", + "displayId": "6", + "asin": "B0F9FT3ZPY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 128, + "sourceId": "7", + "displayId": "7", + "asin": "B0F295JTQZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 129, + "sourceId": "8", + "displayId": "8", + "asin": "B0FPJZ1N51", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 130, + "sourceId": "9_1", + "displayId": "9_1", + "asin": "B08B8SP7XT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 131, + "sourceId": "12_1", + "displayId": "12_1", + "asin": "B002P7HGEO", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 132, + "sourceId": "13_1", + "displayId": "13_1", + "asin": "B09X268FXC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 134, + "sourceId": "14_1", + "displayId": "14_1", + "asin": "B0170OT3X8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 136, + "sourceId": "15_1", + "displayId": "15_1", + "asin": "B0859793H1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 138, + "sourceId": "17", + "displayId": "17", + "asin": "B0FP8KHCPX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 139, + "sourceId": "18_1", + "displayId": "18_1", + "asin": "B09H6KR87N", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 146, + "sourceId": "19_1", + "displayId": "19_1", + "asin": "B0D9778Q65", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 147, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B0CPJCBZR8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 148, + "sourceId": "21", + "displayId": "21", + "asin": "B0CZ63NGNQ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 149, + "sourceId": "22", + "displayId": "22", + "asin": "B0CR4795W6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 150, + "sourceId": "23", + "displayId": "23", + "asin": "B0CR45ZB5Y", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 151, + "sourceId": "24_1", + "displayId": "24_1", + "asin": "B0CYB255ST", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 153, + "sourceId": "25", + "displayId": "25", + "asin": "B0BMYWFKTF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 154, + "sourceId": "26", + "displayId": "26", + "asin": "B0BMYTPRD6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 155, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B0DK1MGDZM", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 157, + "sourceId": "28", + "displayId": "28", + "asin": "B006FUXS30", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 158, + "sourceId": "30", + "displayId": "30", + "asin": "B00BLPUXCI", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 159, + "sourceId": "1", + "displayId": "1", + "asin": "B09N79DR4C", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 160, + "sourceId": "2", + "displayId": "2", + "asin": "B006O74WTI", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 161, + "sourceId": "3", + "displayId": "3", + "asin": "B006O75DIC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 162, + "sourceId": "4", + "displayId": "4", + "asin": "B09323MXYP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 163, + "sourceId": "5", + "displayId": "5", + "asin": "B00K2NTEPC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 164, + "sourceId": "6", + "displayId": "6", + "asin": "B09C19Y6B3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 165, + "sourceId": "7", + "displayId": "7", + "asin": "B00L2HK0S2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 166, + "sourceId": "8", + "displayId": "8", + "asin": "B00666DQBW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 167, + "sourceId": "9", + "displayId": "9", + "asin": "B00666FLII", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 168, + "sourceId": "10", + "displayId": "10", + "asin": "B00666GVM8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 169, + "sourceId": "11_1", + "displayId": "11_1", + "asin": "B07KWJCVVN", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 173, + "sourceId": "13_1", + "displayId": "13_1", + "asin": "B00F0KAGKO", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 179, + "sourceId": "14_1", + "displayId": "14_1", + "asin": "B0C695NBMR", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 180, + "sourceId": "15_1", + "displayId": "15_1", + "asin": "B0F2FXYCG4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 182, + "sourceId": "16", + "displayId": "16", + "asin": "B0FPGC8Z84", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 183, + "sourceId": "17_1", + "displayId": "17_1", + "asin": "B0D8HXBGGB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 184, + "sourceId": "18_1", + "displayId": "18_1", + "asin": "B0DDG8GJP9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 188, + "sourceId": "19", + "displayId": "19", + "asin": "B0FLCZVDDH", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 189, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B07WZZW6V9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 191, + "sourceId": "21", + "displayId": "21", + "asin": "B0GT3SJ6J1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 192, + "sourceId": "22", + "displayId": "22", + "asin": "B077R1GRW1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 193, + "sourceId": "23", + "displayId": "23", + "asin": "B0D2TMYX23", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 194, + "sourceId": "24_1", + "displayId": "24_1", + "asin": "B00AXTKYCM", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 195, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0D45CB5SS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 197, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B0852JR7RD", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 198, + "sourceId": "27", + "displayId": "27", + "asin": "B0GR9F93JL", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 199, + "sourceId": "28_1", + "displayId": "28_1", + "asin": "B0CCJ3NY78", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 200, + "sourceId": "29_1", + "displayId": "29_1", + "asin": "B0D1V26VBG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 201, + "sourceId": "1", + "displayId": "1", + "asin": "B0CN5VVWB2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 202, + "sourceId": "2", + "displayId": "2", + "asin": "B0DLNJTKFB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 203, + "sourceId": "3", + "displayId": "3", + "asin": "B0CSD7S964", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 204, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B0GLP8L4TT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 205, + "sourceId": "5", + "displayId": "5", + "asin": "B0FGJB6LLV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 206, + "sourceId": "6", + "displayId": "6", + "asin": "B0DZ67MYZN", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 207, + "sourceId": "7", + "displayId": "7", + "asin": "B0G3XP9VYB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 208, + "sourceId": "8", + "displayId": "8", + "asin": "B0FNWMRMSZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 209, + "sourceId": "9", + "displayId": "9", + "asin": "B0FNWP3K72", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 210, + "sourceId": "10_1", + "displayId": "10_1", + "asin": "B0DQTMRNLC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 212, + "sourceId": "11", + "displayId": "11", + "asin": "B0DZ62KT5N", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 213, + "sourceId": "13", + "displayId": "13", + "asin": "B0DZ65VCDC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 214, + "sourceId": "16", + "displayId": "16", + "asin": "B0DZ67P85P", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 215, + "sourceId": "17_1", + "displayId": "17_1", + "asin": "B0F6LRCZXW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 216, + "sourceId": "18", + "displayId": "18", + "asin": "B0DPYVJMLK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 217, + "sourceId": "19", + "displayId": "19", + "asin": "B0FDKZJTY5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 218, + "sourceId": "20", + "displayId": "20", + "asin": "B0D9VFN9QW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 219, + "sourceId": "21_1", + "displayId": "21_1", + "asin": "B0BW46XZ2G", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 222, + "sourceId": "22", + "displayId": "22", + "asin": "B0FLCBQ92M", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 223, + "sourceId": "23_1", + "displayId": "23_1", + "asin": "B0F6JW61SR", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 225, + "sourceId": "24", + "displayId": "24", + "asin": "B0CNZ27HCF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 226, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B001DKRB8A", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 232, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B00NH5DWIW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 236, + "sourceId": "28", + "displayId": "28", + "asin": "B01IOKEOGS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 237, + "sourceId": "29", + "displayId": "29", + "asin": "B08YJVVPBK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 238, + "sourceId": "30", + "displayId": "30", + "asin": "B0FG29NPDK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 239, + "sourceId": "1", + "displayId": "1", + "asin": "B0FRFHFXXZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 240, + "sourceId": "3", + "displayId": "3", + "asin": "B0FMQ5G18V", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 241, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B0DPDKD5PB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 242, + "sourceId": "6_1", + "displayId": "6_1", + "asin": "B0FS6JDGNW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 248, + "sourceId": "8", + "displayId": "8", + "asin": "B0DZBM5VRX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 249, + "sourceId": "11_1", + "displayId": "11_1", + "asin": "B0D4Q2KB8X", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 250, + "sourceId": "12_1", + "displayId": "12_1", + "asin": "B098B3XKRS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 251, + "sourceId": "13_1", + "displayId": "13_1", + "asin": "B09F9JM8F9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 252, + "sourceId": "14", + "displayId": "14", + "asin": "B08H5M3ZQ7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 253, + "sourceId": "15", + "displayId": "15", + "asin": "B0DG3NXCCF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 254, + "sourceId": "16_1", + "displayId": "16_1", + "asin": "B0FJX2FSM1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 256, + "sourceId": "17", + "displayId": "17", + "asin": "B089KHDH15", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 257, + "sourceId": "18_1", + "displayId": "18_1", + "asin": "B0CPWP6W5M", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 264, + "sourceId": "19_1", + "displayId": "19_1", + "asin": "B0D4LXTCSZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 265, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B0CK682F4T", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 267, + "sourceId": "21_1", + "displayId": "21_1", + "asin": "B0B9CGJDBV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 268, + "sourceId": "23", + "displayId": "23", + "asin": "B0DV55H9DD", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 269, + "sourceId": "25", + "displayId": "25", + "asin": "B0FJ8B8RJS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 270, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B0D426K41D", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 275, + "sourceId": "27", + "displayId": "27", + "asin": "B0CTD4BF7S", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 276, + "sourceId": "29_1", + "displayId": "29_1", + "asin": "B0CGXGQ43L", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 279, + "sourceId": "30_1", + "displayId": "30_1", + "asin": "B0BDM3B6LY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 283, + "sourceId": "1", + "displayId": "1", + "asin": "B0FS1SJGJ5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 284, + "sourceId": "2", + "displayId": "2", + "asin": "B0FJ1RH4JV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 285, + "sourceId": "3", + "displayId": "3", + "asin": "B0B9MBTX28", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 286, + "sourceId": "4", + "displayId": "4", + "asin": "B0FV2VLSX1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 287, + "sourceId": "5_1", + "displayId": "5_1", + "asin": "B0BRYKW1GD", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 289, + "sourceId": "7_1", + "displayId": "7_1", + "asin": "B0CT5G9YWM", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 291, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B0D927DZ6B", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 294, + "sourceId": "9", + "displayId": "9", + "asin": "B0DSDY3G29", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 295, + "sourceId": "10_1", + "displayId": "10_1", + "asin": "B0CWRRSV9H", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 296, + "sourceId": "11", + "displayId": "11", + "asin": "B0DNDTT9Z4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 297, + "sourceId": "13", + "displayId": "13", + "asin": "B0CP5VD5SG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 298, + "sourceId": "14_1", + "displayId": "14_1", + "asin": "B0BV2Q24YK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 300, + "sourceId": "15_1", + "displayId": "15_1", + "asin": "B0F3JD29KW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 302, + "sourceId": "16", + "displayId": "16", + "asin": "B0C818XVYT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 303, + "sourceId": "17", + "displayId": "17", + "asin": "B0FJRYQ3QV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 304, + "sourceId": "18", + "displayId": "18", + "asin": "B0CP3NYG8J", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 305, + "sourceId": "19", + "displayId": "19", + "asin": "B0F6C7XH75", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 306, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B0FXX9N5VH", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 308, + "sourceId": "22_1", + "displayId": "22_1", + "asin": "B0CFJPCSDP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 310, + "sourceId": "24_1", + "displayId": "24_1", + "asin": "B0FQJHS1MZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 311, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0D5VJN99L", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 313, + "sourceId": "26", + "displayId": "26", + "asin": "B07MCDWVJG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 314, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B0CKYJCJGD", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 319, + "sourceId": "28_1", + "displayId": "28_1", + "asin": "B0CQXPR4H4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 321, + "sourceId": "29", + "displayId": "29", + "asin": "B08S2913J7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 322, + "sourceId": "30_1", + "displayId": "30_1", + "asin": "B0CXPL3GSW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 323, + "sourceId": "1", + "displayId": "1", + "asin": "B0D7JVZWZF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 324, + "sourceId": "2", + "displayId": "2", + "asin": "B0FKMXP3ZR", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 325, + "sourceId": "3", + "displayId": "3", + "asin": "B0FGP7YJC8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 326, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B0F9PDZTCJ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 328, + "sourceId": "5_1", + "displayId": "5_1", + "asin": "B0CTLXM3C6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 331, + "sourceId": "6_1", + "displayId": "6_1", + "asin": "B0CSYB8BPK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 335, + "sourceId": "7_1", + "displayId": "7_1", + "asin": "B01I1CEEXW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 340, + "sourceId": "8", + "displayId": "8", + "asin": "B0G2Y49LCY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 341, + "sourceId": "9_1", + "displayId": "9_1", + "asin": "B0F3HK55L6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 343, + "sourceId": "10", + "displayId": "10", + "asin": "B0GWJ69JK1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 344, + "sourceId": "11_1", + "displayId": "11_1", + "asin": "B09Z877C17", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 345, + "sourceId": "12", + "displayId": "12", + "asin": "B0GLDX9NB1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 346, + "sourceId": "13_1", + "displayId": "13_1", + "asin": "B0FPC1Y19B", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 348, + "sourceId": "14", + "displayId": "14", + "asin": "B0C65438CP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 349, + "sourceId": "17", + "displayId": "17", + "asin": "B0F6MNZB6F", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 350, + "sourceId": "18", + "displayId": "18", + "asin": "B0BVPLLLRP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 351, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B0FK2B5FK2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 353, + "sourceId": "21_1", + "displayId": "21_1", + "asin": "B0BPNFMKQV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 354, + "sourceId": "22", + "displayId": "22", + "asin": "B0G4BLRDW6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 355, + "sourceId": "23", + "displayId": "23", + "asin": "B0F93QCQF1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 356, + "sourceId": "24", + "displayId": "24", + "asin": "B0FHHPYP9K", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 357, + "sourceId": "28", + "displayId": "28", + "asin": "B0F1K9KDX6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 358, + "sourceId": "29", + "displayId": "29", + "asin": "B0F52ZXD55", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 359, + "sourceId": "30_1", + "displayId": "30_1", + "asin": "B07GDGSKK6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 361, + "sourceId": "1_1", + "displayId": "1_1", + "asin": "B08BPHJ34D", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 362, + "sourceId": "2", + "displayId": "2", + "asin": "B07ZFWRH75", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 363, + "sourceId": "3", + "displayId": "3", + "asin": "B0G5PVP3Y3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 364, + "sourceId": "4", + "displayId": "4", + "asin": "B0FXXLPC1T", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 365, + "sourceId": "5", + "displayId": "5", + "asin": "B0GQB1K38X", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 366, + "sourceId": "6", + "displayId": "6", + "asin": "B0C1TCDZ5N", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 367, + "sourceId": "8", + "displayId": "8", + "asin": "B0FHD3QCLW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 368, + "sourceId": "9_1", + "displayId": "9_1", + "asin": "B0F1THT9XW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 370, + "sourceId": "11", + "displayId": "11", + "asin": "B0DYJ8743N", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 371, + "sourceId": "12_1", + "displayId": "12_1", + "asin": "B0FD3Q2RGP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 373, + "sourceId": "13_1", + "displayId": "13_1", + "asin": "B0BV66T3PQ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 374, + "sourceId": "14_1", + "displayId": "14_1", + "asin": "B0CDVYLTB4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 383, + "sourceId": "16", + "displayId": "16", + "asin": "B0CNKGFWKR", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 384, + "sourceId": "17", + "displayId": "17", + "asin": "B0D4VQF22F", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 385, + "sourceId": "18_1", + "displayId": "18_1", + "asin": "B0C5TBR8LB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 387, + "sourceId": "19", + "displayId": "19", + "asin": "B0DDH3G9PG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 388, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B0D8VRMWP2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 390, + "sourceId": "22_1", + "displayId": "22_1", + "asin": "B0BFWXWNTC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 395, + "sourceId": "23_1", + "displayId": "23_1", + "asin": "B096ZCL4JX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 399, + "sourceId": "24_1", + "displayId": "24_1", + "asin": "B0CFDXR5FC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 400, + "sourceId": "25", + "displayId": "25", + "asin": "B0G6DN5QC7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 401, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B0CNRL9R1F", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 402, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B0BJK6D2D4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 403, + "sourceId": "28_1", + "displayId": "28_1", + "asin": "B0DPFDTL7W", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 405, + "sourceId": "29_1", + "displayId": "29_1", + "asin": "B0G5N9KGXC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 406, + "sourceId": "30_1", + "displayId": "30_1", + "asin": "B0F73X9X8D", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 408, + "sourceId": "1", + "displayId": "1", + "asin": "B0CJTJB8PV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 409, + "sourceId": "2", + "displayId": "2", + "asin": "B0FBGD3QJ2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 410, + "sourceId": "3", + "displayId": "3", + "asin": "B0F98TGSQ1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 411, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B0F329ZXH5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 412, + "sourceId": "5", + "displayId": "5", + "asin": "B0G191SX5F", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 413, + "sourceId": "6", + "displayId": "6", + "asin": "B0F7XT5TNY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 414, + "sourceId": "7", + "displayId": "7", + "asin": "B0FVS7K78Q", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 415, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B0FYFZBQLT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 418, + "sourceId": "10", + "displayId": "10", + "asin": "B0FG2LHWB3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 419, + "sourceId": "11", + "displayId": "11", + "asin": "B0F9WX88T1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 420, + "sourceId": "12", + "displayId": "12", + "asin": "B0F7XNDBNN", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 421, + "sourceId": "14", + "displayId": "14", + "asin": "B0DT7GV9NS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 422, + "sourceId": "15_1", + "displayId": "15_1", + "asin": "B0DKF26TYN", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 423, + "sourceId": "18_1", + "displayId": "18_1", + "asin": "B0D1FP339J", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 424, + "sourceId": "20", + "displayId": "20", + "asin": "B0CNCBQCMG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 425, + "sourceId": "21_1", + "displayId": "21_1", + "asin": "B0CHRR45X7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 427, + "sourceId": "23", + "displayId": "23", + "asin": "B0C1RPB8BQ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 428, + "sourceId": "24", + "displayId": "24", + "asin": "B0BVPPBH7D", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 429, + "sourceId": "25", + "displayId": "25", + "asin": "B0BHQKQMG8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 430, + "sourceId": "26", + "displayId": "26", + "asin": "B0C7QQPNC9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 431, + "sourceId": "27", + "displayId": "27", + "asin": "B0FHKT5CBC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 432, + "sourceId": "29", + "displayId": "29", + "asin": "B0DR5XVMN7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 433, + "sourceId": "30", + "displayId": "30", + "asin": "B08HPS68Q4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 434, + "sourceId": "1", + "displayId": "1", + "asin": "B0C4KLQPDZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 435, + "sourceId": "2", + "displayId": "2", + "asin": "B0F6TT21VN", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 436, + "sourceId": "3", + "displayId": "3", + "asin": "B08MFB5W4Q", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 437, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B07C9Z5CG5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 441, + "sourceId": "5", + "displayId": "5", + "asin": "B07589LNBP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 442, + "sourceId": "6", + "displayId": "6", + "asin": "B08HRLZVX2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 443, + "sourceId": "7", + "displayId": "7", + "asin": "B08K7B3T6P", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 444, + "sourceId": "8", + "displayId": "8", + "asin": "B09T9YYYTS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 445, + "sourceId": "9", + "displayId": "9", + "asin": "B081ZVNH98", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 446, + "sourceId": "10", + "displayId": "10", + "asin": "B0F6T4XMXY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 447, + "sourceId": "11_1", + "displayId": "11_1", + "asin": "B07QH4X4Y5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 449, + "sourceId": "12_1", + "displayId": "12_1", + "asin": "B096S27HMH", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 460, + "sourceId": "13_1", + "displayId": "13_1", + "asin": "B0FB9DWYXF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 462, + "sourceId": "14_1", + "displayId": "14_1", + "asin": "B08R58FBXZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 494, + "sourceId": "15_1", + "displayId": "15_1", + "asin": "B0CRK8YNNY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 496, + "sourceId": "16_1", + "displayId": "16_1", + "asin": "B09C8F7J2H", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 504, + "sourceId": "17", + "displayId": "17", + "asin": "B0F6TK2KP3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 505, + "sourceId": "18_1", + "displayId": "18_1", + "asin": "B0BYJHNBWM", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 515, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B0DJBZXCDP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 516, + "sourceId": "21_1", + "displayId": "21_1", + "asin": "B0FMRGW63W", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 518, + "sourceId": "22_1", + "displayId": "22_1", + "asin": "B0D175WMJC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 519, + "sourceId": "23_1", + "displayId": "23_1", + "asin": "B07FLD65NM", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 521, + "sourceId": "24", + "displayId": "24", + "asin": "B0DRFWYNNV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 522, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0DZX3JWQP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 524, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B0F5X5G34F", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 530, + "sourceId": "28_1", + "displayId": "28_1", + "asin": "B0BJDL1D9W", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 544, + "sourceId": "29_1", + "displayId": "29_1", + "asin": "B0BYJMMMLX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 545, + "sourceId": "30_1", + "displayId": "30_1", + "asin": "B092M4RJVV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 552, + "sourceId": "1_1", + "displayId": "1_1", + "asin": "B092M49F1Q", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 565, + "sourceId": "2_1", + "displayId": "2_1", + "asin": "B0FMRFHRZR", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 566, + "sourceId": "3_1", + "displayId": "3_1", + "asin": "B0DZWVVM6F", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 570, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B0BCNZZ32X", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 580, + "sourceId": "6_1", + "displayId": "6_1", + "asin": "B0BRC8PXMW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 581, + "sourceId": "7_1", + "displayId": "7_1", + "asin": "B07RL77RM9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 582, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B0FMRBN7H4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 584, + "sourceId": "9_1", + "displayId": "9_1", + "asin": "B0FMRGHCPK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 587, + "sourceId": "10", + "displayId": "10", + "asin": "B0G4BWPCK7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 588, + "sourceId": "11_1", + "displayId": "11_1", + "asin": "B0CJJ4Y8SB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 589, + "sourceId": "13_1", + "displayId": "13_1", + "asin": "B0DYY436WG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 591, + "sourceId": "14", + "displayId": "14", + "asin": "B0G64PMQ94", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 592, + "sourceId": "16_1", + "displayId": "16_1", + "asin": "B0CST698J6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 593, + "sourceId": "17_1", + "displayId": "17_1", + "asin": "B00U7LUWR8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 594, + "sourceId": "18", + "displayId": "18", + "asin": "B0DHRJX1VS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 595, + "sourceId": "20", + "displayId": "20", + "asin": "B0CY9NB8VS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 596, + "sourceId": "21_1", + "displayId": "21_1", + "asin": "B08ML38H24", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 599, + "sourceId": "22_1", + "displayId": "22_1", + "asin": "B0BXVBVJ6G", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 605, + "sourceId": "23_1", + "displayId": "23_1", + "asin": "B08HS69FQG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 608, + "sourceId": "25", + "displayId": "25", + "asin": "B0F281WHDB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 609, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B0007RN382", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 610, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B0F2JDR3Y5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 612, + "sourceId": "28", + "displayId": "28", + "asin": "B0FX9L2JJ4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 613, + "sourceId": "29_1", + "displayId": "29_1", + "asin": "B0FD9NVNFT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 615, + "sourceId": "30", + "displayId": "30", + "asin": "B0B72HD5B9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 616, + "sourceId": "2_1", + "displayId": "2_1", + "asin": "B0F53FQ9Y4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 618, + "sourceId": "3_1", + "displayId": "3_1", + "asin": "B0GHDHPQ7J", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 629, + "sourceId": "5_1", + "displayId": "5_1", + "asin": "B07B9ZP8TK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 631, + "sourceId": "6", + "displayId": "6", + "asin": "B0DPWW9P2V", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 632, + "sourceId": "7_1", + "displayId": "7_1", + "asin": "B0CR43DTKJ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 659, + "sourceId": "8", + "displayId": "8", + "asin": "B0G8K4C3D6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 660, + "sourceId": "10_1", + "displayId": "10_1", + "asin": "B0F52TLKVM", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 662, + "sourceId": "11", + "displayId": "11", + "asin": "B0BGH6Y6KB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 663, + "sourceId": "12_1", + "displayId": "12_1", + "asin": "B0D28VG1C3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 667, + "sourceId": "13_1", + "displayId": "13_1", + "asin": "B0D3LLKF7C", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 670, + "sourceId": "14", + "displayId": "14", + "asin": "B09KT2VBJL", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 671, + "sourceId": "15_1", + "displayId": "15_1", + "asin": "B07F6P6C3F", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 672, + "sourceId": "18_1", + "displayId": "18_1", + "asin": "B0GCZH5V2P", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 709, + "sourceId": "19_1", + "displayId": "19_1", + "asin": "B0FH5RNFZQ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 710, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B0CSFMDTSR", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 714, + "sourceId": "21", + "displayId": "21", + "asin": "B0GR9TS4N8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 715, + "sourceId": "22", + "displayId": "22", + "asin": "B0D9GWVPGJ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 716, + "sourceId": "23_1", + "displayId": "23_1", + "asin": "B0GF2BKHJK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 717, + "sourceId": "24_1", + "displayId": "24_1", + "asin": "B0GQZ8SPZZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 719, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0D3LQF6P5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 720, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B0GF2ML2NY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 722, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B0C28BCVH6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 723, + "sourceId": "28_1", + "displayId": "28_1", + "asin": "B0C1CRZPMS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 730, + "sourceId": "29_1", + "displayId": "29_1", + "asin": "B0F8HKX897", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 734, + "sourceId": "30_1", + "displayId": "30_1", + "asin": "B0GSKSC1KR", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 735, + "sourceId": "2_1", + "displayId": "2_1", + "asin": "B0GSQGF76K", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 736, + "sourceId": "3_1", + "displayId": "3_1", + "asin": "B0F9WTNVXP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 738, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B0F47S987P", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 740, + "sourceId": "5_1", + "displayId": "5_1", + "asin": "B0F4Y4F5TC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 741, + "sourceId": "6_1", + "displayId": "6_1", + "asin": "B0DYNW29NB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 748, + "sourceId": "7_1", + "displayId": "7_1", + "asin": "B0GF29HX77", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 749, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B0GM2WBVXF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 751, + "sourceId": "9", + "displayId": "9", + "asin": "B0GGWW658M", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 752, + "sourceId": "10", + "displayId": "10", + "asin": "B0F32R7JTF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 753, + "sourceId": "11", + "displayId": "11", + "asin": "B0DZ67TBHQ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 754, + "sourceId": "12_1", + "displayId": "12_1", + "asin": "B0CLC6KSZH", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 755, + "sourceId": "13_1", + "displayId": "13_1", + "asin": "B0F8QW1FS1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 760, + "sourceId": "14_1", + "displayId": "14_1", + "asin": "B0F6LHFVJ3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 768, + "sourceId": "16", + "displayId": "16", + "asin": "B0DZH72GF6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 769, + "sourceId": "17_1", + "displayId": "17_1", + "asin": "B099N1FB4K", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 771, + "sourceId": "18", + "displayId": "18", + "asin": "B0BS678GBK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 772, + "sourceId": "19_1", + "displayId": "19_1", + "asin": "B0F5Y4KSQJ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 778, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B0D584KC9W", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 805, + "sourceId": "21_1", + "displayId": "21_1", + "asin": "B0GK1D75ZF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 810, + "sourceId": "22_1", + "displayId": "22_1", + "asin": "B0DPWXNWV5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 812, + "sourceId": "23_1", + "displayId": "23_1", + "asin": "B0G64ZCGTV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 813, + "sourceId": "24_1", + "displayId": "24_1", + "asin": "B07VHK16YV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 815, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0GS3QV5F2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 816, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B0DC7TR9B5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 821, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B0FH634932", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 824, + "sourceId": "28_1", + "displayId": "28_1", + "asin": "B0CY2XN6JF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 826, + "sourceId": "29_1", + "displayId": "29_1", + "asin": "B0GKR5WMXK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 829, + "sourceId": "30", + "displayId": "30", + "asin": "B0GH4KYZH5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 830, + "sourceId": "1_1", + "displayId": "1_1", + "asin": "B0FD76KJ9P", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 831, + "sourceId": "3", + "displayId": "3", + "asin": "B0836NDGM2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 832, + "sourceId": "4", + "displayId": "4", + "asin": "B0DYJWTS4N", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 833, + "sourceId": "5", + "displayId": "5", + "asin": "B089X4VCPY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 834, + "sourceId": "6", + "displayId": "6", + "asin": "B0CQZR1LZX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 835, + "sourceId": "7_1", + "displayId": "7_1", + "asin": "B0GSVTDQBX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 837, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B0D9TK3VMD", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 839, + "sourceId": "9_1", + "displayId": "9_1", + "asin": "B0GDZWHF6D", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 841, + "sourceId": "10_1", + "displayId": "10_1", + "asin": "B0C8N1LZT9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 842, + "sourceId": "12", + "displayId": "12", + "asin": "B0GWHQHKJS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 843, + "sourceId": "13", + "displayId": "13", + "asin": "B0BTTJKZDC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 844, + "sourceId": "14", + "displayId": "14", + "asin": "B0DZPDJ7Q4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 845, + "sourceId": "15_1", + "displayId": "15_1", + "asin": "B0D5W9F2DS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 849, + "sourceId": "16_1", + "displayId": "16_1", + "asin": "B0CGCPLWV1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 850, + "sourceId": "17_1", + "displayId": "17_1", + "asin": "B09VT58BM4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 852, + "sourceId": "19_1", + "displayId": "19_1", + "asin": "B07XZT797H", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 854, + "sourceId": "20", + "displayId": "20", + "asin": "B0GW9TR89X", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 856, + "sourceId": "23_1", + "displayId": "23_1", + "asin": "B09ZKT7QW6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 859, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0CJYRW7RL", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 861, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B0DSZ4V9PJ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 862, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B09TKN8F9W", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 863, + "sourceId": "28_1", + "displayId": "28_1", + "asin": "B09SW82GSP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 871, + "sourceId": "2_1", + "displayId": "2_1", + "asin": "B001F4OSJY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 878, + "sourceId": "3", + "displayId": "3", + "asin": "B091BK7ZF3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 879, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B07HSL53DY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 883, + "sourceId": "5", + "displayId": "5", + "asin": "B07HSDTYC8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 884, + "sourceId": "6_1", + "displayId": "6_1", + "asin": "B0FKN7JZ6B", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 886, + "sourceId": "7_1", + "displayId": "7_1", + "asin": "B071XJDSBK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 889, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B006UITUJ8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 890, + "sourceId": "10_1", + "displayId": "10_1", + "asin": "B0CBPWL6NZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 891, + "sourceId": "11", + "displayId": "11", + "asin": "B0G3Q9B48L", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 892, + "sourceId": "12", + "displayId": "12", + "asin": "B0BYJV8P98", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 893, + "sourceId": "13_1", + "displayId": "13_1", + "asin": "B0G8DTQP1F", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 897, + "sourceId": "14_1", + "displayId": "14_1", + "asin": "B0CYP192B6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 898, + "sourceId": "15_1", + "displayId": "15_1", + "asin": "B0CCN8TJCD", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 903, + "sourceId": "16_1", + "displayId": "16_1", + "asin": "B0FWKJVMNK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 906, + "sourceId": "19", + "displayId": "19", + "asin": "B0GD11NDH2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 907, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B0BC2NFJBP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 911, + "sourceId": "21_1", + "displayId": "21_1", + "asin": "B0D9RRCC93", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 913, + "sourceId": "23_1", + "displayId": "23_1", + "asin": "B0DLSZFMM2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 918, + "sourceId": "24_1", + "displayId": "24_1", + "asin": "B0GFBG4HSR", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 919, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B07TBCFGPT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 920, + "sourceId": "27", + "displayId": "27", + "asin": "B0GSZRFZGZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 921, + "sourceId": "29_1", + "displayId": "29_1", + "asin": "B008OB1AZ6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 922, + "sourceId": "30_1", + "displayId": "30_1", + "asin": "B09XLVPYPR", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 930, + "sourceId": "1_1", + "displayId": "1_1", + "asin": "B0FZK5NCWK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 933, + "sourceId": "2_1", + "displayId": "2_1", + "asin": "B0DYJTRT6K", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 934, + "sourceId": "3_1", + "displayId": "3_1", + "asin": "B0CL664TZX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 936, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B0DN6XQ5W4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 938, + "sourceId": "5_1", + "displayId": "5_1", + "asin": "B002HNNWLM", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 943, + "sourceId": "6_1", + "displayId": "6_1", + "asin": "B0F5HHHR65", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 946, + "sourceId": "7_1", + "displayId": "7_1", + "asin": "B0G5739C1J", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 951, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B0G11TTQPT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 952, + "sourceId": "9_1", + "displayId": "9_1", + "asin": "B0G579K29G", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 957, + "sourceId": "10", + "displayId": "10", + "asin": "B0G57DKM85", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 958, + "sourceId": "11", + "displayId": "11", + "asin": "B0DGFW14PB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 959, + "sourceId": "12_1", + "displayId": "12_1", + "asin": "B0DK3YXKS5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 960, + "sourceId": "13_1", + "displayId": "13_1", + "asin": "B0FGTHRS1R", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 961, + "sourceId": "14_1", + "displayId": "14_1", + "asin": "B0FP2FDZPZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 963, + "sourceId": "15", + "displayId": "15", + "asin": "B002HO7QQ8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 964, + "sourceId": "16_1", + "displayId": "16_1", + "asin": "B002HNS1TU", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 966, + "sourceId": "17_1", + "displayId": "17_1", + "asin": "B004KL50HS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 967, + "sourceId": "18_1", + "displayId": "18_1", + "asin": "B07QK3B4Q5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 972, + "sourceId": "19", + "displayId": "19", + "asin": "B08DVGHKLL", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 973, + "sourceId": "20", + "displayId": "20", + "asin": "B08K3ZYRGC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 974, + "sourceId": "21", + "displayId": "21", + "asin": "B0DZWVCVK1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 975, + "sourceId": "23_1", + "displayId": "23_1", + "asin": "B0CT29V1D5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 977, + "sourceId": "24_1", + "displayId": "24_1", + "asin": "B01N7G9ALO", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 978, + "sourceId": "25", + "displayId": "25", + "asin": "B0CQLN3T6N", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 979, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B0FJKTYHSV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 981, + "sourceId": "28", + "displayId": "28", + "asin": "B0FRFNVTKX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 982, + "sourceId": "1", + "displayId": "1", + "asin": "B0DJQWP543", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 983, + "sourceId": "3", + "displayId": "3", + "asin": "B0D7M543CT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 984, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B0F21QQQL1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 987, + "sourceId": "5", + "displayId": "5", + "asin": "B0CMZR1JJD", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 988, + "sourceId": "6", + "displayId": "6", + "asin": "B0F66NTL6T", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 989, + "sourceId": "7", + "displayId": "7", + "asin": "B0D976JCLF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 990, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B0FP2DMFMG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 991, + "sourceId": "9_1", + "displayId": "9_1", + "asin": "B0CTDM36PB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 994, + "sourceId": "10", + "displayId": "10", + "asin": "B0DY76XFLY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 995, + "sourceId": "11", + "displayId": "11", + "asin": "B0CQ4PS256", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 996, + "sourceId": "12_1", + "displayId": "12_1", + "asin": "B0C15RDVDK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 997, + "sourceId": "13", + "displayId": "13", + "asin": "B0F5Y8Y58T", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 998, + "sourceId": "14", + "displayId": "14", + "asin": "B0B5CBKC17", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 999, + "sourceId": "16_1", + "displayId": "16_1", + "asin": "B0FMXVRQM2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1000, + "sourceId": "18", + "displayId": "18", + "asin": "B0DC2WX8Q2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1001, + "sourceId": "19_1", + "displayId": "19_1", + "asin": "B0FVR6L7NP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1004, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B0DFQMCBS7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1006, + "sourceId": "21", + "displayId": "21", + "asin": "B07TSMHP3T", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1007, + "sourceId": "23_1", + "displayId": "23_1", + "asin": "B09DY2KCLB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1008, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0GRTXKMGZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1010, + "sourceId": "26", + "displayId": "26", + "asin": "B0BG4TTWWW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1011, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B0FC2QBR9T", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1012, + "sourceId": "29_1", + "displayId": "29_1", + "asin": "B09Y2H27PS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1013, + "sourceId": "30_1", + "displayId": "30_1", + "asin": "B0CTGLQFCD", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1016, + "sourceId": "2_1", + "displayId": "2_1", + "asin": "B01MCVO50E", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1017, + "sourceId": "3", + "displayId": "3", + "asin": "B0FJXM3T1S", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1018, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B0C8MG6NF7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1019, + "sourceId": "5_1", + "displayId": "5_1", + "asin": "B0C7NK648Y", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1020, + "sourceId": "6", + "displayId": "6", + "asin": "B0DYFDXD8N", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1021, + "sourceId": "7", + "displayId": "7", + "asin": "B0GGMLRZWF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1022, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B0D45VVD1Y", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1024, + "sourceId": "9_1", + "displayId": "9_1", + "asin": "B0CC6KP279", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1046, + "sourceId": "12", + "displayId": "12", + "asin": "B0FRZYQYGT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1047, + "sourceId": "13", + "displayId": "13", + "asin": "B0DK447HBK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1048, + "sourceId": "14", + "displayId": "14", + "asin": "B0788GRQT1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1049, + "sourceId": "15", + "displayId": "15", + "asin": "B0F93QPPVD", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1050, + "sourceId": "16_1", + "displayId": "16_1", + "asin": "B0BRQG6CKG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1051, + "sourceId": "17", + "displayId": "17", + "asin": "B09DCW6XN1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1052, + "sourceId": "18", + "displayId": "18", + "asin": "B0FSQDHC9V", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1053, + "sourceId": "19_1", + "displayId": "19_1", + "asin": "B0D25DHV1T", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1054, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B0DJF4Z91G", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1056, + "sourceId": "21_1", + "displayId": "21_1", + "asin": "B0F3J3B1R2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1060, + "sourceId": "24_1", + "displayId": "24_1", + "asin": "B0F3J6WJZJ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1062, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B0FQTWP8GM", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1065, + "sourceId": "28", + "displayId": "28", + "asin": "B0FPQL1ZW9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1066, + "sourceId": "29_1", + "displayId": "29_1", + "asin": "B0B77PQ12W", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1068, + "sourceId": "30", + "displayId": "30", + "asin": "B0FXWTDY16", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1069, + "sourceId": "1_1", + "displayId": "1_1", + "asin": "B0D6ZV5F22", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1070, + "sourceId": "2", + "displayId": "2", + "asin": "B0BF13CW1W", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1071, + "sourceId": "3", + "displayId": "3", + "asin": "B0F52CM3X1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1072, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B0043RJSSG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1095, + "sourceId": "5_1", + "displayId": "5_1", + "asin": "B07V2G46J7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1096, + "sourceId": "6_1", + "displayId": "6_1", + "asin": "B07X4V22PW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1098, + "sourceId": "7_1", + "displayId": "7_1", + "asin": "B0GQXDVW6C", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1099, + "sourceId": "8", + "displayId": "8", + "asin": "B0BK888623", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1100, + "sourceId": "9_1", + "displayId": "9_1", + "asin": "B0BFWC5SZQ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1102, + "sourceId": "10_1", + "displayId": "10_1", + "asin": "B0F1C9ZQKD", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1106, + "sourceId": "11", + "displayId": "11", + "asin": "B09F5VV8DW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1107, + "sourceId": "12", + "displayId": "12", + "asin": "B0BWMT9LFC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1108, + "sourceId": "14_1", + "displayId": "14_1", + "asin": "B0FJLQLRNT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1112, + "sourceId": "15", + "displayId": "15", + "asin": "B08ZCNVYTK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1113, + "sourceId": "16", + "displayId": "16", + "asin": "B0CMZLKY9T", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1114, + "sourceId": "17", + "displayId": "17", + "asin": "B0GJZXZ2F9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1115, + "sourceId": "18", + "displayId": "18", + "asin": "B07BMFCKCR", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1116, + "sourceId": "19_1", + "displayId": "19_1", + "asin": "B0DK46T977", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1118, + "sourceId": "20", + "displayId": "20", + "asin": "B08HCPX1MB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1119, + "sourceId": "21_1", + "displayId": "21_1", + "asin": "B0D8L6WRCM", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1121, + "sourceId": "23_1", + "displayId": "23_1", + "asin": "B09NDN8NV1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1122, + "sourceId": "24", + "displayId": "24", + "asin": "B0GT2527XG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1123, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0FNRCLHNS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1127, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B0DQS8GKLG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1129, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B003NGLFYI", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1132, + "sourceId": "28", + "displayId": "28", + "asin": "B0CR4FTMGG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1133, + "sourceId": "29", + "displayId": "29", + "asin": "B0DK9ZBBKS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1134, + "sourceId": "30", + "displayId": "30", + "asin": "B0D1XX28FN", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1135, + "sourceId": "1_1", + "displayId": "1_1", + "asin": "B003KHEEY8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1151, + "sourceId": "2_1", + "displayId": "2_1", + "asin": "B0F9WRKC84", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1153, + "sourceId": "3", + "displayId": "3", + "asin": "B08BHKGYJ7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1154, + "sourceId": "4", + "displayId": "4", + "asin": "B0FT1562DX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1155, + "sourceId": "5", + "displayId": "5", + "asin": "B0F8QRJ9JB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1156, + "sourceId": "6_1", + "displayId": "6_1", + "asin": "B0070OARSO", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1168, + "sourceId": "7", + "displayId": "7", + "asin": "B07XJ4W6SW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1169, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B0C1V86KMX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1170, + "sourceId": "9_1", + "displayId": "9_1", + "asin": "B0CGM1Z2VG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1171, + "sourceId": "10_1", + "displayId": "10_1", + "asin": "B004699SWM", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1220, + "sourceId": "11", + "displayId": "11", + "asin": "B0GT281VQK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1221, + "sourceId": "13_1", + "displayId": "13_1", + "asin": "B09BCSR7NQ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1222, + "sourceId": "24_1", + "displayId": "24_1", + "asin": "B003YCKTIE", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1223, + "sourceId": "29_1", + "displayId": "29_1", + "asin": "B092CGQN2K", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1224, + "sourceId": "30_1", + "displayId": "30_1", + "asin": "B001WSDMBI", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1225, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B079C2CDLD", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1227, + "sourceId": "5", + "displayId": "5", + "asin": "B077WX43MH", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1228, + "sourceId": "6_1", + "displayId": "6_1", + "asin": "B0FQ2YC11V", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1229, + "sourceId": "7_1", + "displayId": "7_1", + "asin": "B0DRFQJ6CX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1231, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B0BX65MF93", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1233, + "sourceId": "9", + "displayId": "9", + "asin": "B0CT5ZR247", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1234, + "sourceId": "10", + "displayId": "10", + "asin": "B0BFXLLR2F", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1235, + "sourceId": "11_1", + "displayId": "11_1", + "asin": "B0FDQT4X7W", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1236, + "sourceId": "13_1", + "displayId": "13_1", + "asin": "B0FQ2XD95Z", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1238, + "sourceId": "15", + "displayId": "15", + "asin": "B094RDMZ3Z", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1239, + "sourceId": "16_1", + "displayId": "16_1", + "asin": "B0DMZHTJY2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1240, + "sourceId": "18", + "displayId": "18", + "asin": "B0CS2TQGM5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1241, + "sourceId": "19", + "displayId": "19", + "asin": "B0DG2XK945", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1242, + "sourceId": "21", + "displayId": "21", + "asin": "B0G2LNGQPK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1243, + "sourceId": "22", + "displayId": "22", + "asin": "B0G4R1RHYH", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1244, + "sourceId": "24_1", + "displayId": "24_1", + "asin": "B0GSRZM4XB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1245, + "sourceId": "25", + "displayId": "25", + "asin": "B0D926NJN9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1246, + "sourceId": "26", + "displayId": "26", + "asin": "B01LZBHEKJ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1247, + "sourceId": "27", + "displayId": "27", + "asin": "B09LQL4S9Q", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1248, + "sourceId": "29_1", + "displayId": "29_1", + "asin": "B0CQTPF6BJ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1256, + "sourceId": "30", + "displayId": "30", + "asin": "B0DZVY2F7M", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1257, + "sourceId": "1", + "displayId": "1", + "asin": "B0GMYGQ2G6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1258, + "sourceId": "3_1", + "displayId": "3_1", + "asin": "B0C5WQ6DFB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1261, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B0DJVK3SC4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1262, + "sourceId": "5_1", + "displayId": "5_1", + "asin": "B000N324DU", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1267, + "sourceId": "6", + "displayId": "6", + "asin": "B074F6YQZW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1268, + "sourceId": "7_1", + "displayId": "7_1", + "asin": "B09MD5W6Z5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1269, + "sourceId": "8", + "displayId": "8", + "asin": "B0F94GJX9D", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1270, + "sourceId": "9", + "displayId": "9", + "asin": "B0DP298J3J", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1271, + "sourceId": "10", + "displayId": "10", + "asin": "B010W3V6Z2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1272, + "sourceId": "11_1", + "displayId": "11_1", + "asin": "B0F24BSV4V", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1273, + "sourceId": "12", + "displayId": "12", + "asin": "B0B9MKBPH9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1274, + "sourceId": "13", + "displayId": "13", + "asin": "B0BHHKC5JQ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1275, + "sourceId": "14", + "displayId": "14", + "asin": "B0B4RFNK72", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1276, + "sourceId": "15", + "displayId": "15", + "asin": "B01LXD3KE6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1277, + "sourceId": "17", + "displayId": "17", + "asin": "B010W3V1W0", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1278, + "sourceId": "18", + "displayId": "18", + "asin": "B095JNPP53", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1279, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B0D7DSBNNH", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1281, + "sourceId": "21", + "displayId": "21", + "asin": "B0B935PV25", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1282, + "sourceId": "22", + "displayId": "22", + "asin": "B0B67XDHPQ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1283, + "sourceId": "24", + "displayId": "24", + "asin": "B072Z1PQM2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1284, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0CT1J5HWX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1285, + "sourceId": "26", + "displayId": "26", + "asin": "B097G2DXSQ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1286, + "sourceId": "27", + "displayId": "27", + "asin": "B010W3VLE8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1287, + "sourceId": "28", + "displayId": "28", + "asin": "B00R39MP4A", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1288, + "sourceId": "29", + "displayId": "29", + "asin": "B095JMYSQ9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1289, + "sourceId": "30", + "displayId": "30", + "asin": "B0F8F5H3MG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1290, + "sourceId": "1", + "displayId": "1", + "asin": "B0DNM4R43P", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1291, + "sourceId": "2", + "displayId": "2", + "asin": "B0FCFB3X78", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1292, + "sourceId": "3", + "displayId": "3", + "asin": "B0CN4KXVWF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1293, + "sourceId": "4", + "displayId": "4", + "asin": "B0D455HLWT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1294, + "sourceId": "5", + "displayId": "5", + "asin": "B0B1HYLLYT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1295, + "sourceId": "6_1", + "displayId": "6_1", + "asin": "B0F1TKQG14", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1296, + "sourceId": "7", + "displayId": "7", + "asin": "B0F32CLT9F", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1297, + "sourceId": "8", + "displayId": "8", + "asin": "B0DJXYDPFC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1298, + "sourceId": "9", + "displayId": "9", + "asin": "B0B3RRLNCT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1299, + "sourceId": "10", + "displayId": "10", + "asin": "B0F2DR94NT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1300, + "sourceId": "11", + "displayId": "11", + "asin": "B0BL7HRF5R", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1301, + "sourceId": "12", + "displayId": "12", + "asin": "B0B6PT6D7Q", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1302, + "sourceId": "13", + "displayId": "13", + "asin": "B0FF4FLHM4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1303, + "sourceId": "14", + "displayId": "14", + "asin": "B07L2476DB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1304, + "sourceId": "15", + "displayId": "15", + "asin": "B0CK4379VH", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1305, + "sourceId": "16", + "displayId": "16", + "asin": "B0BRFW6XF4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1306, + "sourceId": "17", + "displayId": "17", + "asin": "B07BZT7699", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1307, + "sourceId": "18_1", + "displayId": "18_1", + "asin": "B0D8W4JRTY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1308, + "sourceId": "19", + "displayId": "19", + "asin": "B0F9NQMWGC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1309, + "sourceId": "20", + "displayId": "20", + "asin": "B07CF8KD48", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1310, + "sourceId": "21", + "displayId": "21", + "asin": "B0F9NWBVD8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1311, + "sourceId": "22", + "displayId": "22", + "asin": "B0DSZK41Z9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1312, + "sourceId": "23", + "displayId": "23", + "asin": "B0DHP1TPQL", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1313, + "sourceId": "24_1", + "displayId": "24_1", + "asin": "B0DPHSPQRP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1314, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0BVZ3VKNX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1320, + "sourceId": "26", + "displayId": "26", + "asin": "B0FPX7363M", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1321, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B0F9KCHB7F", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1323, + "sourceId": "28_1", + "displayId": "28_1", + "asin": "B07L3H5DDW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1325, + "sourceId": "30", + "displayId": "30", + "asin": "B003K5S4NW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1326, + "sourceId": "1_1", + "displayId": "1_1", + "asin": "B0BNVHXLDN", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1328, + "sourceId": "2", + "displayId": "2", + "asin": "B0FC2R299V", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1329, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B0BNVJPSDT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1330, + "sourceId": "5", + "displayId": "5", + "asin": "B0CCRNRHYW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1331, + "sourceId": "6_1", + "displayId": "6_1", + "asin": "B0FP2NQM67", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1334, + "sourceId": "7", + "displayId": "7", + "asin": "B0DRSD66T3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1335, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B0DM6CS4KG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1336, + "sourceId": "9_1", + "displayId": "9_1", + "asin": "B0GQ2YGFTR", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1338, + "sourceId": "10", + "displayId": "10", + "asin": "B0F1LNXRSH", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1339, + "sourceId": "11", + "displayId": "11", + "asin": "B0GJ59NQTT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1340, + "sourceId": "12", + "displayId": "12", + "asin": "B0GKY1T54N", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1341, + "sourceId": "13", + "displayId": "13", + "asin": "B0FZNMHLDY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1342, + "sourceId": "14_1", + "displayId": "14_1", + "asin": "B0DHWYL3JP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1344, + "sourceId": "16_1", + "displayId": "16_1", + "asin": "B0CW5DD6SC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1351, + "sourceId": "17_1", + "displayId": "17_1", + "asin": "B0CRH7T5WG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1353, + "sourceId": "19_1", + "displayId": "19_1", + "asin": "B0CRR6F9JX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1354, + "sourceId": "20", + "displayId": "20", + "asin": "B09D3XG1PT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1355, + "sourceId": "22", + "displayId": "22", + "asin": "B00AFGCL42", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1356, + "sourceId": "24_1", + "displayId": "24_1", + "asin": "B0CXP3619X", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1357, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0CW5GFQX3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1363, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B0CZDK561H", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1364, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B0FKLRMG14", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1373, + "sourceId": "28_1", + "displayId": "28_1", + "asin": "B0DFQWC297", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1383, + "sourceId": "1_1", + "displayId": "1_1", + "asin": "B0DGPV9QY8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1386, + "sourceId": "2_1", + "displayId": "2_1", + "asin": "B0GV3W42MJ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1388, + "sourceId": "3_1", + "displayId": "3_1", + "asin": "B0DK4JV5YY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1402, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B0CV4K3HSW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1403, + "sourceId": "9", + "displayId": "9", + "asin": "B0FN5YD344", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1404, + "sourceId": "10", + "displayId": "10", + "asin": "B01HY4XZE2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1407, + "sourceId": "13", + "displayId": "13", + "asin": "B0D485JG3T", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1408, + "sourceId": "15", + "displayId": "15", + "asin": "B0GC584NTL", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1409, + "sourceId": "16", + "displayId": "16", + "asin": "B0FDQLKJL3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1410, + "sourceId": "18_1", + "displayId": "18_1", + "asin": "B0D6RBQR4Q", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1418, + "sourceId": "19_1", + "displayId": "19_1", + "asin": "B0CSLMZ4XS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1419, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B0FC64KYP9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1421, + "sourceId": "21_1", + "displayId": "21_1", + "asin": "B0FH234TL6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1445, + "sourceId": "22_1", + "displayId": "22_1", + "asin": "B0F6D4Z3WB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1455, + "sourceId": "23_1", + "displayId": "23_1", + "asin": "B0F8RCZ91V", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1465, + "sourceId": "24_1", + "displayId": "24_1", + "asin": "B0FP5Q7B7X", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1476, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0FM88JBRX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1477, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B0CKMT72MX", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1486, + "sourceId": "27", + "displayId": "27", + "asin": "B0C4JT7PHB", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1487, + "sourceId": "28", + "displayId": "28", + "asin": "B0C1RMVGTZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1488, + "sourceId": "29", + "displayId": "29", + "asin": "B07BFQJ3G5", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1489, + "sourceId": "30", + "displayId": "30", + "asin": "B074VGHYF8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1490, + "sourceId": "1", + "displayId": "1", + "asin": "B015AK9JXI", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1491, + "sourceId": "2_1", + "displayId": "2_1", + "asin": "B084WSGN9C", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1492, + "sourceId": "3_1", + "displayId": "3_1", + "asin": "B0FHWJ42Q8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1497, + "sourceId": "4_1", + "displayId": "4_1", + "asin": "B0CZDTGFSQ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1498, + "sourceId": "5_1", + "displayId": "5_1", + "asin": "B0F7XKNY9L", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1499, + "sourceId": "6", + "displayId": "6", + "asin": "B0DWLFKPNW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1500, + "sourceId": "7_1", + "displayId": "7_1", + "asin": "B0CWDPSJG4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1512, + "sourceId": "8_1", + "displayId": "8_1", + "asin": "B0G488Z8JG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1514, + "sourceId": "9_1", + "displayId": "9_1", + "asin": "B0BYRQ5TBY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1515, + "sourceId": "10", + "displayId": "10", + "asin": "B0CWH1MRCV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1516, + "sourceId": "11", + "displayId": "11", + "asin": "B0FSCXLBHZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1517, + "sourceId": "12", + "displayId": "12", + "asin": "B0GH6YJX2L", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1518, + "sourceId": "13_1", + "displayId": "13_1", + "asin": "B0GMQ29YQ9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1519, + "sourceId": "14_1", + "displayId": "14_1", + "asin": "B0BQLX4QP3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1521, + "sourceId": "15", + "displayId": "15", + "asin": "B0FXVHQNQ4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1522, + "sourceId": "16", + "displayId": "16", + "asin": "B072DVNZYH", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1523, + "sourceId": "17_1", + "displayId": "17_1", + "asin": "B0G198MZH3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1524, + "sourceId": "18", + "displayId": "18", + "asin": "B0F7HGQHLP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1525, + "sourceId": "19", + "displayId": "19", + "asin": "B0B9M83MZV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1526, + "sourceId": "20", + "displayId": "20", + "asin": "B074P9YRGW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1527, + "sourceId": "21_1", + "displayId": "21_1", + "asin": "B0G3YJ32Q4", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1528, + "sourceId": "22", + "displayId": "22", + "asin": "B0D8RXPCH6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1529, + "sourceId": "24", + "displayId": "24", + "asin": "B0CBPKKT98", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1530, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0DGG82L25", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1531, + "sourceId": "26", + "displayId": "26", + "asin": "B0FXVNDFHC", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1532, + "sourceId": "27", + "displayId": "27", + "asin": "B0CYY2YJ2S", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1533, + "sourceId": "28", + "displayId": "28", + "asin": "B0FC34Z9P6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1534, + "sourceId": "29", + "displayId": "29", + "asin": "B0018MQIVO", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1535, + "sourceId": "30", + "displayId": "30", + "asin": "B018OQ66AE", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1536, + "sourceId": "1", + "displayId": "1", + "asin": "B0FNMK6R7Z", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1537, + "sourceId": "3", + "displayId": "3", + "asin": "B0CTJ8WRWZ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1538, + "sourceId": "4", + "displayId": "4", + "asin": "B0CTJ9522Y", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1539, + "sourceId": "5", + "displayId": "5", + "asin": "B0CTJ88CKR", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1540, + "sourceId": "6", + "displayId": "6", + "asin": "B07DL3PBL7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1541, + "sourceId": "7_1", + "displayId": "7_1", + "asin": "B0C96V7HFN", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1543, + "sourceId": "8", + "displayId": "8", + "asin": "B079HQKBP3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1544, + "sourceId": "9", + "displayId": "9", + "asin": "B0BZHW8VQ6", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1545, + "sourceId": "10_1", + "displayId": "10_1", + "asin": "B019RKRGWS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1547, + "sourceId": "11", + "displayId": "11", + "asin": "B0DCLSFGQS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1548, + "sourceId": "12", + "displayId": "12", + "asin": "B07FL8Y4BP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1549, + "sourceId": "14", + "displayId": "14", + "asin": "B01NBVCL86", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1550, + "sourceId": "15_1", + "displayId": "15_1", + "asin": "B0C8J5Z7VN", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1551, + "sourceId": "16", + "displayId": "16", + "asin": "B0CP73M8ST", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1552, + "sourceId": "18", + "displayId": "18", + "asin": "B0G2XVTF2R", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1553, + "sourceId": "19_1", + "displayId": "19_1", + "asin": "B08GCVHM9S", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1555, + "sourceId": "20_1", + "displayId": "20_1", + "asin": "B0B5X3YGMP", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1557, + "sourceId": "22", + "displayId": "22", + "asin": "B07VM7QS8C", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1558, + "sourceId": "23", + "displayId": "23", + "asin": "B0F93G7KFF", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1559, + "sourceId": "24", + "displayId": "24", + "asin": "B098B8QTM1", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1560, + "sourceId": "25_1", + "displayId": "25_1", + "asin": "B0F4WSK73F", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1561, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B0DC5M4XT7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1564, + "sourceId": "27", + "displayId": "27", + "asin": "B07SD5DWFT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1565, + "sourceId": "28", + "displayId": "28", + "asin": "B082ZNZG3X", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1566, + "sourceId": "29", + "displayId": "29", + "asin": "B084M4ZGC3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1567, + "sourceId": "30", + "displayId": "30", + "asin": "B0FXH7SVWV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1568, + "sourceId": "3", + "displayId": "3", + "asin": "B07RM4MB3H", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1569, + "sourceId": "4", + "displayId": "4", + "asin": "B0154H395G", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1570, + "sourceId": "5", + "displayId": "5", + "asin": "B08CHFDRJT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1571, + "sourceId": "6", + "displayId": "6", + "asin": "B09YQ3D7CW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1572, + "sourceId": "7_1", + "displayId": "7_1", + "asin": "B087YTMRK8", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1574, + "sourceId": "8", + "displayId": "8", + "asin": "B08WKDDV96", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1575, + "sourceId": "9", + "displayId": "9", + "asin": "B0GFMG4SFT", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1576, + "sourceId": "10", + "displayId": "10", + "asin": "B07KWY3XLW", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1577, + "sourceId": "11", + "displayId": "11", + "asin": "B07RQTKPSK", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1578, + "sourceId": "12", + "displayId": "12", + "asin": "B0CRHC42M2", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1579, + "sourceId": "14", + "displayId": "14", + "asin": "B07RGG2TCV", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1580, + "sourceId": "15", + "displayId": "15", + "asin": "B0CTJNQ5MH", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1581, + "sourceId": "16", + "displayId": "16", + "asin": "B0GGZSVY7G", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1582, + "sourceId": "17", + "displayId": "17", + "asin": "B0G3WTPGMG", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1583, + "sourceId": "18", + "displayId": "18", + "asin": "B0GH136M59", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1584, + "sourceId": "19", + "displayId": "19", + "asin": "B0G3WJP9HJ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1585, + "sourceId": "20", + "displayId": "20", + "asin": "B0814RZNHY", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1586, + "sourceId": "21", + "displayId": "21", + "asin": "B09ZXZH432", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1587, + "sourceId": "22_1", + "displayId": "22_1", + "asin": "B0BWY99XXS", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1589, + "sourceId": "23", + "displayId": "23", + "asin": "B0849Y6VYJ", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1590, + "sourceId": "24", + "displayId": "24", + "asin": "B0FKBBNN2G", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1591, + "sourceId": "25", + "displayId": "25", + "asin": "B07SBWB2X9", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1592, + "sourceId": "26_1", + "displayId": "26_1", + "asin": "B0DK4JNBM3", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1593, + "sourceId": "27_1", + "displayId": "27_1", + "asin": "B0FFZ3636F", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1594, + "sourceId": "29", + "displayId": "29", + "asin": "B0BRGZKXN7", + "country": "英国", + "url": "", + "title": "" + }, + { + "rowIndex": 1602, + "sourceId": "2", + "displayId": "2", + "asin": "B0GSTM85H3", + "country": "英国", + "url": "", + "title": "" + } + ] + }, + "code": None +} + spide.process_task(task_data) \ No newline at end of file diff --git a/app/amazon/main.py b/app/amazon/main.py index 91b664a..1b8a035 100644 --- a/app/amazon/main.py +++ b/app/amazon/main.py @@ -9,6 +9,8 @@ from amazon.del_brand import AmazoneDriver, kill_process from amazon.approve import ApproveTask from amazon.match_action import MatchTak from amazon.price_match import PriceTask +from amazon.asin_status import StatusTask +from amazon.detail_spider import SpiderTask from amazon.tool import get_shop_info,show_notification @@ -55,7 +57,9 @@ class TaskMonitor: task_type_info = { "product-risk-resolve-run" : "产品风险审批", "shop-match-run" : "匹配价格", - "price-track-run" : "跟价" + "price-track-run" : "跟价", + "query-asin-run" : "状态查询", + "appearance-patent-run" : "亚马逊采集", } try: while self.running: @@ -122,7 +126,9 @@ class TaskMonitor: TASK_INFO = { "产品风险审批" : ApproveTask, "匹配价格" : MatchTak, - "跟价" : PriceTask + "跟价" : PriceTask, + "状态查询" : StatusTask, + "亚马逊采集" : SpiderTask, } self.log(f"线程 {id(task_data)} 开始处理产品风险审批任务...") # 创建ApproveTask实例并处理任务 diff --git a/app/amazon/match_action.py b/app/amazon/match_action.py index 2a4d3e0..7745f20 100644 --- a/app/amazon/match_action.py +++ b/app/amazon/match_action.py @@ -445,13 +445,13 @@ class MatchTak: import traceback self.log(f"处理国家 {country_code} 失败: {str(e)}", "ERROR") self.log(traceback.format_exc(), "ERROR") - if "与页面的连接已断开" in e: + if "与页面的连接已断开" in str(e): iskill = True # 更新已处理国家数 if task_id in runing_task: runing_task[task_id]["processed_countries"] += 1 - + self.log(f"{task_id}任务处理完成") # 最后回传,标记完成 try: # self.post_result(task_id, shop_name, country_code, "", "", is_done=True) diff --git a/app/amazon/price_match.py b/app/amazon/price_match.py index 73ee741..ebdaa18 100644 --- a/app/amazon/price_match.py +++ b/app/amazon/price_match.py @@ -17,6 +17,97 @@ from amazon.tool import show_notification,get_shop_info,remove_special_character from config import runing_task, runing_shop,base_dir,DELETE_BRAND_API_BASE +class RepricingLogic: + + @staticmethod + def situation_1_general_decrease(my_price, rank1_price, is_first_time=False): + """ + 情况1:常规递减跟价 (最左侧独立长图块) + 当不是自己购物车时,按总价当作第一名递减。 + """ + if is_first_time: + return rank1_price - 0.3 + + diff = abs(my_price - rank1_price) + + # 精简了原图中长串的阶梯逻辑 + if diff <= 0.3: + return rank1_price - 0.5 + elif diff <= 0.8: + return rank1_price - 0.7 + elif diff <= 10.5: + # 0.8 到 10.5 之间,原图逻辑全部是“减1” + return rank1_price - 1.0 + else: + return None # 相差10.5以上,跳过 + + @staticmethod + def situation_2_own_buybox(my_price, rank2_price): + """ + 情况2:已经是自己购物车 + 逻辑:判断与第二名的差价,如果拉开足够差距,则稍微降一点点(减0.5)保持优势,防止卖太便宜。 + """ + diff = abs(rank2_price - my_price) + + # 1. 绝对差价2欧以上 + if diff >= 2.0: + return rank2_price - 0.3 + + # 2. 产品售价区间判定 (是否要提高价格) + if (20 <= my_price < 30 and diff >= 4) or \ + (30 <= my_price < 60 and diff >= 8) or \ + (60 <= my_price <= 150 and diff >= 15): + return rank2_price - 0.3 # 满足区间大差价,提价至第二名之下 + + return my_price # 不满足条件则保持原价 + + @staticmethod + def situation_3_not_own_buybox(my_price, rank1_price): + """ + 情况3:不是自己购物车 (常规情况) + """ + diff = abs(my_price - rank1_price) + + if diff <= 0.3: + return rank1_price - 0.5 + elif 0.5 <= diff <= 0.8: + return rank1_price - 0.7 + elif 0.8 < diff <= 2.5: + return rank1_price - 1.0 + elif diff > 2.5: # 2.5-3.5以上跳过 + return None + + return rank1_price - 0.3 # 默认按第一名减0.3 + + @staticmethod + def situation_4_encounter_amz_us_1st(my_price, amz_us_price): + """ + 情况4:第一名是 Amazon US 卖家 + """ + diff = abs(my_price - amz_us_price) + + if diff <= 3: + return amz_us_price - 2 + elif 4 <= diff <= 6: + return amz_us_price - 3 + elif 8 <= diff <= 12: + return None # 跳过不跟价 + + return amz_us_price - 3 # 默认直接按照 Amazon US 减去3 + + @staticmethod + def situation_5_im_1st_amz_us_2nd(my_price, amz_us_price): + """ + 情况5:自己是第一名,第二名是 Amazon US 卖家 + """ + diff = abs(amz_us_price - my_price) + + if diff <= 7: + return None # 相差5以内跳过 (保持原价) + else: + return amz_us_price - 5 + + def calculate_target_price( front_end_data,current_Price,current_shop_name, recommended_price,recommended_shipping @@ -35,54 +126,44 @@ def calculate_target_price( # --- Step 2: 紫鸟后台特殊判定 (最高优先级) --- if recommended_shipping > 0: - backend_base_price = recommended_price - backend_shipping = recommended_shipping - total_price = backend_base_price + backend_shipping + price_1 = float(front_end_data.get("top_sellers")[0].get("price")) # 实际第一名价格 + return RepricingLogic.situation_1_general_decrease(my_price,price_1,is_my_buybox) + # backend_base_price = recommended_price + # backend_shipping = recommended_shipping + # total_price = backend_base_price + backend_shipping + # + # if is_my_buybox: + # # 🌟【逻辑更新】:如果是自己的购物车,直接跳过,不做任何价格调整 + # return None + # else: + # # 不是自己的购物车:直接将紫鸟的总和作为"第一名"价格,强制抛入阶梯跟价逻辑 + # return calculate_standard_competitor_pricing(my_price, total_price) - if is_my_buybox: - # 🌟【逻辑更新】:如果是自己的购物车,直接跳过,不做任何价格调整 - return None - else: - # 不是自己的购物车:直接将紫鸟的总和作为"第一名"价格,强制抛入阶梯跟价逻辑 - return calculate_standard_competitor_pricing(my_price, total_price) + # # 第一名是自己, 第二名 Amazon US 卖家 的情况 + shop_name_1 = front_end_data.get("top_sellers")[0].get("shop_name") + shop_name_2 = front_end_data.get("top_sellers")[1].get("shop_name") if len(front_end_data.get("top_sellers")) >=2 else "" + if shop_name_1 == current_shop_name and "Amazon" in shop_name_2: + price_2 = float(front_end_data.get("top_sellers")[1].get("price")) # 实际第二名价格 + return RepricingLogic.situation_5_im_1st_amz_us_2nd(my_price,price_2) # --- Step 3: 常规核心分流逻辑 (如果没有紫鸟后台数据) --- # 分支 A:第一名是 Amazon US 卖家 (特殊强敌优先) price_1 = float(front_end_data.get("top_sellers")[0].get("price")) # 实际第一名价格 - if "Amazon." in cart_seller: - diff = abs(my_price - price_1) - if diff <= 5.0 or my_price > price_1: - return price_1 - 5.0 - elif 5.0 < diff <= 8.0: - return price_1 - 3.0 - elif 8.0 < diff <= 12.0: - return None # 跳过,不跟价 + if "Amazon" in shop_name_1: + return RepricingLogic.isituation_4_encounter_amz_us_1st(my_price,price_1) # 分支 B:不是 Amazon US,且目前是自己的购物车 elif is_my_buybox: price_2 = float(front_end_data.get("top_sellers")[1].get("price")) # 实际第二名价格 - diff_with_2nd = price_2 - my_price - if diff_with_2nd >= 2.0: - return price_2 - 0.3 - else: - # 提价区间判定 - if (20 <= my_price <= 30) and diff_with_2nd >= 4: - return price_2 - 0.3 - elif (30 <= my_price <= 60) and diff_with_2nd >= 8: - return price_2 - 0.3 - elif (60 <= my_price <= 150) and diff_with_2nd >= 15: - return price_2 - 0.3 - else: - return None - + return RepricingLogic.situation_2_own_buybox(my_price,price_2) # 分支 C:不是 Amazon US,也不是自己的购物车 else: # 正常情况下的普通跟价,调用阶梯逻辑 - return calculate_standard_competitor_pricing(my_price, price_1) + return RepricingLogic.situation_3_not_own_buybox(my_price, price_1) # ===================================================================== @@ -96,7 +177,7 @@ def calculate_standard_competitor_pricing(my_current_price, target_competitor_pr diff = abs(my_current_price - target_competitor_price) # 根据阶梯执行跟价扣减 - if diff <= 0.3: + if 0 < diff < 0.5: return base_target - 0.5 elif 0.5 <= diff <= 0.8: return base_target - 0.7 @@ -104,10 +185,12 @@ def calculate_standard_competitor_pricing(my_current_price, target_competitor_pr return base_target - 1.0 elif 1.5 <= diff <= 2.5: return base_target - 1.0 - elif diff > 2.5: - return my_current_price # 差距过大,跳过不跟价 - - + elif 2.5 < diff <= 3 : + return None # 差距过大,跳过不跟价 + # elif diff > 3: + # return base_target + else: + return base_target @@ -519,8 +602,8 @@ class AmzonePriceMatch(AmamzonBase): current_country_ele = self.tab.ele('xpath://div[@class="dropdown-account-switcher-header-label"]/span[last()]', timeout=20) current_country = current_country_ele.text.strip() - - while retry_num < 3: # 最多重试3次 + max_retry_num = 5 + while retry_num < max_retry_num: # 最多重试3次 try: if appoint_asin is not None: print(self.mark_name,"指定asin操作",appoint_asin) @@ -536,7 +619,7 @@ class AmzonePriceMatch(AmamzonBase): page_pamel = self.tab.eles('xpath://kat-pagination', timeout=5) if len(page_pamel) > 0: current_page = page_pamel[0].sr('xpath:.//ul[@class="pages"]//li[@aria-current="true"]').text - + # yield (None,{"page":int(current_page.strip())}) # 总页数 total_page = page_pamel[0].sr.eles( 'xpath:.//ul[@class="pages"]//span[@class="page__inner"][last()]') @@ -555,6 +638,14 @@ class AmzonePriceMatch(AmamzonBase): sku_ls = self.tab.eles("xpath://div[@data-sku]", timeout=10) print(f"【{self.mark_name}】获取到 {len(sku_ls)}") + + if len(sku_ls) == 0: + retry_num += 1 + print(f"没有获取到 ASIN 商品,重试{retry_num}/{max_retry_num}") + self.tab.refresh() + self.tab.wait.doc_loaded(raise_err=False, timeout=120) + continue + # for sku_ele in sku_ls[0:2]: for sku_ele in sku_ls: @@ -586,18 +677,16 @@ class AmzonePriceMatch(AmamzonBase): # 如果紫鸟里当前价格低于最低价则删除,否则跳过 if mode == "status" and miniprice_info.get(asin): backend_price = float(miniprice_info.get(asin)) - if float(current_price) < backend_price: + if float(current_price) <= backend_price: + # yield (asin, { + # "statu": "删除(当前价格低于最低价)", + # "deleteSkipAsin": True, + # "removeAsin": asin, + # }) yield (asin, { - "statu": "删除(当前价格低于最低价)", - "deleteSkipAsin": True, - "removeAsin": asin, - }) - continue - else: - yield (asin, { - "statu": "跳过(当前价格不低于最低价)", - "deleteSkipAsin": True, - "removeAsin": asin, + "statu": "跳过(当前价格低于或等于最低价)", + "currentPrice": current_price, + "minimumPrice": bottom_price, # 最低价格 }) continue @@ -626,6 +715,7 @@ class AmzonePriceMatch(AmamzonBase): chrome = ChromeAmzone(tab=new_tab) front_end_data = chrome.run(country=current_country) chrome.close() + self.clear_tab() print(self.mark_name,"亚马逊前台抓取到数据",front_end_data) if front_end_data is None or len(front_end_data.get("top_sellers")) == 0: yield (asin, { @@ -688,8 +778,28 @@ class AmzonePriceMatch(AmamzonBase): "firstPlace": price_1, "secondPlace": price_2, "cartShopName" : cartShopName, + "shippingFee" : f"{shipping_fee}", "priceChangeStatus" : "改价成功", }) + else: + recommendedPrice = recommend_price + shipping_fee + price_1 = float(front_end_data.get("top_sellers")[0].get("price")) if len( + front_end_data.get("top_sellers")) >= 2 else "" # 实际第一名价格 + price_2 = float(front_end_data.get("top_sellers")[1].get("price")) if len( + front_end_data.get("top_sellers")) >= 2 else "" # 实际第二名价格 + cartShopName = front_end_data.get("cart_seller") + yield (asin, { + "statu": "跳过,无需改价", + "currentPrice": current_price, + "recommendedPrice": f"{recommendedPrice}", + "minimumPrice": bottom_price, # 最低价格 + "firstPlace": price_1, + "secondPlace": price_2, + "cartShopName": cartShopName, + "shippingFee": f"{shipping_fee}", + "priceChangeStatus": "跳过,无需改价", + }) + already_asin.add(asin) # 判断是否存在需要翻页的情况 @@ -704,6 +814,7 @@ class AmzonePriceMatch(AmamzonBase): num += 1 print(f"【{self.mark_name}】【程序计算】正在翻页,已翻 {num} 页...") already_asin = set() + retry_num = 0 except Exception as e: print(f"【{self.mark_name}】处理跟价操作异常", e) @@ -924,6 +1035,11 @@ class PriceTask: skip_asins_by_country = shop_item.get("skip_asins_by_country",{}) asin_rows_by_country = shop_item.get("asin_rows_by_country",{}) skip_asin_details_by_country = shop_item.get("skip_asin_details_by_country",{}) + minimum_price_by_country_and_asin = shop_item.get("minimum_price_by_country_and_asin",{}) + if len(minimum_price_by_country_and_asin) > 0: + country_codes = minimum_price_by_country_and_asin.keys() + + # 指定ASIN的情况 mode = shop_item.get("mode") if not company_name: @@ -955,20 +1071,25 @@ class PriceTask: # 检查是否收到暂停请求 if task_id in runing_task and runing_task[task_id].get("stop_requested", False): - self.log(f"检测到任务 {task_id} 的暂停请求,停止处理国家", "WARNING") + self.log(f"检测到任务 {task_id} 的暂停请求,停止处理国家", "ERROR") + driver.close_store() break skip_asin = skip_asins_by_country.get(country_code,[]) #需要跳过的asin appoint_asin = asin_rows_by_country.get(country_code,[]) - miniprice_info = {i.get('asin'):i.get('minimumPrice') for i in skip_asin_details_by_country.get(country_code,[])} + if mode == "status": + miniprice_info = {i.get('asin'):i.get('minimumPrice') for i in skip_asin_details_by_country.get(country_code,[])} + else: + miniprice_info = minimum_price_by_country_and_asin.get(country_code,{}) try: self.process_country(driver, country_code, task_id, shop_name, risk_listing_filter, shopMallName=shopMallName,skip_asin=skip_asin, limit=limit, - appoint_asin=appoint_asin,mode=mode,miniprice_info=miniprice_info) + appoint_asin=appoint_asin,mode=mode,miniprice_info=miniprice_info, + ) except Exception as e: import traceback self.log(f"处理国家 {country_code} 失败: {str(e)}", "ERROR") self.log(traceback.format_exc(), "ERROR") - if "与页面的连接已断开" in e: + if "与页面的连接已断开" in str(e): iskill = True # 更新已处理国家数 if task_id in runing_task: @@ -986,6 +1107,7 @@ class PriceTask: self.post_stage_finished(task_id, user_id, stage_index) except Exception as e: self.log(f"回传结果失败: {str(e)}", "ERROR") + self.log(f"{task_id}任务处理完成") # 从正在执行中的店铺列表中移除 if shop_name in runing_shop: @@ -994,8 +1116,7 @@ class PriceTask: def process_country(self, driver: AmzonePriceMatch, country_code: str, task_id: int, shop_name: str, risk_listing_filter: str,shopMallName:str,skip_asin:list,appoint_asin:list,mode:str, - miniprice_info:dict={}, - limit: str = None): + miniprice_info:dict={}, limit: str = None): """处理单个国家的审批任务 Args: @@ -1113,36 +1234,39 @@ class PriceTask: for i in range(max_range): if len(appoint_asin) > i: _shopMallName = appoint_asin[i]["shopMallName"] - ap_asin = appoint_asin[i]["shopMallName"] + ap_asin = appoint_asin[i]["asin"] else: _shopMallName = shopMallName ap_asin = None + for _ in range(max_retries): + for asin, status in driver.run_page_action( + current_shop_name=_shopMallName, + appoint_asin=ap_asin,skip_asin=skip_asin,mode=mode, + miniprice_info=miniprice_info + ): + if asin is None: + continue + # 检查是否收到暂停请求 + if task_id in runing_task and runing_task[task_id].get("stop_requested", False): + self.log(f"检测到任务 {task_id} 的暂停请求,停止处理ASIN", "WARNING") + break - for asin, status in driver.run_page_action( - current_shop_name=_shopMallName, - appoint_asin=ap_asin,skip_asin=skip_asin,mode=mode, - miniprice_info=miniprice_info - ): - # 检查是否收到暂停请求 - if task_id in runing_task and runing_task[task_id].get("stop_requested", False): - self.log(f"检测到任务 {task_id} 的暂停请求,停止处理ASIN", "WARNING") - break + self.log(f"ASIN {asin} 处理结果: {status}") - self.log(f"ASIN {asin} 处理结果: {status}") + # 更新任务状态 + if task_id in runing_task: + runing_task[task_id]["current_asin"] = asin + runing_task[task_id]["processed_asins"] += 1 - # 更新任务状态 - if task_id in runing_task: - runing_task[task_id]["current_asin"] = asin - runing_task[task_id]["processed_asins"] += 1 + runing_task[task_id]["failed_count"] += 1 - runing_task[task_id]["failed_count"] += 1 - - # 回传结果到API - try: - self.post_result(task_id, shop_name, country_code, asin, status,shopMallName) - except Exception as e: - self.log(f"回传结果失败: {str(e)}", "ERROR") + # 回传结果到API + try: + self.post_result(task_id, shop_name, country_code, asin, status,shopMallName) + except Exception as e: + self.log(f"回传结果失败: {str(e)}", "ERROR") + break self.log(f"国家 {country_name} 处理完成") @@ -1197,18 +1321,6 @@ class PriceTask: """ url = f"{DELETE_BRAND_API_BASE}/api/price-track/tasks/{task_id}/result" - """ - (asin,{ - "statu" : "改价成功", - "currentPrice" : current_price, - "recommendedPrice" : f"{recommendedPrice}", - "minimumPrice" : bottom_price, #最低价格 - "firstPlace": price_1, - "secondPlace": price_2, - "cartShopName" : current_shop_name, - "priceChangeStatus" : "改价成功", - }) - """ payload = { "shops": [ @@ -1229,6 +1341,7 @@ class PriceTask: "deleteSkipAsin": status.get("deleteSkipAsin",False), "removeAsin": status.get("removeAsin") if status.get("removeAsin") else "", # "modifyCount": "2", + "shippingFee" : status.get("shippingFee") if status.get("shippingFee") else "", "status": status.get("statu") } ] @@ -1277,34 +1390,44 @@ class PriceTask: if __name__ == '__main__': # 使用示例 - user_info = { - "company": "rongchuang123", - "username": "自动化_Robot", - "password": "#20zsg25" - } - shop_name = "魏振峰" - country = "德国" - kill_process('v6') - driver = AmzonePriceMatch(user_info) - browser = driver.open_shop(shop_name) - sw_suc = driver.SwitchingCountries(country) - driver.SwitchPage() - risk_listing_filter = "Active" - _shopMallName = "WEIZHENFENG168" - ap_asin ="B0F1N18XFW" - skip_asin = [] - for _ in range(3): - try: - sku_ls = driver.search(filter_type=risk_listing_filter) - break - except Exception as e: - print(e) - driver.tab.refresh() - if len(sku_ls) > 0: - print("有数据,开始操作") - for asin, status in driver.run_page_action( - current_shop_name=_shopMallName, - appoint_asin=ap_asin,skip_asin=skip_asin - ): - print(f"ASIN {asin} 的处理结果: {status}") - print("已完成操作") + # user_info = { + # "company": "尾号5578的公司115", + # "username": "自动化_Robot", + # "password": "#20zsg25" + # } + # shop_name = "刘建煌" + # country = "德国" + # kill_process('v6') + # driver = AmzonePriceMatch(user_info) + # browser = driver.open_shop(shop_name) + # sw_suc = driver.SwitchingCountries(country) + # driver.SwitchPage() + # risk_listing_filter = "Active" + # _shopMallName = "Jianhuang 888" + # ap_asin ="B0BGHRP6BS" + # skip_asin = [] + # for _ in range(3): + # try: + # sku_ls = driver.search(filter_type=risk_listing_filter) + # break + # except Exception as e: + # print(e) + # driver.tab.refresh() + # if len(sku_ls) > 0: + # print("有数据,开始操作") + # for asin, status in driver.run_page_action( + # current_shop_name=_shopMallName, + # appoint_asin=ap_asin,skip_asin=skip_asin,mode="asin" + # ): + # print(f"ASIN {asin} 的处理结果: {status}") + # print("已完成操作") + + front_end_data = {"top_sellers": [{"rank": 1, "price": "36.81", "stock": "5", "shop_name": "Windera"}, {"rank": 2, "price": "36.50", "stock": "100", "shop_name": "Jianhuang 888"}], "cart_seller": "Windera", "timestamp": "2026-04-25 09:32:58"} + current_Price = 36.50 + current_shop_name = "Jianhuang 888" + recommended_price = 36.81 + recommended_shipping = 0 + calculate_target_price( + front_end_data, current_Price, current_shop_name, + recommended_price, recommended_shipping + ) \ No newline at end of file diff --git a/app/assets/convert.js b/app/assets/convert.js index bec17e0..c820697 100644 --- a/app/assets/convert.js +++ b/app/assets/convert.js @@ -1 +1 @@ -import{d as A,o as H,a as l,c as n,b as z,B as K,e as s,F as w,r as F,t as i,f as _,n as P,w as M,u as j,x as q,g as d,h as E,y as J,i as k,E as r,z as L,A as O,C as G,D as Q,_ as W,q as X,s as Y}from"./pywebview-C66x_2Dh.js";import{e as Z}from"./brand-BZije8D7.js";const ee={class:"page-shell module-page"},se={class:"main-content"},te={class:"left-panel"},ae={class:"upload-zone"},le={class:"selected-files clean-placeholder"},ne={key:0,class:"more-line"},oe={key:1},re={class:"option-group"},ie=["value"],ce={class:"template-item-content"},ue={class:"label"},de={key:0,class:"template-tag"},ve={key:1,class:"template-tag muted"},pe={key:2,class:"template-tag custom"},_e={class:"desc"},fe={key:0,class:"empty-option"},me={class:"option-group"},he={class:"radio-item active"},ye={class:"desc"},ge={class:"run-row"},be=["disabled"],we={class:"loading-msg"},ke={class:"right-panel"},Ce={class:"task-list-wrap"},xe={class:"clean-result-summary"},Fe={class:"summary-card"},Ie={class:"summary-card"},Pe={class:"summary-card"},Ee={class:"result-list-wrap"},Te={key:0,class:"empty-tasks"},Be={key:1,class:"task-list clean-result-list"},De={class:"left"},Ne=["title"],Re={key:0,class:"files"},$e={key:1,class:"files"},Se={class:"task-right"},Ue=["onClick"],Ve=["onClick"],Ae=A({__name:"BrandConvertTab",setup(ze){const p=d([]),g=d(""),f=d([]),m=d(!1),b=d([]),h=d({total:0,successCount:0,failedCount:0,items:[]}),v=d([]),u=d(""),C=E(()=>p.value.slice(0,8)),T=E(()=>v.value.find(a=>a.id===u.value)||null);async function I(a){const e=k();if(!e?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传桥接能力");const t=[];for(const o of a){const c=typeof o=="string"?o:o.absolutePath,V=typeof o=="string"?void 0:o.relativePath,y=await e.upload_file_to_java(c,V);if(!y?.success||!y.data)throw new Error(y?.error||y?.message||`上传失败:${c}`);t.push(y.data)}return t}async function B(a){const e=await J();v.value=e||[];const t=v.value.find(c=>c.id===u.value);if(t){u.value=t.id;return}const o=v.value.find(c=>c.isDefault);if(o){u.value=o.id;return}u.value=v.value[0]?.id||""}async function D(a,e){p.value=a,g.value="",f.value=await I(a),r.success(e)}async function N(){const a=k();if(!a?.select_brand_xlsx_files){r.warning("当前环境不支持文件选择,请在本机客户端中打开");return}try{const e=await a.select_brand_xlsx_files();if(!e?.length)return;await D(e,`已选择 ${e.length} 个待转换文件`)}catch(e){r.error(e instanceof Error?e.message:"选择失败")}}async function R(){const a=k();if(!a?.select_brand_folder){r.warning("当前环境不支持文件夹选择,请在本机客户端中打开");return}try{const e=await a.select_brand_folder();if(!e)return;g.value=e.split(/[/\\]/).filter(Boolean).pop()||"";const t=await Z(e);if(t.success&&t.items?.length){p.value=t.items.map(o=>o.relativePath),f.value=await I(t.items),r.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`);return}r.warning(t.error||"该文件夹下没有 xlsx 文件")}catch(e){r.error(e instanceof Error?e.message:"选择失败")}}async function $(){if(!f.value.length){r.warning("请先选择待转换 Excel 文件或文件夹");return}if(!u.value){r.warning("请先选择模板");return}try{m.value=!0;const a=await L({files:f.value.map(e=>({fileKey:e.fileKey,originalFilename:e.originalFilename,relativePath:e.relativePath})),templateId:u.value,archiveName:f.value.some(e=>!!e.relativePath)&&g.value?g.value:void 0});h.value=a,b.value=a.items||[],await x(),r.success("格式转换完成")}catch(a){r.error(a instanceof Error?a.message:"格式转换失败")}finally{m.value=!1}}async function x(){try{const a=await O();b.value=a.items||[],h.value={total:a.items?.length||0,successCount:a.items?.filter(e=>e.success).length||0,failedCount:a.items?.filter(e=>!e.success).length||0,items:a.items||[]}}catch{}}async function S(a){try{await G(a),await x(),r.success("已删除")}catch(e){r.error(e instanceof Error?e.message:"删除失败")}}async function U(a){const e=k(),t=a.downloadUrl||(a.resultId?Q(a.resultId):"");if(!t){r.warning("当前结果没有下载地址");return}const o=a.outputFilename||`${new Date().toISOString().slice(0,10).replace(/-/g,"")}.txt`;if(e?.save_file_from_url_new){const c=await e.save_file_from_url_new(t,o);c.success?r.success(`已保存:${c.path||o}`):c.error&&c.error!=="用户取消"&&r.error(c.error);return}}return H(()=>{B().catch(()=>{}),x().catch(()=>{})}),(a,e)=>(l(),n("div",ee,[z(K,{active:"convert"}),s("div",se,[s("aside",te,[e[5]||(e[5]=s("div",{class:"section-title"},"选择文件",-1)),s("div",ae,[e[1]||(e[1]=s("div",{class:"hint"},"选择需要转换的 Excel 文件或文件夹,将按所选模板生成 txt 文件。",-1)),s("div",{class:"btns"},[s("button",{type:"button",class:"opt-btn",onClick:N},"选择 Excel 文件"),s("button",{type:"button",class:"opt-btn",onClick:R},"选择文件夹")]),s("div",le,[p.value.length?(l(),n(w,{key:0},[(l(!0),n(w,null,F(C.value,t=>(l(),n("span",{key:t},i(t),1))),128)),p.value.length>C.value.length?(l(),n("span",ne," 还有 "+i(p.value.length-C.value.length)+" 个文件未展开显示 ",1)):_("",!0)],64)):(l(),n("span",oe,"暂未选择待转换文件"))])]),e[6]||(e[6]=s("div",{class:"section-title"},"模板选择",-1)),s("div",re,[(l(!0),n(w,null,F(v.value,t=>(l(),n("label",{key:t.id,class:P(["radio-item",{active:u.value===t.id}])},[M(s("input",{"onUpdate:modelValue":e[0]||(e[0]=o=>u.value=o),type:"radio",value:t.id,name:"convert-template"},null,8,ie),[[j,u.value]]),s("div",ce,[s("div",null,[s("span",ue,[q(i(t.templateName)+" ",1),t.isDefault?(l(),n("span",de,"默认")):t.builtIn?(l(),n("span",ve,"内置")):(l(),n("span",pe,"自定义"))]),s("div",_e,"输出文件:"+i(t.outputFilename),1)])])],2))),128)),v.value.length?_("",!0):(l(),n("div",fe,"暂无可用模板"))]),e[7]||(e[7]=s("div",{class:"section-title"},"转换说明",-1)),s("div",me,[s("label",he,[e[3]||(e[3]=s("input",{type:"checkbox",checked:"",disabled:""},null,-1)),s("div",null,[e[2]||(e[2]=s("span",{class:"label"},"按当前模板输出",-1)),s("div",ye,"当前模板:"+i(T.value?.templateName||"未加载模板"),1)])]),e[4]||(e[4]=s("label",{class:"radio-item active"},[s("input",{type:"checkbox",checked:"",disabled:""}),s("div",null,[s("span",{class:"label"},"SKU 使用雪花ID-序号"),s("div",{class:"desc"},"例如 1773816146796-1")])],-1))]),s("div",ge,[s("button",{type:"button",class:"btn-run",disabled:m.value,onClick:$},i(m.value?"转换中...":"开始转换"),9,be),s("span",we,i(m.value?"正在生成并上传结果,请稍候…":"选择文件后即可执行格式转换,结果会显示在右侧供下载"),1)])]),s("section",ke,[e[12]||(e[12]=s("div",{class:"panel-header"},"转换结果",-1)),s("div",Ce,[s("div",xe,[s("div",Fe,[e[8]||(e[8]=s("span",{class:"summary-label"},"已处理文件",-1)),s("strong",null,i(h.value.total),1)]),s("div",Ie,[e[9]||(e[9]=s("span",{class:"summary-label"},"成功结果",-1)),s("strong",null,i(h.value.successCount),1)]),s("div",Pe,[e[10]||(e[10]=s("span",{class:"summary-label"},"失败文件",-1)),s("strong",null,i(h.value.failedCount),1)])]),s("div",Ee,[e[11]||(e[11]=s("div",{class:"result-list-header"},[s("span",null,"生成的结果压缩包列表")],-1)),b.value.length===0?(l(),n("div",Te," 暂无转换结果,完成格式转换后会在这里展示结果压缩包 ")):(l(),n("ul",Be,[(l(!0),n(w,null,F(b.value,t=>(l(),n("li",{key:`${t.resultId||t.outputFilename||t.sourceFilename}`,class:"task-item"},[s("div",De,[s("span",{class:"id",title:t.sourceFilename},i(t.sourceFilename||"-"),9,Ne),t.outputFilename?(l(),n("div",Re,"压缩包文件:"+i(t.outputFilename),1)):_("",!0),t.error?(l(),n("div",$e,"错误信息:"+i(t.error),1)):_("",!0)]),s("div",Se,[s("span",{class:P(["status",t.success?"success":"failed"])},i(t.success?"已完成":"失败"),3),t.success&&(t.downloadUrl||t.resultId)?(l(),n("button",{key:0,type:"button",class:"download",onClick:o=>U(t)}," 下载压缩包 ",8,Ue)):_("",!0),t.resultId?(l(),n("button",{key:1,type:"button",class:"btn-delete",onClick:o=>S(t.resultId)}," 删除 ",8,Ve)):_("",!0)])]))),128))]))])])])])]))}}),He=W(Ae,[["__scopeId","data-v-0e58908e"]]);X(He).use(Y).mount("#app"); +import { d as A, o as H, a as l, c as n, b as z, B as K, e as s, F as w, r as F, t as i, f as _, n as P, w as M, u as j, x as q, g as d, h as E, y as J, i as k, E as r, z as L, A as O, C as G, D as Q, _ as W, q as X, s as Y } from "./pywebview-C66x_2Dh.js"; import { e as Z } from "./brand-BZije8D7.js"; const ee = { class: "page-shell module-page" }, se = { class: "main-content" }, te = { class: "left-panel" }, ae = { class: "upload-zone" }, le = { class: "selected-files clean-placeholder" }, ne = { key: 0, class: "more-line" }, oe = { key: 1 }, re = { class: "option-group" }, ie = ["value"], ce = { class: "template-item-content" }, ue = { class: "label" }, de = { key: 0, class: "template-tag" }, ve = { key: 1, class: "template-tag muted" }, pe = { key: 2, class: "template-tag custom" }, _e = { class: "desc" }, fe = { key: 0, class: "empty-option" }, me = { class: "option-group" }, he = { class: "radio-item active" }, ye = { class: "desc" }, ge = { class: "run-row" }, be = ["disabled"], we = { class: "loading-msg" }, ke = { class: "right-panel" }, Ce = { class: "task-list-wrap" }, xe = { class: "clean-result-summary" }, Fe = { class: "summary-card" }, Ie = { class: "summary-card" }, Pe = { class: "summary-card" }, Ee = { class: "result-list-wrap" }, Te = { key: 0, class: "empty-tasks" }, Be = { key: 1, class: "task-list clean-result-list" }, De = { class: "left" }, Ne = ["title"], Re = { key: 0, class: "files" }, $e = { key: 1, class: "files" }, Se = { class: "task-right" }, Ue = ["onClick"], Ve = ["onClick"], Ae = A({ __name: "BrandConvertTab", setup(ze) { const p = d([]), g = d(""), f = d([]), m = d(!1), b = d([]), h = d({ total: 0, successCount: 0, failedCount: 0, items: [] }), v = d([]), u = d(""), C = E(() => p.value.slice(0, 8)), T = E(() => v.value.find(a => a.id === u.value) || null); async function I(a) { const e = k(); if (!e?.upload_file_to_java) throw new Error("当前桌面端未提供文件上传桥接能力"); const t = []; for (const o of a) { const c = typeof o == "string" ? o : o.absolutePath, V = typeof o == "string" ? void 0 : o.relativePath, y = await e.upload_file_to_java(c, V); if (!y?.success || !y.data) throw new Error(y?.error || y?.message || `上传失败:${c}`); t.push(y.data) } return t } async function B(a) { const e = await J(); v.value = e || []; const t = v.value.find(c => c.id === u.value); if (t) { u.value = t.id; return } const o = v.value.find(c => c.isDefault); if (o) { u.value = o.id; return } u.value = v.value[0]?.id || "" } async function D(a, e) { p.value = a, g.value = "", f.value = await I(a), r.success(e) } async function N() { const a = k(); if (!a?.select_brand_xlsx_files) { r.warning("当前环境不支持文件选择,请在本机客户端中打开"); return } try { const e = await a.select_brand_xlsx_files(); if (!e?.length) return; await D(e, `已选择 ${e.length} 个待转换文件`) } catch (e) { r.error(e instanceof Error ? e.message : "选择失败") } } async function R() { const a = k(); if (!a?.select_brand_folder) { r.warning("当前环境不支持文件夹选择,请在本机客户端中打开"); return } try { const e = await a.select_brand_folder(); if (!e) return; g.value = e.split(/[/\\]/).filter(Boolean).pop() || ""; const t = await Z(e); if (t.success && t.items?.length) { p.value = t.items.map(o => o.relativePath), f.value = await I(t.items), r.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`); return } r.warning(t.error || "该文件夹下没有 xlsx 文件") } catch (e) { r.error(e instanceof Error ? e.message : "选择失败") } } async function $() { if (!f.value.length) { r.warning("请先选择待转换 Excel 文件或文件夹"); return } if (!u.value) { r.warning("请先选择模板"); return } try { m.value = !0; const a = await L({ files: f.value.map(e => ({ fileKey: e.fileKey, originalFilename: e.originalFilename, relativePath: e.relativePath })), templateId: u.value, archiveName: f.value.some(e => !!e.relativePath) && g.value ? g.value : void 0 }); h.value = a, b.value = a.items || [], await x(), r.success("格式转换完成") } catch (a) { r.error(a instanceof Error ? a.message : "格式转换失败") } finally { m.value = !1 } } async function x() { try { const a = await O(); b.value = a.items || [], h.value = { total: a.items?.length || 0, successCount: a.items?.filter(e => e.success).length || 0, failedCount: a.items?.filter(e => !e.success).length || 0, items: a.items || [] } } catch { } } async function S(a) { try { await G(a), await x(), r.success("已删除") } catch (e) { r.error(e instanceof Error ? e.message : "删除失败") } } async function U(a) { const e = k(), t = a.downloadUrl || (a.resultId ? Q(a.resultId) : ""); if (!t) { r.warning("当前结果没有下载地址"); return } const o = a.outputFilename || `${new Date().toISOString().slice(0, 10).replace(/-/g, "")}.txt`; if (e?.save_file_from_url_new) { const c = await e.save_file_from_url_new(t, o); c.success ? r.success(`已保存:${c.path || o}`) : c.error && c.error !== "用户取消" && r.error(c.error); return } } return H(() => { B().catch(() => { }), x().catch(() => { }) }), (a, e) => (l(), n("div", ee, [z(K, { active: "convert" }), s("div", se, [s("aside", te, [e[5] || (e[5] = s("div", { class: "section-title" }, "选择文件", -1)), s("div", ae, [e[1] || (e[1] = s("div", { class: "hint" }, "选择需要转换的 Excel 文件或文件夹,将按所选模板生成 txt 文件。", -1)), s("div", { class: "btns" }, [s("button", { type: "button", class: "opt-btn", onClick: N }, "选择 Excel 文件"), s("button", { type: "button", class: "opt-btn", onClick: R }, "选择文件夹")]), s("div", le, [p.value.length ? (l(), n(w, { key: 0 }, [(l(!0), n(w, null, F(C.value, t => (l(), n("span", { key: t }, i(t), 1))), 128)), p.value.length > C.value.length ? (l(), n("span", ne, " 还有 " + i(p.value.length - C.value.length) + " 个文件未展开显示 ", 1)) : _("", !0)], 64)) : (l(), n("span", oe, "暂未选择待转换文件"))])]), e[6] || (e[6] = s("div", { class: "section-title" }, "模板选择", -1)), s("div", re, [(l(!0), n(w, null, F(v.value, t => (l(), n("label", { key: t.id, class: P(["radio-item", { active: u.value === t.id }]) }, [M(s("input", { "onUpdate:modelValue": e[0] || (e[0] = o => u.value = o), type: "radio", value: t.id, name: "convert-template" }, null, 8, ie), [[j, u.value]]), s("div", ce, [s("div", null, [s("span", ue, [q(i(t.templateName) + " ", 1), t.isDefault ? (l(), n("span", de, "默认")) : t.builtIn ? (l(), n("span", ve, "内置")) : (l(), n("span", pe, "自定义"))]), s("div", _e, "输出文件:" + i(t.outputFilename), 1)])])], 2))), 128)), v.value.length ? _("", !0) : (l(), n("div", fe, "暂无可用模板"))]), e[7] || (e[7] = s("div", { class: "section-title" }, "转换说明", -1)), s("div", me, [s("label", he, [e[3] || (e[3] = s("input", { type: "checkbox", checked: "", disabled: "" }, null, -1)), s("div", null, [e[2] || (e[2] = s("span", { class: "label" }, "按当前模板输出", -1)), s("div", ye, "当前模板:" + i(T.value?.templateName || "未加载模板"), 1)])]), e[4] || (e[4] = s("label", { class: "radio-item active" }, [s("input", { type: "checkbox", checked: "", disabled: "" }), s("div", null, [s("span", { class: "label" }, "SKU 使用雪花ID-序号"), s("div", { class: "desc" }, "例如 1773816146796-1")])], -1))]), s("div", ge, [s("button", { type: "button", class: "btn-run", disabled: m.value, onClick: $ }, i(m.value ? "转换中..." : "开始转换"), 9, be), s("span", we, i(m.value ? "正在生成并上传结果,请稍候…" : "选择文件后即可执行格式转换,结果会显示在右侧供下载"), 1)])]), s("section", ke, [e[12] || (e[12] = s("div", { class: "panel-header" }, "转换结果", -1)), s("div", Ce, [s("div", xe, [s("div", Fe, [e[8] || (e[8] = s("span", { class: "summary-label" }, "已处理文件", -1)), s("strong", null, i(h.value.total), 1)]), s("div", Ie, [e[9] || (e[9] = s("span", { class: "summary-label" }, "成功结果", -1)), s("strong", null, i(h.value.successCount), 1)]), s("div", Pe, [e[10] || (e[10] = s("span", { class: "summary-label" }, "失败文件", -1)), s("strong", null, i(h.value.failedCount), 1)])]), s("div", Ee, [e[11] || (e[11] = s("div", { class: "result-list-header" }, [s("span", null, "生成的结果压缩包列表")], -1)), b.value.length === 0 ? (l(), n("div", Te, " 暂无转换结果,完成格式转换后会在这里展示结果压缩包 ")) : (l(), n("ul", Be, [(l(!0), n(w, null, F(b.value, t => (l(), n("li", { key: `${t.resultId || t.outputFilename || t.sourceFilename}`, class: "task-item" }, [s("div", De, [s("span", { class: "id", title: t.sourceFilename }, i(t.sourceFilename || "-"), 9, Ne), t.outputFilename ? (l(), n("div", Re, "压缩包文件:" + i(t.outputFilename), 1)) : _("", !0), t.error ? (l(), n("div", $e, "错误信息:" + i(t.error), 1)) : _("", !0)]), s("div", Se, [s("span", { class: P(["status", t.success ? "success" : "failed"]) }, i(t.success ? "已完成" : "失败"), 3), t.success && (t.downloadUrl || t.resultId) ? (l(), n("button", { key: 0, type: "button", class: "download", onClick: o => U(t) }, " 下载压缩包 ", 8, Ue)) : _("", !0), t.resultId ? (l(), n("button", { key: 1, type: "button", class: "btn-delete", onClick: o => S(t.resultId) }, " 删除 ", 8, Ve)) : _("", !0)])]))), 128))]))])])])])])) } }), He = W(Ae, [["__scopeId", "data-v-0e58908e"]]); X(He).use(Y).mount("#app"); diff --git a/app/assets/dedupe.js b/app/assets/dedupe.js index 4aebb8b..92667fd 100644 --- a/app/assets/dedupe.js +++ b/app/assets/dedupe.js @@ -1 +1 @@ -import{d as z,o as W,a,c as n,b as q,B as J,e as s,F as C,r as F,t as u,f as b,n as I,w as P,v as B,g as c,h as L,i as x,E as o,j as O,k as G,l as Q,m as X,p as Y,_ as Z,q as ee,s as se}from"./pywebview-C66x_2Dh.js";import{e as te}from"./brand-BZije8D7.js";const le={class:"page-shell module-page"},ae={class:"main-content"},ne={class:"left-panel"},oe={class:"upload-zone"},re={class:"selected-files clean-placeholder"},ie={key:0,class:"more-line"},ue={key:1},ce={class:"option-group column-option-group"},de={class:"column-toolbar"},ve={class:"column-count"},pe={key:0,class:"column-grid"},fe=["value"],_e={key:1,class:"empty-column-state"},me={class:"option-group"},he={class:"run-row"},ge=["disabled"],ye={class:"loading-msg"},be={class:"right-panel"},we={class:"task-list-wrap"},ke={class:"clean-result-summary"},Ce={class:"summary-card"},Ie={class:"summary-card"},xe={class:"summary-card"},De={class:"result-list-wrap"},Ee={key:0,class:"empty-tasks"},Fe={key:1,class:"task-list clean-result-list"},Pe={class:"left"},Be=["title"],Se={key:0,class:"files"},Ue={key:1,class:"files"},Ne={class:"task-right"},$e=["onClick"],Ae=["onClick"],He=z({__name:"BrandDedupeTab",setup(Re){const p=c([]),d=c([]),f=c([]),w=c(""),v=c([]),S=c(!1),_=c(!0),m=c(!0),h=c(!1),k=c([]),g=c({total:0,successCount:0,failedCount:0,items:[]}),D=L(()=>f.value.slice(0,8));function $(){d.value=[...p.value]}function A(){d.value=[]}async function U(l){const e=x();if(!e?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传桥接能力");const t=[];for(const r of l){const i=typeof r=="string"?r:r.absolutePath,j=typeof r=="string"?void 0:r.relativePath,y=await e.upload_file_to_java(i,j);if(!y?.success||!y.data)throw new Error(y?.error||y?.message||`上传失败:${i}`);t.push(y.data)}return t}async function N(l){const e=await Y(l);if(!e.headers?.length){o.error("读取 Excel 表头失败"),p.value=[],d.value=[];return}const t=["id","ASIN","国家","价格","卖家名称"],r=[...t.filter(i=>e.headers?.includes(i)),...(e.headers||[]).filter(i=>!t.includes(i))];p.value=r,d.value=t.filter(i=>r.includes(i))}async function H(l,e){f.value=l,w.value="",v.value=await U(l),v.value.length>0&&await N(v.value[0].fileKey),o.success(e)}async function K(){const l=x();if(!l?.select_brand_xlsx_files){o.warning("当前环境不支持文件选择,请在本机客户端中打开");return}try{const e=await l.select_brand_xlsx_files();if(!e?.length)return;await H(e,`已选择 ${e.length} 个待清洗文件`)}catch(e){o.error(e instanceof Error?e.message:"选择失败")}}async function R(){const l=x();if(!l?.select_brand_folder){o.warning("当前环境不支持文件夹选择,请在本机客户端中打开");return}try{const e=await l.select_brand_folder();if(!e)return;w.value=e.split(/[/\\]/).filter(Boolean).pop()||"";const t=await te(e);if(t.success&&t.items?.length){f.value=t.items.map(r=>r.relativePath),v.value=await U(t.items),v.value.length>0&&await N(v.value[0].fileKey),o.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`);return}o.warning(t.error||"该文件夹下没有 xlsx 文件")}catch(e){o.error(e instanceof Error?e.message:"选择失败")}}async function V(){if(!v.value.length){o.warning("请先选择待清洗 Excel 文件或文件夹");return}if(!d.value.length){o.warning("请至少选择一列保留列");return}if(!S.value&&!_.value&&!m.value){o.warning("请至少选择一种 ID 保留规则");return}try{h.value=!0;const l=await O({files:v.value.map(e=>({fileKey:e.fileKey,originalFilename:e.originalFilename,relativePath:e.relativePath})),selectedColumns:d.value,keepIntegerIds:S.value,keepUnderscoreIds:_.value,keepIntegerMainIdsWhenNoSubIds:m.value,archiveName:v.value.some(e=>!!e.relativePath)&&w.value?w.value:void 0});g.value=l,k.value=l.items||[],await E(),o.success("数据去重完成")}catch(l){o.error(l instanceof Error?l.message:"去重失败")}finally{h.value=!1}}async function E(){try{const l=await G();k.value=l.items||[],g.value={total:l.items?.length||0,successCount:l.items?.filter(e=>e.success).length||0,failedCount:l.items?.filter(e=>!e.success).length||0,items:l.items||[]}}catch{}}async function M(l){try{await Q(l),await E(),o.success("已删除")}catch(e){o.error(e instanceof Error?e.message:"删除失败")}}async function T(l){const e=x(),t=l.downloadUrl||(l.resultId?X(l.resultId):"");if(!t){o.warning("当前结果没有下载地址");return}const r=l.outputFilename||`${new Date().toISOString().slice(0,10).replace(/-/g,"")}_cleaned.xlsx`;if(e?.save_file_from_url_new){const i=await e.save_file_from_url_new(t,r);i.success?o.success(`已保存:${i.path||r}`):i.error&&i.error!=="用户取消"&&o.error(i.error);return}}return W(()=>{E().catch(()=>{})}),(l,e)=>(a(),n("div",le,[q(J,{active:"dedupe"}),s("div",ae,[s("aside",ne,[e[7]||(e[7]=s("div",{class:"section-title"},"选择文件",-1)),s("div",oe,[e[3]||(e[3]=s("div",{class:"hint"},"选择需要清洗的 Excel 文件或文件夹,后续将按所选规则输出处理结果。",-1)),s("div",{class:"btns"},[s("button",{type:"button",class:"opt-btn",onClick:K},"选择 Excel 文件"),s("button",{type:"button",class:"opt-btn",onClick:R},"选择文件夹")]),s("div",re,[f.value.length?(a(),n(C,{key:0},[(a(!0),n(C,null,F(D.value,t=>(a(),n("span",{key:t},u(t),1))),128)),f.value.length>D.value.length?(a(),n("span",ie," 还有 "+u(f.value.length-D.value.length)+" 个文件未展开显示 ",1)):b("",!0)],64)):(a(),n("span",ue,"暂未选择待清洗文件"))])]),e[8]||(e[8]=s("div",{class:"section-title"},"保留列设置",-1)),s("div",ce,[s("div",de,[s("span",ve,"已选择 "+u(d.value.length)+" / "+u(p.value.length)+" 列",1),s("div",{class:"column-actions"},[s("button",{type:"button",class:"opt-btn small",onClick:$},"全选"),s("button",{type:"button",class:"opt-btn small",onClick:A},"清空")])]),p.value.length?(a(),n("div",pe,[(a(!0),n(C,null,F(p.value,t=>(a(),n("label",{key:t,class:I(["column-item",{active:d.value.includes(t)}])},[P(s("input",{"onUpdate:modelValue":e[0]||(e[0]=r=>d.value=r),type:"checkbox",value:t},null,8,fe),[[B,d.value]]),s("span",null,u(t),1)],2))),128))])):(a(),n("div",_e,"请选择 Excel 文件后读取表头并填充可保留列")),e[4]||(e[4]=s("div",{class:"desc"},"读取首个 Excel 文件的第一行作为表头,用于动态选择需要保留的列。",-1))]),e[9]||(e[9]=s("div",{class:"section-title"},"ID 保留规则",-1)),s("div",me,[s("label",{class:I(["radio-item",{active:_.value}])},[P(s("input",{"onUpdate:modelValue":e[1]||(e[1]=t=>_.value=t),type:"checkbox"},null,512),[[B,_.value]]),e[5]||(e[5]=s("div",null,[s("span",{class:"label"},"保留子链接"),s("div",{class:"desc"},"例如 1_1、2_3 这种带下划线的子项 ID")],-1))],2),s("label",{class:I(["radio-item",{active:m.value}])},[P(s("input",{"onUpdate:modelValue":e[2]||(e[2]=t=>m.value=t),type:"checkbox"},null,512),[[B,m.value]]),e[6]||(e[6]=s("div",null,[s("span",{class:"label"},"仅剩主链接无子链接"),s("div",{class:"desc"},"当某个主链接只有 13 这类主 ID、没有 13_1 这类对应子 ID 时,自动保留该主 ID")],-1))],2)]),s("div",he,[s("button",{type:"button",class:"btn-run",disabled:h.value,onClick:V},u(h.value?"清洗中...":"开始清洗"),9,ge),s("span",ye,u(h.value?"正在处理文件并上传结果,请稍候…":"选择文件、列和 ID 规则后即可执行清洗,结果会显示在右侧供下载"),1)])]),s("section",be,[e[14]||(e[14]=s("div",{class:"panel-header"},"去重结果",-1)),s("div",we,[s("div",ke,[s("div",Ce,[e[10]||(e[10]=s("span",{class:"summary-label"},"已处理文件",-1)),s("strong",null,u(g.value.total),1)]),s("div",Ie,[e[11]||(e[11]=s("span",{class:"summary-label"},"成功结果",-1)),s("strong",null,u(g.value.successCount),1)]),s("div",xe,[e[12]||(e[12]=s("span",{class:"summary-label"},"失败文件",-1)),s("strong",null,u(g.value.failedCount),1)])]),s("div",De,[e[13]||(e[13]=s("div",{class:"result-list-header"},[s("span",null,"处理后的 Excel 列表")],-1)),k.value.length===0?(a(),n("div",Ee," 暂无去重结果,完成数据去重后会在这里展示输出文件 ")):(a(),n("ul",Fe,[(a(!0),n(C,null,F(k.value,t=>(a(),n("li",{key:`${t.resultId||t.outputFilename||t.sourceFilename}`,class:"task-item"},[s("div",Pe,[s("span",{class:"id",title:t.sourceFilename},u(t.sourceFilename||"-"),9,Be),t.outputFilename?(a(),n("div",Se,"输出文件:"+u(t.outputFilename),1)):b("",!0),t.error?(a(),n("div",Ue,"错误信息:"+u(t.error),1)):b("",!0)]),s("div",Ne,[s("span",{class:I(["status",t.success?"success":"failed"])},u(t.success?"已完成":"失败"),3),t.success&&(t.downloadUrl||t.resultId)?(a(),n("button",{key:0,type:"button",class:"download",onClick:r=>T(t)}," 下载文件 ",8,$e)):b("",!0),t.resultId?(a(),n("button",{key:1,type:"button",class:"btn-delete",onClick:r=>M(t.resultId)}," 删除 ",8,Ae)):b("",!0)])]))),128))]))])])])])]))}}),Ke=Z(He,[["__scopeId","data-v-c7e8afd4"]]);ee(Ke).use(se).mount("#app"); +import { d as z, o as W, a, c as n, b as q, B as J, e as s, F as C, r as F, t as u, f as b, n as I, w as P, v as B, g as c, h as L, i as x, E as o, j as O, k as G, l as Q, m as X, p as Y, _ as Z, q as ee, s as se } from "./pywebview-C66x_2Dh.js"; import { e as te } from "./brand-BZije8D7.js"; const le = { class: "page-shell module-page" }, ae = { class: "main-content" }, ne = { class: "left-panel" }, oe = { class: "upload-zone" }, re = { class: "selected-files clean-placeholder" }, ie = { key: 0, class: "more-line" }, ue = { key: 1 }, ce = { class: "option-group column-option-group" }, de = { class: "column-toolbar" }, ve = { class: "column-count" }, pe = { key: 0, class: "column-grid" }, fe = ["value"], _e = { key: 1, class: "empty-column-state" }, me = { class: "option-group" }, he = { class: "run-row" }, ge = ["disabled"], ye = { class: "loading-msg" }, be = { class: "right-panel" }, we = { class: "task-list-wrap" }, ke = { class: "clean-result-summary" }, Ce = { class: "summary-card" }, Ie = { class: "summary-card" }, xe = { class: "summary-card" }, De = { class: "result-list-wrap" }, Ee = { key: 0, class: "empty-tasks" }, Fe = { key: 1, class: "task-list clean-result-list" }, Pe = { class: "left" }, Be = ["title"], Se = { key: 0, class: "files" }, Ue = { key: 1, class: "files" }, Ne = { class: "task-right" }, $e = ["onClick"], Ae = ["onClick"], He = z({ __name: "BrandDedupeTab", setup(Re) { const p = c([]), d = c([]), f = c([]), w = c(""), v = c([]), S = c(!1), _ = c(!0), m = c(!0), h = c(!1), k = c([]), g = c({ total: 0, successCount: 0, failedCount: 0, items: [] }), D = L(() => f.value.slice(0, 8)); function $() { d.value = [...p.value] } function A() { d.value = [] } async function U(l) { const e = x(); if (!e?.upload_file_to_java) throw new Error("当前桌面端未提供文件上传桥接能力"); const t = []; for (const r of l) { const i = typeof r == "string" ? r : r.absolutePath, j = typeof r == "string" ? void 0 : r.relativePath, y = await e.upload_file_to_java(i, j); if (!y?.success || !y.data) throw new Error(y?.error || y?.message || `上传失败:${i}`); t.push(y.data) } return t } async function N(l) { const e = await Y(l); if (!e.headers?.length) { o.error("读取 Excel 表头失败"), p.value = [], d.value = []; return } const t = ["id", "ASIN", "国家", "价格", "卖家名称"], r = [...t.filter(i => e.headers?.includes(i)), ...(e.headers || []).filter(i => !t.includes(i))]; p.value = r, d.value = t.filter(i => r.includes(i)) } async function H(l, e) { f.value = l, w.value = "", v.value = await U(l), v.value.length > 0 && await N(v.value[0].fileKey), o.success(e) } async function K() { const l = x(); if (!l?.select_brand_xlsx_files) { o.warning("当前环境不支持文件选择,请在本机客户端中打开"); return } try { const e = await l.select_brand_xlsx_files(); if (!e?.length) return; await H(e, `已选择 ${e.length} 个待清洗文件`) } catch (e) { o.error(e instanceof Error ? e.message : "选择失败") } } async function R() { const l = x(); if (!l?.select_brand_folder) { o.warning("当前环境不支持文件夹选择,请在本机客户端中打开"); return } try { const e = await l.select_brand_folder(); if (!e) return; w.value = e.split(/[/\\]/).filter(Boolean).pop() || ""; const t = await te(e); if (t.success && t.items?.length) { f.value = t.items.map(r => r.relativePath), v.value = await U(t.items), v.value.length > 0 && await N(v.value[0].fileKey), o.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`); return } o.warning(t.error || "该文件夹下没有 xlsx 文件") } catch (e) { o.error(e instanceof Error ? e.message : "选择失败") } } async function V() { if (!v.value.length) { o.warning("请先选择待清洗 Excel 文件或文件夹"); return } if (!d.value.length) { o.warning("请至少选择一列保留列"); return } if (!S.value && !_.value && !m.value) { o.warning("请至少选择一种 ID 保留规则"); return } try { h.value = !0; const l = await O({ files: v.value.map(e => ({ fileKey: e.fileKey, originalFilename: e.originalFilename, relativePath: e.relativePath })), selectedColumns: d.value, keepIntegerIds: S.value, keepUnderscoreIds: _.value, keepIntegerMainIdsWhenNoSubIds: m.value, archiveName: v.value.some(e => !!e.relativePath) && w.value ? w.value : void 0 }); g.value = l, k.value = l.items || [], await E(), o.success("数据去重完成") } catch (l) { o.error(l instanceof Error ? l.message : "去重失败") } finally { h.value = !1 } } async function E() { try { const l = await G(); k.value = l.items || [], g.value = { total: l.items?.length || 0, successCount: l.items?.filter(e => e.success).length || 0, failedCount: l.items?.filter(e => !e.success).length || 0, items: l.items || [] } } catch { } } async function M(l) { try { await Q(l), await E(), o.success("已删除") } catch (e) { o.error(e instanceof Error ? e.message : "删除失败") } } async function T(l) { const e = x(), t = l.downloadUrl || (l.resultId ? X(l.resultId) : ""); if (!t) { o.warning("当前结果没有下载地址"); return } const r = l.outputFilename || `${new Date().toISOString().slice(0, 10).replace(/-/g, "")}_cleaned.xlsx`; if (e?.save_file_from_url_new) { const i = await e.save_file_from_url_new(t, r); i.success ? o.success(`已保存:${i.path || r}`) : i.error && i.error !== "用户取消" && o.error(i.error); return } } return W(() => { E().catch(() => { }) }), (l, e) => (a(), n("div", le, [q(J, { active: "dedupe" }), s("div", ae, [s("aside", ne, [e[7] || (e[7] = s("div", { class: "section-title" }, "选择文件", -1)), s("div", oe, [e[3] || (e[3] = s("div", { class: "hint" }, "选择需要清洗的 Excel 文件或文件夹,后续将按所选规则输出处理结果。", -1)), s("div", { class: "btns" }, [s("button", { type: "button", class: "opt-btn", onClick: K }, "选择 Excel 文件"), s("button", { type: "button", class: "opt-btn", onClick: R }, "选择文件夹")]), s("div", re, [f.value.length ? (a(), n(C, { key: 0 }, [(a(!0), n(C, null, F(D.value, t => (a(), n("span", { key: t }, u(t), 1))), 128)), f.value.length > D.value.length ? (a(), n("span", ie, " 还有 " + u(f.value.length - D.value.length) + " 个文件未展开显示 ", 1)) : b("", !0)], 64)) : (a(), n("span", ue, "暂未选择待清洗文件"))])]), e[8] || (e[8] = s("div", { class: "section-title" }, "保留列设置", -1)), s("div", ce, [s("div", de, [s("span", ve, "已选择 " + u(d.value.length) + " / " + u(p.value.length) + " 列", 1), s("div", { class: "column-actions" }, [s("button", { type: "button", class: "opt-btn small", onClick: $ }, "全选"), s("button", { type: "button", class: "opt-btn small", onClick: A }, "清空")])]), p.value.length ? (a(), n("div", pe, [(a(!0), n(C, null, F(p.value, t => (a(), n("label", { key: t, class: I(["column-item", { active: d.value.includes(t) }]) }, [P(s("input", { "onUpdate:modelValue": e[0] || (e[0] = r => d.value = r), type: "checkbox", value: t }, null, 8, fe), [[B, d.value]]), s("span", null, u(t), 1)], 2))), 128))])) : (a(), n("div", _e, "请选择 Excel 文件后读取表头并填充可保留列")), e[4] || (e[4] = s("div", { class: "desc" }, "读取首个 Excel 文件的第一行作为表头,用于动态选择需要保留的列。", -1))]), e[9] || (e[9] = s("div", { class: "section-title" }, "ID 保留规则", -1)), s("div", me, [s("label", { class: I(["radio-item", { active: _.value }]) }, [P(s("input", { "onUpdate:modelValue": e[1] || (e[1] = t => _.value = t), type: "checkbox" }, null, 512), [[B, _.value]]), e[5] || (e[5] = s("div", null, [s("span", { class: "label" }, "保留子链接"), s("div", { class: "desc" }, "例如 1_1、2_3 这种带下划线的子项 ID")], -1))], 2), s("label", { class: I(["radio-item", { active: m.value }]) }, [P(s("input", { "onUpdate:modelValue": e[2] || (e[2] = t => m.value = t), type: "checkbox" }, null, 512), [[B, m.value]]), e[6] || (e[6] = s("div", null, [s("span", { class: "label" }, "仅剩主链接无子链接"), s("div", { class: "desc" }, "当某个主链接只有 13 这类主 ID、没有 13_1 这类对应子 ID 时,自动保留该主 ID")], -1))], 2)]), s("div", he, [s("button", { type: "button", class: "btn-run", disabled: h.value, onClick: V }, u(h.value ? "清洗中..." : "开始清洗"), 9, ge), s("span", ye, u(h.value ? "正在处理文件并上传结果,请稍候…" : "选择文件、列和 ID 规则后即可执行清洗,结果会显示在右侧供下载"), 1)])]), s("section", be, [e[14] || (e[14] = s("div", { class: "panel-header" }, "去重结果", -1)), s("div", we, [s("div", ke, [s("div", Ce, [e[10] || (e[10] = s("span", { class: "summary-label" }, "已处理文件", -1)), s("strong", null, u(g.value.total), 1)]), s("div", Ie, [e[11] || (e[11] = s("span", { class: "summary-label" }, "成功结果", -1)), s("strong", null, u(g.value.successCount), 1)]), s("div", xe, [e[12] || (e[12] = s("span", { class: "summary-label" }, "失败文件", -1)), s("strong", null, u(g.value.failedCount), 1)])]), s("div", De, [e[13] || (e[13] = s("div", { class: "result-list-header" }, [s("span", null, "处理后的 Excel 列表")], -1)), k.value.length === 0 ? (a(), n("div", Ee, " 暂无去重结果,完成数据去重后会在这里展示输出文件 ")) : (a(), n("ul", Fe, [(a(!0), n(C, null, F(k.value, t => (a(), n("li", { key: `${t.resultId || t.outputFilename || t.sourceFilename}`, class: "task-item" }, [s("div", Pe, [s("span", { class: "id", title: t.sourceFilename }, u(t.sourceFilename || "-"), 9, Be), t.outputFilename ? (a(), n("div", Se, "输出文件:" + u(t.outputFilename), 1)) : b("", !0), t.error ? (a(), n("div", Ue, "错误信息:" + u(t.error), 1)) : b("", !0)]), s("div", Ne, [s("span", { class: I(["status", t.success ? "success" : "failed"]) }, u(t.success ? "已完成" : "失败"), 3), t.success && (t.downloadUrl || t.resultId) ? (a(), n("button", { key: 0, type: "button", class: "download", onClick: r => T(t) }, " 下载文件 ", 8, $e)) : b("", !0), t.resultId ? (a(), n("button", { key: 1, type: "button", class: "btn-delete", onClick: r => M(t.resultId) }, " 删除 ", 8, Ae)) : b("", !0)])]))), 128))]))])])])])])) } }), Ke = Z(He, [["__scopeId", "data-v-c7e8afd4"]]); ee(Ke).use(se).mount("#app"); diff --git a/app/assets/delete-brand.js b/app/assets/delete-brand.js index d0ceee6..63783c6 100644 --- a/app/assets/delete-brand.js +++ b/app/assets/delete-brand.js @@ -1 +1,5 @@ +<<<<<<< HEAD import{d as Ye,o as Ze,L as es,a as d,c as f,b as ss,B as ts,e as r,F as H,r as fe,t as v,f as h,M as as,N as De,n as Me,g as y,h as G,O as ns,i as J,E as p,P as ls,Q as rs,R as os,S as us,T as is,_ as cs,q as ds,s as fs}from"./pywebview-C66x_2Dh.js";import{e as vs}from"./brand-BZije8D7.js";const hs={class:"page-shell module-page"},ps={class:"main-content"},_s={class:"left-panel"},ys={class:"upload-zone"},gs={class:"selected-files clean-placeholder split-selected-files"},ms={key:0,class:"more-line"},ks={key:1},ws={class:"run-row"},Is=["disabled"],bs=["disabled"],Ss={class:"loading-msg"},Ts={key:0,class:"queue-debug-card"},Es={key:0,class:"queue-debug-line"},Cs={key:1,class:"queue-debug-payload"},Fs={class:"right-panel"},Rs={class:"task-list-wrap"},Ns={class:"clean-result-summary"},Ps={class:"summary-card"},xs={class:"summary-card"},$s={class:"summary-card"},As={class:"result-list-wrap"},Ds={key:0,class:"empty-tasks"},Ms={key:0,class:"result-subsection"},Ls={class:"task-list clean-result-list"},Bs={class:"left split-result-main"},qs=["title"],Us={class:"files"},Os={class:"files"},Ks={key:0,class:"files"},Hs={key:1,class:"files"},Gs={key:2,class:"files"},Js={key:3,class:"time"},js={key:4,class:"delete-brand-progress-block"},zs={class:"delete-brand-progress-header"},Vs={class:"delete-brand-progress-bar"},Xs={class:"files delete-brand-progress"},Qs={key:5,class:"files split-entry-list delete-brand-preview"},Ws={key:6,class:"files"},Ys={class:"task-right split-result-actions"},Zs=["onClick"],et=["onClick"],st={key:1,class:"result-subsection"},tt={class:"task-list clean-result-list"},at={class:"left split-result-main"},nt=["title"],lt={class:"files"},rt={class:"files"},ot={key:0,class:"files"},ut={key:1,class:"files"},it={key:2,class:"time"},ct={key:3,class:"delete-brand-progress-block"},dt={class:"delete-brand-progress-header"},ft={class:"delete-brand-progress-bar"},vt={class:"files delete-brand-progress"},ht={key:4,class:"files split-entry-list delete-brand-preview"},pt={key:5,class:"files"},_t={class:"task-right split-result-actions"},yt=["onClick"],gt=["onClick"],mt=Ye({__name:"BrandDeleteBrandTab",setup(wt){function $(){return`delete-brand:current-tasks:${typeof window<"u"&&window.localStorage.getItem("uid")||"0"}`}const A=y([]),j=y([]),L=y(!1),ve=y([]),i=y([]),B=y([]),z=y({total:0,successCount:0,failedCount:0,items:[]}),b=y(""),S=y(""),m=y({}),T=y(null),ee=y(!1),V=y(!1),C=y(!1),D=y(""),X=y(!1),q=y(null),se=y(!1),te=G(()=>A.value.slice(0,10)),F=G(()=>{const e=[];return i.value.forEach(s=>{e.push(...s.items)}),e});function Le(){try{const e=typeof window<"u"?window.localStorage.getItem($()):null;if(e){if(i.value=JSON.parse(e),i.value.length>0){const s=i.value[i.value.length-1];b.value=s.queuePushResult||"",S.value=s.queuePayloadText||""}}else i.value=[]}catch{i.value=[]}}function ae(e,s,t,a){if(!s?.length)return;const l=i.value.findIndex(c=>c.taskId===e),n=l>=0?i.value[l]:null,o=s.map(c=>{const _=n?.items.find(We=>M(We,c)),k=Array.isArray(c.countries)?c.countries:void 0,g=Array.isArray(_?.countries)?_?.countries:void 0,w=k&&k.length>0?k:g&&g.length>0?g:k??g,I=Array.isArray(c.previewRows)?c.previewRows:void 0,E=Array.isArray(_?.previewRows)?_?.previewRows:void 0,de=I&&I.length>0?I:E&&E.length>0?E:I??E;return{...c,countries:w,previewRows:de,_pushed:_?._pushed??c._pushed??!1,_completed:_?._completed??c._completed??!1}}),u={taskId:e,items:o,createdAt:n?.createdAt||Date.now(),queuePushResult:t??n?.queuePushResult,queuePayloadText:a??n?.queuePayloadText};l>=0?i.value[l]=u:i.value.push(u),typeof window<"u"&&window.localStorage.setItem($(),JSON.stringify(i.value))}function he(e){const s=i.value.length;i.value=i.value.filter(t=>t.taskId!==e),i.value.length!==s&&typeof window<"u"&&window.localStorage.setItem($(),JSON.stringify(i.value))}function pe(e){return e==="SUCCESS"||e==="FAILED"||e==="COMPLETED"}function Be(e){if(!e?.length)return!1;const s=new Set;if(e.forEach(a=>{a.taskId&&pe(a.taskStatus)&&s.add(a.taskId)}),!s.size)return!1;const t=i.value.length;return i.value=i.value.filter(a=>!s.has(a.taskId)),i.value.length!==t?(ne(),!0):!1}const Q=G(()=>B.value.filter(e=>!F.value.some(s=>M(s,e)))),qe=G(()=>F.value.length>0||Q.value.length>0),Ue=G(()=>F.value.filter(e=>Pe(e)&&R(e)==="未入队"));function ne(){typeof window<"u"&&(i.value.length===0?window.localStorage.removeItem($()):window.localStorage.setItem($(),JSON.stringify(i.value)))}function N(e){return e?(i.value.find(t=>t.taskId===e)?.items.length||0)>1:!1}function le(e){return e&&i.value.find(s=>s.taskId===e)||null}function M(e,s){return!e||!s?!1:e.resultId!=null&&s.resultId!=null?e.resultId===s.resultId:e.fileKey&&s.fileKey?e.fileKey===s.fileKey:e.sourceFilename===s.sourceFilename}function P(e,s){const t=le(e);return t&&t.items.find(a=>M(a,s))||null}function _e(e){if(!e)return!1;const s=le(e);if(!s)return!1;let t=!1;const a=m.value[e]?.line_progress?.info,l=N(e);if(a?.file_name&&a.current_line!=null&&a.total_lines!=null&&a.total_lines>0&&a.current_line>=a.total_lines){const n=s.items.find(o=>o.sourceFilename===a.file_name);n&&!n._completed&&(n._completed=!0,t=!0)}if(!l){const n=m.value[e]?.task?.status;if((n==="SUCCESS"||n==="FAILED")&&s.items.length===1){const o=s.items[0];o&&!o._completed&&(o._completed=!0,t=!0)}}return t&&ne(),t}function ye(e){return e&&m.value[e]?.task?.status||""}function W(e){if(e.error)return e.error;if(e.matchStatus&&e.matchStatus!=="MATCHED")return e.matchMessage||"";const s=e.taskId;return s&&m.value[s]?.task?.errorMessage||""}function ge(e){const s=e.taskId;if(!s)return!1;const t=m.value[s]?.line_progress,a=ye(s),l=N(s),n=R(e);if(l){const o=P(s,e),u=K(e)===D.value,c=!!(t?.has_progress&&t?.info?.file_name===e.sourceFilename);return u||c||o?._pushed||(a==="RUNNING"||a==="PENDING"||!a)&&o?._completed?!0:{success:!1,retryable:!0}}return n==="本文件解析完毕"||n==="已被全局判定为终态"?!1:t?.has_progress||t?.info?!0:n==="已入队"||n==="处理中"}function me(e){return e.map(s=>s.matched||s.matchStatus==="MATCHED"||s.matchStatus==="INDEX_STALE"?{...s,_pushed:!1,_completed:!1}:{...s,matched:!1,openStoreUrl:void 0,error:s.error||void 0,_pushed:!1,_completed:!1})}function ke(e){return e.matched&&e.matchStatus==="INDEX_STALE"?e.matchMessage||`已匹配 ${e.shopId||""}(索引过期)`.trim():e.matchStatus==="MATCHED"?`已匹配 ${e.shopId||""}`.trim():e.matchMessage?e.matchMessage:e.matchStatus==="CONFLICT"?"存在多个同名店铺,请人工确认":e.matchStatus==="PENDING"?"店铺索引暂未就绪":e.matchStatus?e.matchStatus:e.matched?`已匹配 ${e.shopId||""}`.trim():"待匹配"}function Oe(){ve.value=[...F.value,...Q.value]}function x(){Oe(),Ke(ve.value)}function Ke(e){z.value={total:e.length,successCount:e.filter(s=>s.success).length,failedCount:e.filter(s=>!s.success).length,items:e}}function re(e){const s=e.taskId;return s&&(m.value[s]?.fileProgress||[]).find(l=>l.fileKey&&e.fileKey?l.fileKey===e.fileKey:l.sourceFilename&&e.sourceFilename?l.sourceFilename===e.sourceFilename:!1)||null}function we(e){const s=e.taskId;if(!s)return"";const t=m.value[s],a=t?.line_progress?.info,l=re(e);if(N(s)){const u=P(s,e),c=t?.task?.status,_=!!(a?.file_name&&a.file_name===e.sourceFilename);let k=u?._completed?"COMPLETED":(u?._pushed,"PENDING"),g=0,w=Math.max(0,e.totalRows??l?.totalRows??0);c==="SUCCESS"||c==="FAILED"&&u?._completed?(k="COMPLETED",g=w):_?(k="RUNNING",g=Math.max(0,Math.min(w||Number.MAX_SAFE_INTEGER,a?.current_line??0)),!w&&a?.total_lines&&a.total_lines>0&&(w=a.total_lines)):u?._completed?(k="COMPLETED",g=w):u?._pushed&&(k="PENDING",g=0);const I=[];if(I.push(`文件状态:${k}`),I.push(`文件进度:${g}/${w}`),a?.finished_files!=null){const E=a.file_total&&a.file_total>0?`/${a.file_total}`:"";I.push(`已完成文件:${a.finished_files}${E}`)}return a?.phase&&I.push(`阶段:${a.phase}`),I.join("|")}if(l){const u=[],c=l.processedRows??0,_=l.totalRows??0;if(l.status&&u.push(`文件状态:${l.status}`),u.push(`文件进度:${c}/${_}`),a?.finished_files!=null){const k=a.file_total&&a.file_total>0?`/${a.file_total}`:"";u.push(`已完成文件:${a.finished_files}${k}`)}return a?.phase&&u.push(`阶段:${a.phase}`),u.join("|")}if(!t?.line_progress?.has_progress||!a){const u=t?.task?.status;return u?`任务状态:${u}`:""}const o=[];if(a.phase&&o.push(`阶段:${a.phase}`),a.file_index&&a.file_total&&o.push(`文件:${a.file_index}/${a.file_total}`),a.file_name&&o.push(`当前文件:${a.file_name}`),a.current_line!=null&&a.total_lines!=null&&o.push(`${N(s)?"当前文件进度":"进度"}:${a.current_line}/${a.total_lines}`),a.current_country&&o.push(`国家:${a.current_country}`),a.current_asin&&o.push(`ASIN:${a.current_asin}`),a.finished_files!=null){const u=a.file_total&&a.file_total>0?`/${a.file_total}`:"";o.push(`已完成文件:${a.finished_files}${u}`)}return o.join("|")}function Y(e){const s=e.taskId;if(!s)return 0;const t=m.value[s]?.line_progress?.info;if(N(s)){const o=P(s,e);if(m.value[s]?.task?.status==="SUCCESS"||o?._completed)return 100;const c=Math.max(0,e.totalRows??re(e)?.totalRows??0);if(!!(t?.file_name&&t.file_name===e.sourceFilename)){if(t?.current_line!=null&&t?.total_lines&&t.total_lines>0)return Math.max(0,Math.min(100,Math.round(t.current_line/t.total_lines*100)));if(t?.current_line!=null&&c>0)return Math.max(0,Math.min(100,Math.round(t.current_line/c*100)))}return 0}const l=re(e);return l?Math.max(0,Math.min(100,l.percent??0)):t?t.current_line!=null&&t.total_lines&&t.total_lines>0?Math.max(0,Math.min(100,Math.round(t.current_line/t.total_lines*100))):t.finished_files!=null&&t.file_total&&t.file_total>0?Math.max(0,Math.min(100,Math.round(t.finished_files/t.file_total*100))):m.value[s]?.task?.status==="SUCCESS"?100:0:0}function Ie(e){const s=m.value[e]?.task?.status;return pe(s)}function U(){const e=new Set;return i.value.forEach(s=>{s.items.some(t=>t._pushed)&&e.add(s.taskId)}),Array.from(e)}function R(e){const s=e.taskId;if(!s||!le(s))return"";const a=P(s,e),l=ye(s),n=m.value[s]?.line_progress,o=N(s);if(!o&&(l==="SUCCESS"||l==="FAILED"||e.taskStatus==="SUCCESS"||e.taskStatus==="FAILED"))return"已被全局判定为终态";if(a?._completed)return"本文件解析完毕";if(l==="RUNNING"&&n?.has_progress&&n?.info?.file_name===e.sourceFilename)return"处理中";if(o&&!a?._pushed&&!a?._completed)return"未入队";if(o&&l==="SUCCESS")return"本文件解析完毕";if(!o){const u=m.value[s];if(u?.items&&u.items.find(_=>M(_,e))&&l==="SUCCESS")return"本文件解析完毕"}return a?._pushed?"已入队":"未入队"}function be(e){return!!(e.downloadUrl||e.fileReady)}function He(e){const s=e?.task?.id;if(!s)return!1;const t=i.value.find(o=>o.taskId===s);if(!t)return{success:!1,retryable:!1};const a=e?.items||[];let l=!1;const n=t.items.map(o=>{const u=a.find(de=>M(de,o));if(!u)return o;const c=Array.isArray(u.countries)?u.countries:void 0,_=Array.isArray(o.countries)?o.countries:void 0,k=c&&c.length>0?c:_&&_.length>0?_:c??_,g=Array.isArray(u.previewRows)?u.previewRows:void 0,w=Array.isArray(o.previewRows)?o.previewRows:void 0,I=g&&g.length>0?g:w&&w.length>0?w:g??w,E={...o,...u,countries:k,previewRows:I,_pushed:o._pushed,_completed:o._completed};return JSON.stringify(E)!==JSON.stringify(o)&&(l=!0),E});for(const o of a)n.some(u=>M(u,o))||(n.push({...o,_pushed:!1,_completed:!1}),l=!0);return JSON.stringify(n)!==JSON.stringify(t.items)&&(t.items=n,l=!0),l&&ne(),l}async function oe(e){const s=e||U();if(s.length)try{const t=await ns(s);se.value&&C.value&&(b.value="后端已恢复,继续执行当前任务并自动衔接后续任务..."),se.value=!1;let a=!1;for(const l of t.items||[]){const n=l?.task?.id;typeof n=="number"&&n>0&&(m.value[n]=l,He(l)&&(a=!0),_e(n)&&(a=!0))}a&&x()}catch(t){const a=(t instanceof Error?t.message:String(t||"")).toLowerCase();["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(n=>a.includes(n.toLowerCase()))&&C.value&&(se.value=!0,b.value="当前任务运行中,正在等待后端服务恢复...")}}function Ge(){return is()}function ue(e=!1){if(T.value){if(!e)return;clearTimeout(T.value),T.value=null}const s=async()=>{if(T.value=null,ee.value){ue();return}const t=U();if(!t.length)return;ee.value=!0;let a=!1,l=!1;try{await oe(t),await Ae();for(const n of t)Ie(n)&&(he(n),a=!0,l=!0)}finally{ee.value=!1}l?await O():a&&x(),U().length>0&&ue()};e?s():T.value=window.setTimeout(s,Ge())}function ie(e=!1){T.value&&!e||ue(e)}function Z(e){const s=e.taskId?m.value[e.taskId]?.task?.status:null;return s==="SUCCESS"?{className:"success",text:"已完成"}:s==="FAILED"?{className:"failed",text:"失败"}:s==="RUNNING"?{className:"running",text:"执行中"}:e.taskStatus==="SUCCESS"?{className:"success",text:"已完成"}:e.taskStatus==="FAILED"?{className:"failed",text:"失败"}:e.taskStatus==="RUNNING"?{className:"running",text:"执行中"}:e.success?{className:"success",text:"已完成"}:{className:"failed",text:"失败"}}function Se(){T.value&&(window.clearTimeout(T.value),T.value=null),ce()}async function Te(e){const s=J();if(!s?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传桥接能力");const t=[];for(const a of e){const l=typeof a=="string"?a:a.absolutePath,n=typeof a=="string"?void 0:a.relativePath,o=await s.upload_file_to_java(l,n);if(!o?.success||!o.data)throw new Error(o?.error||o?.message||`上传失败:${l}`);t.push(o.data)}return t}async function Je(){const e=J();if(!e?.select_brand_xlsx_files){p.warning("当前环境不支持文件选择,请在本机客户端中打开");return}try{const s=await e.select_brand_xlsx_files();if(!s?.length)return;A.value=s,j.value=await Te(s),p.success(`已选择 ${s.length} 个删除品牌文件`)}catch(s){p.error(s instanceof Error?s.message:"选择失败")}}async function je(){const e=J();if(!e?.select_brand_folder){p.warning("当前环境不支持文件夹选择,请在本机客户端中打开");return}try{const s=await e.select_brand_folder();if(!s)return;const t=await vs(s);if(!t.success||!t.items?.length){p.warning(t.error||"该文件夹下没有 xlsx 文件");return}A.value=t.items.map(a=>a.relativePath||a.absolutePath),j.value=await Te(t.items),p.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`)}catch(s){p.error(s instanceof Error?s.message:"选择失败")}}async function ze(){if(!j.value.length){p.warning("请先选择待处理文件");return}try{L.value=!0;const e=await ls({files:j.value.map(n=>({fileKey:n.fileKey,originalFilename:n.originalFilename,relativePath:n.relativePath}))}),s=me(e.items||[]),t=s.some(n=>n.matchStatus==="MATCHED"||n.matchStatus==="INDEX_STALE"||n.matched),a=s.some(n=>n.matchStatus==="INDEX_STALE"&&n.matched),l=s.some(n=>!n.matched&&n.matchStatus!=="MATCHED"&&n.matchStatus!=="INDEX_STALE");b.value=t?"解析完成,可在左侧点击“推送到 Python 队列”开始串行处理":"解析完成,当前没有可推送的文件",S.value="",s.length&&s[0].taskId&&ae(s[0].taskId,s,b.value,S.value),x(),l?p.warning("部分文件尚未命中可用店铺索引,已保留状态信息,请等待后台刷新后重试。"):a?p.warning("部分文件命中的是过期索引,仍可推送到 Python 队列;后台刷新后会自动重新匹配。"):t?p.success("删除品牌解析完成,请在左侧推送到 Python 队列"):p.warning("当前没有可推送的文件,请先等待店铺索引刷新。"),await O()}catch(e){p.error(e instanceof Error?e.message:"执行失败")}finally{L.value=!1}}async function Ee(e){const s=e.taskId;if(!s){p.warning("未找到任务ID");return}const t=J(),a=rs(s),l=e.outputFilename||e.sourceFilename||`delete-brand_${s}.xlsx`;if(t?.save_file_from_url_new){const n=await t.save_file_from_url_new(a,l);n.success?p.success(`已保存:${n.path||l}`):n.error&&n.error!=="用户取消"&&p.error(n.error);return}}async function O(){try{const e=await os();B.value=me(e.items||[]),Be(B.value),x(),await oe(),ie(!0)}catch(e){const s=(e instanceof Error?e.message:String(e||"")).toLowerCase();["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(a=>s.includes(a.toLowerCase()))||console.error("loadHistory error:",e)}}function Ce(e){i.value.forEach(t=>{t.items=t.items.filter(a=>a.resultId!==e)});const s=i.value.length;i.value=i.value.filter(t=>t.items.length>0),i.value.length!==s&&typeof window<"u"&&window.localStorage.setItem($(),JSON.stringify(i.value)),B.value=B.value.filter(t=>t.resultId!==e),x(),U().length===0&&Se()}async function Fe(e){try{await us(e),Ce(e),await O(),p.success("已删除")}catch(s){const t=s instanceof Error?s.message:"删除失败";if(typeof t=="string"&&t.includes("记录不存在")){Ce(e),p.success("已删除");return}p.error(t)}}function Re(e){const s=e.slice(0,5).map(a=>`${a.country}:${a.asin}${a.status?`(${a.status})`:""}`);return e.length-s.length>0?`${s.join("、")} 等 ${e.length} 条`:s.join("、")}function It(e,s){}function ce(){q.value&&(window.clearTimeout(q.value),q.value=null)}function Ve(e=3e3){ce(),q.value=window.setTimeout(()=>{q.value=null,Ae().catch(()=>{})},e)}function Xe(e){return e.includes("当前店铺正在执行中")}function Ne(){for(const e of i.value)for(const s of e.items){const t=R(s);if(t==="已入队"||t==="处理中")return!0}return!1}function K(e){return e.resultId!=null?`result:${e.resultId}`:`task:${e.taskId||0}:${e.sourceFilename||""}`}function Pe(e){return!!(e.taskId&&(e.matchStatus==="MATCHED"||e.matchStatus==="INDEX_STALE"||e.matched))}function xe(){return F.value.find(e=>!Pe(e)||K(e)===D.value||P(e.taskId,e)?._completed?!1:R(e)==="未入队")}async function $e(e,s){if(s?.auto&&Ne())return e.taskId,e.sourceFilename,{success:!1,retryable:!0};const t=J(),a=e.taskId;if(!a)return{success:!1,retryable:!1};const l=i.value.find(c=>c.taskId===a);if(!l)return{success:!1,retryable:!1};if(!t?.enqueue_json)return p.error("当前环境未启用 pywebview enqueue_json(浏览器环境不会推送)"),{success:!1,retryable:!1};const n={type:"delete-brand-run",ts:Date.now(),data:{taskId:a,items:[e]}};S.value=JSON.stringify(n,null,2);const o=await t.enqueue_json(n);let u="";if(o?.success){u=`已推送文件 ${e.sourceFilename},当前队列长度:${o.queue_size??"-"}`;const c=P(a,e);return c&&(c._pushed=!0,c._completed=!1),D.value=K(e),ae(a,l.items,u,S.value),ie(!0),b.value=u,{success:!0,retryable:!1}}else{const c=o?.error||"未知错误";if(u=`推送到 Python 队列失败:${c}`,b.value=u,ae(a,l.items,u,S.value),s?.auto&&Xe(c))return{success:!1,retryable:!0}}return b.value=u,{success:!1,retryable:!1}}async function Qe(){const e=xe();if(!e){p.warning("当前没有可推送的文件");return}V.value=!0,C.value=!0,ce();const s=await $e(e);if(V.value=!1,!s.success){C.value=!1,D.value="";return}p.success("已开始按顺序推送到 Python 队列")}async function Ae(){if(!C.value||X.value){C.value,X.value;return}if(Ne())return;const e=D.value;if(e){const t=F.value.find(a=>K(a)===e);if(t){const a=t.taskId,l=N(a);l&&(_e(a),R(t),void 0);const n=R(t);if(n==="已入队"||n==="处理中"){t.sourceFilename;return}if(l){const o=P(a,t);if(o&&!o._completed){t.sourceFilename,o._pushed,o._completed;return}}}}const s=xe();if(!s){D.value="",C.value=!1;return}X.value=!0;try{s.taskId,s.sourceFilename,K(s);const t=await $e(s,{auto:!0});if(!t.success){if(t.retryable){s.taskId,s.sourceFilename,Ve();return}s.taskId,s.sourceFilename,C.value=!1}}finally{X.value=!1}}return Ze(()=>{Le();const e=U();e.length>0?oe(e).then(async()=>{let s=!1,t=!1;for(const a of e)Ie(a)&&(he(a),s=!0,t=!0);t?await O():s&&x(),ie(!0)}):x(),O().catch(()=>{})}),es(()=>{Se()}),(e,s)=>(d(),f("div",hs,[ss(ts,{active:"delete-brand"}),r("div",ps,[r("aside",_s,[s[2]||(s[2]=r("div",{class:"section-title"},"选择文件",-1)),r("div",ys,[s[0]||(s[0]=r("div",{class:"hint"},"上传删除品牌 Excel;无论是直接上传文件还是上传文件夹批量导入,都会按每个 Excel 文件名作为店铺名。",-1)),r("div",{class:"btns"},[r("button",{type:"button",class:"opt-btn",onClick:Je},"选择 Excel 文件"),r("button",{type:"button",class:"opt-btn",onClick:je},"选择文件夹")]),r("div",gs,[A.value.length?(d(),f(H,{key:0},[(d(!0),f(H,null,fe(te.value,t=>(d(),f("span",{key:t},v(t),1))),128)),A.value.length>te.value.length?(d(),f("span",ms," 还有 "+v(A.value.length-te.value.length)+" 个文件未展开显示 ",1)):h("",!0)],64)):(d(),f("span",ks,"暂未选择删除品牌文件"))])]),s[3]||(s[3]=as('