fix: update patrol delete progress handling

This commit is contained in:
koko
2026-05-02 02:03:49 +08:00
parent 7c2b154c20
commit 1ecce13814
41 changed files with 313 additions and 158 deletions

View File

@@ -1792,6 +1792,10 @@ class PatrolDeleteTask:
f"国家 {country_name} 处理结束success={country_result['success']}"
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:
self.log(f"店铺 {shop_name} 国家处理完成,正在关闭店铺")
@@ -1822,6 +1826,22 @@ class PatrolDeleteTask:
del runing_shop[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]:
error_info = ""
driver: Optional[InventoryManage] = None
@@ -1996,6 +2016,8 @@ class PatrolDeleteTask:
"type": "completeDraft",
"status": PatrolDeleteTask._string_result_field(item.get("tag")),
"quantity": quantity,
"deleteQuantity": "",
"processStatus": "",
}
)
self.log(f"trace_id={trace_id} 国家 {country_name} 补全草稿读取完成: rows={rows}")
@@ -2032,6 +2054,7 @@ class PatrolDeleteTask:
"status": status,
"quantity": InventoryManage._normalize_quantity_text(item.get("quantity")),
"deleteQuantity": str(deleted_count),
"processStatus": "已完成" if deleted_count > 0 else "",
}
)
section = {"country": country_name, "rows": rows} if rows else None
@@ -2116,6 +2139,7 @@ class PatrolDeleteTask:
cart_ratios: Optional[List[Dict[str, Any]]] = None,
error: str = "",
shop_done: bool = False,
heartbeat_only: bool = False,
):
"""回传巡店删除结果到 Java API。"""
from config import DELETE_BRAND_API_BASE
@@ -2130,6 +2154,8 @@ class PatrolDeleteTask:
}
if error:
shop_payload["error"] = error
elif heartbeat_only:
shop_payload["heartbeatOnly"] = True
else:
shop_payload["countrySections"] = self._normalize_country_sections_for_result(country_sections)
shop_payload["cartRatios"] = self._normalize_cart_ratios_for_result(cart_ratios)
@@ -2217,9 +2243,12 @@ class PatrolDeleteTask:
rows = []
for row in section.get("rows") or []:
if cls._is_complete_draft_result_row(row):
delete_quantity = cls._string_result_field(row.get("deleteQuantity"))
normalized_row = {
"status": cls._complete_draft_result_status(row),
"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:
normalized_row = {
@@ -2255,6 +2284,19 @@ class PatrolDeleteTask:
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"
@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
def _replace_complete_draft_rows(
cls,

View File

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

View File

@@ -7,13 +7,13 @@ import json
import sys
import shutil
import os
from amazon.main import TaskMonitor
os.makedirs(cache_path,exist_ok=True)
if not debug:
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.stderr = sys.stdout
from amazon.main import TaskMonitor
import webview
import threading
import time

View File

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

View File

@@ -60,7 +60,12 @@
</el-table>
</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-input-row">
<el-input
@@ -823,13 +828,14 @@ async function refreshActiveTaskProgress(taskIds?: number[]) {
),
);
if (!ids.length) {
return;
return [];
}
const batch = await getPatrolDeleteTaskProgressBatch(ids);
mergeHistoryProgressItems(batch.items || []);
if ((batch.missingTaskIds || []).length) {
await loadHistory();
}
return batch.missingTaskIds || [];
}
function startHistoryPolling() {
@@ -1029,7 +1035,11 @@ async function waitForTaskTerminal(taskId: number) {
if (disposed) return "STOPPED";
if (activeTaskId.value !== taskId) return "DELETED";
try {
await refreshActiveTaskProgress([taskId]);
const missingTaskIds = await refreshActiveTaskProgress([taskId]);
if (missingTaskIds.includes(taskId)) {
clearActiveQueueTask();
return "DELETED";
}
if (activeTaskId.value !== taskId) return "DELETED";
if (transientErrorCount > 0) {
queuePushResult.value = `任务 ${taskId} 后端已恢复,继续等待执行结果...`;
@@ -1236,6 +1246,8 @@ onUnmounted(() => {
.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; }
.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; }
.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; }

View File

@@ -5,10 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>外观专利检测</title>
<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/brand-BZije8D7.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css">
<link rel="stylesheet" crossorigin href="/assets/appearance-patent-BPCrG75P.css">
<link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/brand-CABpTGPu.js">
<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/appearance-patent-TI-osB39.css">
<link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css">
</head>
<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" />
<title>格式转换 - 数富AI</title>
<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/brand-BZije8D7.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css">
<link rel="stylesheet" crossorigin href="/assets/convert-BKSNvX8i.css">
<link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/brand-CABpTGPu.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-BFZO8_3q.css">
<link rel="stylesheet" crossorigin href="/assets/convert-r7MSXq7I.css">
</head>
<body>
<div id="app"></div>

View File

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

View File

@@ -5,10 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>删除品牌 - 数富AI</title>
<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/brand-BZije8D7.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css">
<link rel="stylesheet" crossorigin href="/assets/delete-brand-BP3XWKAC.css">
<link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/brand-CABpTGPu.js">
<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/delete-brand-B5ChOXZY.css">
</head>
<body>
<div id="app"></div>

View File

@@ -5,10 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>巡店删除 - 数富AI</title>
<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/zh-cn-CuE9Zzgz.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css">
<link rel="stylesheet" crossorigin href="/assets/patrol-delete-CSekhzSS.css">
<link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/zh-cn-BbuLS91u.js">
<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/patrol-delete-DyumfGaZ.css">
<link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css">
<link rel="stylesheet" crossorigin href="/assets/el-input-xaztPnzw.css">
</head>

View File

@@ -5,10 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>跟价 - 数富AI</title>
<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/brand-BZije8D7.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css">
<link rel="stylesheet" crossorigin href="/assets/price-track-z8RU_FlW.css">
<link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/brand-CABpTGPu.js">
<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/price-track-DMhhVz4u.css">
<link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css">
<link rel="stylesheet" crossorigin href="/assets/el-input-xaztPnzw.css">
</head>

View File

@@ -5,11 +5,12 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>商品风险解决 - 数富AI</title>
<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="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/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-input-xaztPnzw.css">
</head>

View File

@@ -5,10 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>巡店删除 - 数富AI</title>
<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/zh-cn-CuE9Zzgz.js">
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css">
<link rel="stylesheet" crossorigin href="/assets/query-asin-Bv7Jtgqa.css">
<link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/zh-cn-BbuLS91u.js">
<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/query-asin-Bw6BQsRN.css">
<link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css">
<link rel="stylesheet" crossorigin href="/assets/el-input-xaztPnzw.css">
</head>

View File

@@ -5,12 +5,13 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>匹配店铺 - 数富AI</title>
<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/zh-cn-CuE9Zzgz.js">
<link rel="modulepreload" crossorigin href="/assets/pywebview-BWNiqXug.js">
<link rel="modulepreload" crossorigin href="/assets/zh-cn-BbuLS91u.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/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-input-xaztPnzw.css">
</head>

View File

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

1
version.txt Normal file
View File

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