fix: update patrol delete progress handling

This commit is contained in:
koko
2026-05-02 02:03:49 +08:00
parent 34148b5d8a
commit 7968cef8c3
45 changed files with 373 additions and 218 deletions

View File

@@ -1792,6 +1792,10 @@ class PatrolDeleteTask:
f"国家 {country_name} 处理结束success={country_result['success']}" f"国家 {country_name} 处理结束success={country_result['success']}"
f"deleted={country_result['deletedCount']}reopenRequired={requires_browser_reset}" f"deleted={country_result['deletedCount']}reopenRequired={requires_browser_reset}"
) )
self._post_progress_result_safely(
task_id=task_id,
shop_name=shop_name,
)
if driver is not None: if driver is not None:
self.log(f"店铺 {shop_name} 国家处理完成,正在关闭店铺") self.log(f"店铺 {shop_name} 国家处理完成,正在关闭店铺")
@@ -1822,6 +1826,22 @@ class PatrolDeleteTask:
del runing_shop[shop_name] del runing_shop[shop_name]
self.log(f"店铺 {shop_name} 已从执行列表中移除") self.log(f"店铺 {shop_name} 已从执行列表中移除")
def _post_progress_result_safely(
self,
task_id: int,
shop_name: str,
) -> None:
"""Submit a heartbeat-only payload so Java does not append duplicate result rows."""
try:
self.post_result(
task_id=task_id,
shop_name=shop_name,
shop_done=False,
heartbeat_only=True,
)
except Exception as exc:
self.log(f"店铺 {shop_name} 中间结果回传失败,继续执行: {str(exc)}", "WARNING")
def open_shop(self, max_retries: int, company_name: str, shop_name: str, iskill: bool = False) -> Optional[InventoryManage]: def open_shop(self, max_retries: int, company_name: str, shop_name: str, iskill: bool = False) -> Optional[InventoryManage]:
error_info = "" error_info = ""
driver: Optional[InventoryManage] = None driver: Optional[InventoryManage] = None
@@ -1996,6 +2016,8 @@ class PatrolDeleteTask:
"type": "completeDraft", "type": "completeDraft",
"status": PatrolDeleteTask._string_result_field(item.get("tag")), "status": PatrolDeleteTask._string_result_field(item.get("tag")),
"quantity": quantity, "quantity": quantity,
"deleteQuantity": "",
"processStatus": "",
} }
) )
self.log(f"trace_id={trace_id} 国家 {country_name} 补全草稿读取完成: rows={rows}") self.log(f"trace_id={trace_id} 国家 {country_name} 补全草稿读取完成: rows={rows}")
@@ -2032,6 +2054,7 @@ class PatrolDeleteTask:
"status": status, "status": status,
"quantity": InventoryManage._normalize_quantity_text(item.get("quantity")), "quantity": InventoryManage._normalize_quantity_text(item.get("quantity")),
"deleteQuantity": str(deleted_count), "deleteQuantity": str(deleted_count),
"processStatus": "已完成" if deleted_count > 0 else "",
} }
) )
section = {"country": country_name, "rows": rows} if rows else None section = {"country": country_name, "rows": rows} if rows else None
@@ -2116,6 +2139,7 @@ class PatrolDeleteTask:
cart_ratios: Optional[List[Dict[str, Any]]] = None, cart_ratios: Optional[List[Dict[str, Any]]] = None,
error: str = "", error: str = "",
shop_done: bool = False, shop_done: bool = False,
heartbeat_only: bool = False,
): ):
"""回传巡店删除结果到 Java API。""" """回传巡店删除结果到 Java API。"""
from config import DELETE_BRAND_API_BASE from config import DELETE_BRAND_API_BASE
@@ -2130,6 +2154,8 @@ class PatrolDeleteTask:
} }
if error: if error:
shop_payload["error"] = error shop_payload["error"] = error
elif heartbeat_only:
shop_payload["heartbeatOnly"] = True
else: else:
shop_payload["countrySections"] = self._normalize_country_sections_for_result(country_sections) shop_payload["countrySections"] = self._normalize_country_sections_for_result(country_sections)
shop_payload["cartRatios"] = self._normalize_cart_ratios_for_result(cart_ratios) shop_payload["cartRatios"] = self._normalize_cart_ratios_for_result(cart_ratios)
@@ -2217,9 +2243,12 @@ class PatrolDeleteTask:
rows = [] rows = []
for row in section.get("rows") or []: for row in section.get("rows") or []:
if cls._is_complete_draft_result_row(row): if cls._is_complete_draft_result_row(row):
delete_quantity = cls._string_result_field(row.get("deleteQuantity"))
normalized_row = { normalized_row = {
"status": cls._complete_draft_result_status(row),
"quantity": cls._string_result_field(row.get("quantity")), "quantity": cls._string_result_field(row.get("quantity")),
"deleteQuantity": cls._string_result_field(row.get("deleteQuantity")), "deleteQuantity": delete_quantity,
"processStatus": cls._complete_draft_process_status(row, delete_quantity),
} }
else: else:
normalized_row = { normalized_row = {
@@ -2255,6 +2284,19 @@ class PatrolDeleteTask:
row_type = str(row.get("type") or row.get("kind") or row.get("_kind") or "").strip() row_type = str(row.get("type") or row.get("kind") or row.get("_kind") or "").strip()
return status in {"补全草稿", "商品信息草稿"} or tag == "补全草稿" or row_type == "completeDraft" return status in {"补全草稿", "商品信息草稿"} or tag == "补全草稿" or row_type == "completeDraft"
@staticmethod
def _complete_draft_result_status(row: Dict[str, Any]) -> str:
status = PatrolDeleteTask._string_result_field(row.get("status") or row.get("tag")).strip()
return status or "商品信息草稿"
@staticmethod
def _complete_draft_process_status(row: Dict[str, Any], delete_quantity: str) -> str:
process_status = PatrolDeleteTask._string_result_field(row.get("processStatus")).strip()
if process_status:
return process_status
match = re.search(r"\d+", str(delete_quantity or ""))
return "已完成" if match and int(match.group(0)) > 0 else ""
@classmethod @classmethod
def _replace_complete_draft_rows( def _replace_complete_draft_rows(
cls, cls,

View File

@@ -27,9 +27,9 @@ def _resolve_asset_filename(filename):
"""Resolve hashed Vite assets without maintaining hardcoded alias tables.""" """Resolve hashed Vite assets without maintaining hardcoded alias tables."""
safe_name = os.path.basename(filename) safe_name = os.path.basename(filename)
asset_dirs = [ asset_dirs = [
ASSETS_DIR,
os.path.abspath(os.path.join(BASE_DIR, 'new_web_source', 'assets')), os.path.abspath(os.path.join(BASE_DIR, 'new_web_source', 'assets')),
os.path.abspath(os.path.join(BASE_DIR, '..', 'new_web_source', 'assets')), os.path.abspath(os.path.join(BASE_DIR, '..', 'new_web_source', 'assets')),
ASSETS_DIR,
] ]
for asset_dir in asset_dirs: for asset_dir in asset_dirs:
exact_path = os.path.join(asset_dir, safe_name) exact_path = os.path.join(asset_dir, safe_name)
@@ -153,9 +153,9 @@ def serve_assets(filename):
"""提供 static 目录及子目录下的静态文件访问。""" """提供 static 目录及子目录下的静态文件访问。"""
filename = _resolve_asset_filename(filename) filename = _resolve_asset_filename(filename)
candidate_dirs = [ candidate_dirs = [
os.path.abspath(ASSETS_DIR),
os.path.abspath(os.path.join(BASE_DIR, 'new_web_source', 'assets')), os.path.abspath(os.path.join(BASE_DIR, 'new_web_source', 'assets')),
os.path.abspath(os.path.join(BASE_DIR, '..', 'new_web_source', 'assets')), os.path.abspath(os.path.join(BASE_DIR, '..', 'new_web_source', 'assets')),
os.path.abspath(ASSETS_DIR),
] ]
for static_abs in candidate_dirs: for static_abs in candidate_dirs:
filepath = os.path.normpath(os.path.join(static_abs, filename)) filepath = os.path.normpath(os.path.join(static_abs, filename))

View File

@@ -7,13 +7,13 @@ import json
import sys import sys
import shutil import shutil
import os import os
from amazon.main import TaskMonitor
os.makedirs(cache_path,exist_ok=True) os.makedirs(cache_path,exist_ok=True)
if not debug: if not debug:
today = datetime.datetime.now().strftime("%Y_%m_%d") today = datetime.datetime.now().strftime("%Y_%m_%d")
sys.stdout = open(os.path.join(cache_path,f'{today}.log'), 'a',buffering=1,encoding='utf-8') sys.stdout = open(os.path.join(cache_path,f'{today}.log'), 'a',buffering=1,encoding='utf-8')
sys.stderr = sys.stdout sys.stderr = sys.stdout
from amazon.main import TaskMonitor
import webview import webview
import threading import threading
import time import time

View File

@@ -5,10 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>格式转换 - 数富AI</title> <title>格式转换 - 数富AI</title>
<script type="module" crossorigin src="/assets/convert.js"></script> <script type="module" crossorigin src="/assets/convert.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-BtdhG28Q.js"> <link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/brand-Lp7YWffz.js"> <link rel="modulepreload" crossorigin href="/assets/brand-CABpTGPu.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css"> <link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/convert-BKSNvX8i.css"> <link rel="stylesheet" crossorigin href="/assets/convert-r7MSXq7I.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@@ -5,10 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>数据去重 - 数富AI</title> <title>数据去重 - 数富AI</title>
<script type="module" crossorigin src="/assets/dedupe.js"></script> <script type="module" crossorigin src="/assets/dedupe.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-BtdhG28Q.js"> <link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/brand-Lp7YWffz.js"> <link rel="modulepreload" crossorigin href="/assets/brand-CABpTGPu.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css"> <link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/dedupe-DNlVfFj-.css"> <link rel="stylesheet" crossorigin href="/assets/dedupe-DMeaPUMZ.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@@ -5,11 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>删除品牌 - 数富AI</title> <title>删除品牌 - 数富AI</title>
<script type="module" crossorigin src="/assets/delete-brand.js"></script> <script type="module" crossorigin src="/assets/delete-brand.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-BtdhG28Q.js"> <link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/brand-Lp7YWffz.js"> <link rel="modulepreload" crossorigin href="/assets/brand-CABpTGPu.js">
<link rel="modulepreload" crossorigin href="/assets/categorized-timers-JPA-olTr.js"> <link rel="modulepreload" crossorigin href="/assets/categorized-timers-JPA-olTr.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css"> <link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/delete-brand-BfMLVSQU.css"> <link rel="stylesheet" crossorigin href="/assets/delete-brand-B5ChOXZY.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@@ -5,10 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>数据拆分 - 数富AI</title> <title>数据拆分 - 数富AI</title>
<script type="module" crossorigin src="/assets/split.js"></script> <script type="module" crossorigin src="/assets/split.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-BtdhG28Q.js"> <link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/brand-Lp7YWffz.js"> <link rel="modulepreload" crossorigin href="/assets/brand-CABpTGPu.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css"> <link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/split-BoBVrLdC.css"> <link rel="stylesheet" crossorigin href="/assets/split-Cw6sXhAg.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@@ -105,7 +105,7 @@ def test_patrol_delete_task_post_result_retries_business_failure(monkeypatch):
assert len(calls) == 3 assert len(calls) == 3
def test_normalize_country_sections_omits_status_fields_for_complete_draft_rows(): def test_normalize_country_sections_keeps_status_fields_for_complete_draft_rows():
rows = PatrolDeleteTask._normalize_country_sections_for_result( rows = PatrolDeleteTask._normalize_country_sections_for_result(
[ [
{ {
@@ -132,7 +132,7 @@ def test_normalize_country_sections_omits_status_fields_for_complete_draft_rows(
{ {
"country": "意大利", "country": "意大利",
"rows": [ "rows": [
{"quantity": "12", "deleteQuantity": "3"}, {"status": "商品信息草稿", "quantity": "12", "deleteQuantity": "3", "processStatus": "已完成"},
{"status": "缺少的信息", "quantity": "1", "deleteQuantity": "1", "processStatus": "已完成"}, {"status": "缺少的信息", "quantity": "1", "deleteQuantity": "1", "processStatus": "已完成"},
], ],
} }
@@ -150,8 +150,8 @@ def test_replace_complete_draft_rows_uses_quick_view_rows():
complete_draft_section = { complete_draft_section = {
"country": "西班牙", "country": "西班牙",
"rows": [ "rows": [
{"type": "completeDraft", "quantity": "1", "deleteQuantity": "1"}, {"type": "completeDraft", "quantity": "1", "deleteQuantity": "1", "processStatus": "已完成"},
{"type": "completeDraft", "quantity": "0", "deleteQuantity": "0"}, {"type": "completeDraft", "quantity": "0", "deleteQuantity": "0", "processStatus": ""},
], ],
} }
@@ -161,8 +161,8 @@ def test_replace_complete_draft_rows_uses_quick_view_rows():
"country": "西班牙", "country": "西班牙",
"rows": [ "rows": [
{"status": "全部", "quantity": "6230", "deleteQuantity": "0", "processStatus": "无可删商品"}, {"status": "全部", "quantity": "6230", "deleteQuantity": "0", "processStatus": "无可删商品"},
{"type": "completeDraft", "quantity": "1", "deleteQuantity": "1"}, {"type": "completeDraft", "quantity": "1", "deleteQuantity": "1", "processStatus": "已完成"},
{"type": "completeDraft", "quantity": "0", "deleteQuantity": "0"}, {"type": "completeDraft", "quantity": "0", "deleteQuantity": "0", "processStatus": ""},
], ],
} }
assert PatrolDeleteTask._normalize_country_sections_for_result([merged]) == [ assert PatrolDeleteTask._normalize_country_sections_for_result([merged]) == [
@@ -170,8 +170,8 @@ def test_replace_complete_draft_rows_uses_quick_view_rows():
"country": "西班牙", "country": "西班牙",
"rows": [ "rows": [
{"status": "全部", "quantity": "6230", "deleteQuantity": "0", "processStatus": "无可删商品"}, {"status": "全部", "quantity": "6230", "deleteQuantity": "0", "processStatus": "无可删商品"},
{"quantity": "1", "deleteQuantity": "1"}, {"status": "商品信息草稿", "quantity": "1", "deleteQuantity": "1", "processStatus": "已完成"},
{"quantity": "0", "deleteQuantity": "0"}, {"status": "商品信息草稿", "quantity": "0", "deleteQuantity": "0", "processStatus": ""},
], ],
} }
] ]
@@ -261,6 +261,18 @@ def test_patrol_delete_task_process_task_aggregates_country_results(monkeypatch)
assert runing_task[1]["deleted_listings_count"] == 2 assert runing_task[1]["deleted_listings_count"] == 2
assert "郭亚芳" not in runing_shop assert "郭亚芳" not in runing_shop
assert calls == [ assert calls == [
{
"task_id": 1,
"shop_name": "郭亚芳",
"shop_done": False,
"heartbeat_only": True,
},
{
"task_id": 1,
"shop_name": "郭亚芳",
"shop_done": False,
"heartbeat_only": True,
},
{ {
"task_id": 1, "task_id": 1,
"shop_name": "郭亚芳", "shop_name": "郭亚芳",
@@ -377,16 +389,28 @@ def test_delete_complete_draft_country_section_reports_delete_quantity(monkeypat
assert result["countrySection"] == { assert result["countrySection"] == {
"country": "德国", "country": "德国",
"rows": [ "rows": [
{"type": "completeDraft", "status": "未提交的草稿", "quantity": "0", "deleteQuantity": "3"}, {
{"type": "completeDraft", "status": "已提交:提供缺少的信息", "quantity": "2", "deleteQuantity": "0"}, "type": "completeDraft",
"status": "未提交的草稿",
"quantity": "0",
"deleteQuantity": "3",
"processStatus": "已完成",
},
{
"type": "completeDraft",
"status": "已提交:提供缺少的信息",
"quantity": "2",
"deleteQuantity": "0",
"processStatus": "",
},
], ],
} }
assert PatrolDeleteTask._normalize_country_sections_for_result([result["countrySection"]]) == [ assert PatrolDeleteTask._normalize_country_sections_for_result([result["countrySection"]]) == [
{ {
"country": "德国", "country": "德国",
"rows": [ "rows": [
{"quantity": "0", "deleteQuantity": "3"}, {"status": "未提交的草稿", "quantity": "0", "deleteQuantity": "3", "processStatus": "已完成"},
{"quantity": "2", "deleteQuantity": "0"}, {"status": "已提交:提供缺少的信息", "quantity": "2", "deleteQuantity": "0", "processStatus": ""},
], ],
} }
] ]

View File

@@ -60,7 +60,12 @@
</el-table> </el-table>
</div> </div>
<div class="section-title">删除条件</div> <div class="section-title condition-title">
<span>删除条件</span>
<span class="condition-title-hint">
注意删除条件的描述需要和页面描述一致
</span>
</div>
<div class="condition-panel"> <div class="condition-panel">
<div class="condition-input-row"> <div class="condition-input-row">
<el-input <el-input
@@ -823,13 +828,14 @@ async function refreshActiveTaskProgress(taskIds?: number[]) {
), ),
); );
if (!ids.length) { if (!ids.length) {
return; return [];
} }
const batch = await getPatrolDeleteTaskProgressBatch(ids); const batch = await getPatrolDeleteTaskProgressBatch(ids);
mergeHistoryProgressItems(batch.items || []); mergeHistoryProgressItems(batch.items || []);
if ((batch.missingTaskIds || []).length) { if ((batch.missingTaskIds || []).length) {
await loadHistory(); await loadHistory();
} }
return batch.missingTaskIds || [];
} }
function startHistoryPolling() { function startHistoryPolling() {
@@ -1029,7 +1035,11 @@ async function waitForTaskTerminal(taskId: number) {
if (disposed) return "STOPPED"; if (disposed) return "STOPPED";
if (activeTaskId.value !== taskId) return "DELETED"; if (activeTaskId.value !== taskId) return "DELETED";
try { try {
await refreshActiveTaskProgress([taskId]); const missingTaskIds = await refreshActiveTaskProgress([taskId]);
if (missingTaskIds.includes(taskId)) {
clearActiveQueueTask();
return "DELETED";
}
if (activeTaskId.value !== taskId) return "DELETED"; if (activeTaskId.value !== taskId) return "DELETED";
if (transientErrorCount > 0) { if (transientErrorCount > 0) {
queuePushResult.value = `任务 ${taskId} 后端已恢复,继续等待执行结果...`; queuePushResult.value = `任务 ${taskId} 后端已恢复,继续等待执行结果...`;
@@ -1236,6 +1246,8 @@ onUnmounted(() => {
.left-panel { width: 400px; background: #1e1e1e; padding: 20px; overflow-y: auto; border-right: 1px solid #2a2a2a; } .left-panel { width: 400px; background: #1e1e1e; padding: 20px; overflow-y: auto; border-right: 1px solid #2a2a2a; }
.right-panel { flex: 1; display: flex; flex-direction: column; min-width: 0; background: #1a1a1a; } .right-panel { flex: 1; display: flex; flex-direction: column; min-width: 0; background: #1a1a1a; }
.section-title { font-size: 13px; color: #bbb; margin-bottom: 10px; } .section-title { font-size: 13px; color: #bbb; margin-bottom: 10px; }
.condition-title { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.condition-title-hint { flex: 1; min-width: 0; color: #d6a95a; font-size: 12px; text-align: right; line-height: 1.35; }
.input-zone { border: 1px dashed #3a3a3a; border-radius: 10px; padding: 16px; background: #252525; margin-bottom: 20px; } .input-zone { border: 1px dashed #3a3a3a; border-radius: 10px; padding: 16px; background: #252525; margin-bottom: 20px; }
.hint { color: #888; font-size: 12px; margin-bottom: 12px; line-height: 1.5; text-align: left; } .hint { color: #888; font-size: 12px; margin-bottom: 12px; line-height: 1.5; text-align: left; }
.input-row { display: flex; gap: 10px; align-items: center; } .input-row { display: flex; gap: 10px; align-items: center; }

View File

@@ -5,10 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>外观专利检测</title> <title>外观专利检测</title>
<script type="module" crossorigin src="/assets/appearance-patent.js"></script> <script type="module" crossorigin src="/assets/appearance-patent.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-C66x_2Dh.js"> <link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/brand-BZije8D7.js"> <link rel="modulepreload" crossorigin href="/assets/brand-CABpTGPu.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css"> <link rel="modulepreload" crossorigin href="/assets/categorized-timers-JPA-olTr.js">
<link rel="stylesheet" crossorigin href="/assets/appearance-patent-BPCrG75P.css"> <link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/appearance-patent-TI-osB39.css">
<link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css"> <link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css">
</head> </head>
<body> <body>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
import{aZ as r}from"./pywebview-BWNiqXug.js";const n="";function a(e){return r(`${n}/api/brand/expand-folder-recursive`,{folder:e})}export{a as e};

View File

@@ -0,0 +1 @@
const r=new Map;function c(n){let t=r.get(n);return t||(t=new Map,r.set(n,t)),t}function u(n,t){const e=r.get(n);e&&(e.delete(t),e.size||r.delete(n))}function l(n,t,e){const i=window.setTimeout(()=>{u(n,i),t()},e);return c(n).set(i,{id:i,kind:"timeout",category:n}),i}function a(n,t,e){const i=window.setInterval(t,e);return c(n).set(i,{id:i,kind:"interval",category:n}),i}function f(n,t){if(t==null)return;const i=r.get(n)?.get(t);i?.kind==="interval"?window.clearInterval(t):window.clearTimeout(t),i?.cancel?.(),u(n,t)}function s(n){const t=r.get(n);if(t){for(const e of t.values())e.kind==="interval"?window.clearInterval(e.id):window.clearTimeout(e.id),e.cancel?.();r.delete(n)}}function d(n,t){return new Promise(e=>{const i=window.setTimeout(()=>{u(n,i),e()},t);c(n).set(i,{id:i,kind:"timeout",category:n,cancel:e})})}function m(n){const t=`${n}:`;for(const e of Array.from(r.keys()))(e===n||e.startsWith(t))&&s(e)}function w(n){const t=e=>`${n}:${e}`;return{setTimeout(e,i,o){return l(t(e),i,o)},setInterval(e,i,o){return a(t(e),i,o)},clearTimer(e,i){f(t(e),i)},clearCategory(e){s(t(e))},clearScope(){m(n)},sleep(e,i){return d(t(e),i)}}}export{w as c};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -5,10 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>格式转换 - 数富AI</title> <title>格式转换 - 数富AI</title>
<script type="module" crossorigin src="/assets/convert.js"></script> <script type="module" crossorigin src="/assets/convert.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-C66x_2Dh.js"> <link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/brand-BZije8D7.js"> <link rel="modulepreload" crossorigin href="/assets/brand-CABpTGPu.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css"> <link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/convert-BKSNvX8i.css"> <link rel="stylesheet" crossorigin href="/assets/convert-r7MSXq7I.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@@ -5,10 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>数据去重 - 数富AI</title> <title>数据去重 - 数富AI</title>
<script type="module" crossorigin src="/assets/dedupe.js"></script> <script type="module" crossorigin src="/assets/dedupe.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-C66x_2Dh.js"> <link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/brand-BZije8D7.js"> <link rel="modulepreload" crossorigin href="/assets/brand-CABpTGPu.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css"> <link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/dedupe-DNlVfFj-.css"> <link rel="stylesheet" crossorigin href="/assets/dedupe-DMeaPUMZ.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@@ -5,10 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>删除品牌 - 数富AI</title> <title>删除品牌 - 数富AI</title>
<script type="module" crossorigin src="/assets/delete-brand.js"></script> <script type="module" crossorigin src="/assets/delete-brand.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-C66x_2Dh.js"> <link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/brand-BZije8D7.js"> <link rel="modulepreload" crossorigin href="/assets/brand-CABpTGPu.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css"> <link rel="modulepreload" crossorigin href="/assets/categorized-timers-JPA-olTr.js">
<link rel="stylesheet" crossorigin href="/assets/delete-brand-BP3XWKAC.css"> <link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/delete-brand-B5ChOXZY.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@@ -5,10 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>巡店删除 - 数富AI</title> <title>巡店删除 - 数富AI</title>
<script type="module" crossorigin src="/assets/patrol-delete.js"></script> <script type="module" crossorigin src="/assets/patrol-delete.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-C66x_2Dh.js"> <link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/zh-cn-CuE9Zzgz.js"> <link rel="modulepreload" crossorigin href="/assets/zh-cn-BbuLS91u.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css"> <link rel="modulepreload" crossorigin href="/assets/categorized-timers-JPA-olTr.js">
<link rel="stylesheet" crossorigin href="/assets/patrol-delete-CSekhzSS.css"> <link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/patrol-delete-DyumfGaZ.css">
<link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css"> <link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css">
<link rel="stylesheet" crossorigin href="/assets/el-input-xaztPnzw.css"> <link rel="stylesheet" crossorigin href="/assets/el-input-xaztPnzw.css">
</head> </head>

View File

@@ -5,10 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>跟价 - 数富AI</title> <title>跟价 - 数富AI</title>
<script type="module" crossorigin src="/assets/price-track.js"></script> <script type="module" crossorigin src="/assets/price-track.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-C66x_2Dh.js"> <link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/brand-BZije8D7.js"> <link rel="modulepreload" crossorigin href="/assets/brand-CABpTGPu.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css"> <link rel="modulepreload" crossorigin href="/assets/categorized-timers-JPA-olTr.js">
<link rel="stylesheet" crossorigin href="/assets/price-track-z8RU_FlW.css"> <link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/price-track-DMhhVz4u.css">
<link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css"> <link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css">
<link rel="stylesheet" crossorigin href="/assets/el-input-xaztPnzw.css"> <link rel="stylesheet" crossorigin href="/assets/el-input-xaztPnzw.css">
</head> </head>

View File

@@ -5,11 +5,12 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>商品风险解决 - 数富AI</title> <title>商品风险解决 - 数富AI</title>
<script type="module" crossorigin src="/assets/product-risk.js"></script> <script type="module" crossorigin src="/assets/product-risk.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-C66x_2Dh.js"> <link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/listingFilters-BpGOU_pJ.js"> <link rel="modulepreload" crossorigin href="/assets/listingFilters-BpGOU_pJ.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css"> <link rel="modulepreload" crossorigin href="/assets/categorized-timers-JPA-olTr.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/listingFilters-CK58rX4v.css"> <link rel="stylesheet" crossorigin href="/assets/listingFilters-CK58rX4v.css">
<link rel="stylesheet" crossorigin href="/assets/product-risk-eXMv239F.css"> <link rel="stylesheet" crossorigin href="/assets/product-risk-CI6qY5U2.css">
<link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css"> <link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css">
<link rel="stylesheet" crossorigin href="/assets/el-input-xaztPnzw.css"> <link rel="stylesheet" crossorigin href="/assets/el-input-xaztPnzw.css">
</head> </head>

View File

@@ -5,10 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>巡店删除 - 数富AI</title> <title>巡店删除 - 数富AI</title>
<script type="module" crossorigin src="/assets/query-asin.js"></script> <script type="module" crossorigin src="/assets/query-asin.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-C66x_2Dh.js"> <link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/zh-cn-CuE9Zzgz.js"> <link rel="modulepreload" crossorigin href="/assets/zh-cn-BbuLS91u.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css"> <link rel="modulepreload" crossorigin href="/assets/categorized-timers-JPA-olTr.js">
<link rel="stylesheet" crossorigin href="/assets/query-asin-Bv7Jtgqa.css"> <link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/query-asin-Bw6BQsRN.css">
<link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css"> <link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css">
<link rel="stylesheet" crossorigin href="/assets/el-input-xaztPnzw.css"> <link rel="stylesheet" crossorigin href="/assets/el-input-xaztPnzw.css">
</head> </head>

View File

@@ -5,12 +5,13 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>匹配店铺 - 数富AI</title> <title>匹配店铺 - 数富AI</title>
<script type="module" crossorigin src="/assets/shop-match.js"></script> <script type="module" crossorigin src="/assets/shop-match.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-C66x_2Dh.js"> <link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/zh-cn-CuE9Zzgz.js"> <link rel="modulepreload" crossorigin href="/assets/zh-cn-BbuLS91u.js">
<link rel="modulepreload" crossorigin href="/assets/listingFilters-BpGOU_pJ.js"> <link rel="modulepreload" crossorigin href="/assets/listingFilters-BpGOU_pJ.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css"> <link rel="modulepreload" crossorigin href="/assets/categorized-timers-JPA-olTr.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/listingFilters-CK58rX4v.css"> <link rel="stylesheet" crossorigin href="/assets/listingFilters-CK58rX4v.css">
<link rel="stylesheet" crossorigin href="/assets/shop-match-BiZP8IGM.css"> <link rel="stylesheet" crossorigin href="/assets/shop-match-CxCKUsqS.css">
<link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css"> <link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css">
<link rel="stylesheet" crossorigin href="/assets/el-input-xaztPnzw.css"> <link rel="stylesheet" crossorigin href="/assets/el-input-xaztPnzw.css">
</head> </head>

View File

@@ -5,10 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>数据拆分 - 数富AI</title> <title>数据拆分 - 数富AI</title>
<script type="module" crossorigin src="/assets/split.js"></script> <script type="module" crossorigin src="/assets/split.js"></script>
<link rel="modulepreload" crossorigin href="/assets/pywebview-C66x_2Dh.js"> <link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/brand-BZije8D7.js"> <link rel="modulepreload" crossorigin href="/assets/brand-CABpTGPu.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css"> <link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/split-BoBVrLdC.css"> <link rel="stylesheet" crossorigin href="/assets/split-Cw6sXhAg.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

1
version.txt Normal file
View File

@@ -0,0 +1 @@
{"version": "1.0.56"}