fix: update frontend
This commit is contained in:
BIN
__pycache__/ts.cpython-39.pyc
Normal file
BIN
__pycache__/ts.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/amazon/__pycache__/approve.cpython-39.pyc
Normal file
BIN
app/amazon/__pycache__/approve.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/amazon/__pycache__/asin_status.cpython-39.pyc
Normal file
BIN
app/amazon/__pycache__/asin_status.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/amazon/__pycache__/base.cpython-39.pyc
Normal file
BIN
app/amazon/__pycache__/base.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/amazon/__pycache__/del_brand.cpython-39.pyc
Normal file
BIN
app/amazon/__pycache__/del_brand.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/amazon/__pycache__/detail_spider.cpython-39.pyc
Normal file
BIN
app/amazon/__pycache__/detail_spider.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/amazon/__pycache__/main.cpython-39.pyc
Normal file
BIN
app/amazon/__pycache__/main.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/amazon/__pycache__/match_action.cpython-39.pyc
Normal file
BIN
app/amazon/__pycache__/match_action.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/amazon/__pycache__/patrol_delete.cpython-314.pyc
Normal file
BIN
app/amazon/__pycache__/patrol_delete.cpython-314.pyc
Normal file
Binary file not shown.
BIN
app/amazon/__pycache__/patrol_delete.cpython-39.pyc
Normal file
BIN
app/amazon/__pycache__/patrol_delete.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/amazon/__pycache__/price_match.cpython-39.pyc
Normal file
BIN
app/amazon/__pycache__/price_match.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/amazon/__pycache__/tool.cpython-39.pyc
Normal file
BIN
app/amazon/__pycache__/tool.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/blueprints/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
app/blueprints/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/blueprints/__pycache__/admin.cpython-39.pyc
Normal file
BIN
app/blueprints/__pycache__/admin.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/blueprints/__pycache__/auth.cpython-39.pyc
Normal file
BIN
app/blueprints/__pycache__/auth.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/blueprints/__pycache__/brand.cpython-39.pyc
Normal file
BIN
app/blueprints/__pycache__/brand.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/blueprints/__pycache__/communication.cpython-39.pyc
Normal file
BIN
app/blueprints/__pycache__/communication.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/blueprints/__pycache__/image.cpython-39.pyc
Normal file
BIN
app/blueprints/__pycache__/image.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/blueprints/__pycache__/main.cpython-39.pyc
Normal file
BIN
app/blueprints/__pycache__/main.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/brand_spider/__pycache__/main.cpython-39.pyc
Normal file
BIN
app/brand_spider/__pycache__/main.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/brand_spider/__pycache__/web_dec.cpython-39.pyc
Normal file
BIN
app/brand_spider/__pycache__/web_dec.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/tests/__pycache__/conftest.cpython-39-pytest-8.4.2.pyc
Normal file
BIN
app/tests/__pycache__/conftest.cpython-39-pytest-8.4.2.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
app/tests/__pycache__/test_patrol_delete.cpython-39.pyc
Normal file
BIN
app/tests/__pycache__/test_patrol_delete.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/tool/__pycache__/devices.cpython-39.pyc
Normal file
BIN
app/tool/__pycache__/devices.cpython-39.pyc
Normal file
Binary file not shown.
@@ -785,24 +785,24 @@
|
||||
else if (status === 'cancelled') showToast('已取消');
|
||||
}
|
||||
|
||||
function verifyTerminalTaskStatus(taskId, expectedStatus) {
|
||||
return fetch('/api/brand/tasks/' + taskId, {
|
||||
credentials: 'include',
|
||||
headers: withUidHeaders({ 'X-Requested-With': 'XMLHttpRequest' })
|
||||
})
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(res) {
|
||||
if (!res.success || !res.task) return null;
|
||||
var actualStatus = (res.task.status || '').toLowerCase();
|
||||
if (actualStatus === 'success' || actualStatus === 'failed' || actualStatus === 'cancelled') {
|
||||
return actualStatus;
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.catch(function() { return null; });
|
||||
}
|
||||
|
||||
function pollRunTask(taskId) {
|
||||
function verifyTerminalTaskStatus(taskId, expectedStatus) {
|
||||
return fetch('/api/brand/tasks/' + taskId, {
|
||||
credentials: 'include',
|
||||
headers: withUidHeaders({ 'X-Requested-With': 'XMLHttpRequest' })
|
||||
})
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(res) {
|
||||
if (!res.success || !res.task) return null;
|
||||
var actualStatus = (res.task.status || '').toLowerCase();
|
||||
if (actualStatus === 'success' || actualStatus === 'failed' || actualStatus === 'cancelled') {
|
||||
return actualStatus;
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.catch(function() { return null; });
|
||||
}
|
||||
|
||||
function pollRunTask(taskId) {
|
||||
pollTaskId = taskId;
|
||||
var runProgressFill = document.getElementById('runProgressFill');
|
||||
var runProgressText = document.getElementById('runProgressText');
|
||||
@@ -865,18 +865,18 @@
|
||||
break;
|
||||
}
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
if (terminalStatus) {
|
||||
var verifiedStatus = await verifyTerminalTaskStatus(taskId, terminalStatus);
|
||||
if (verifiedStatus) {
|
||||
try { runTaskEventAbortController.abort(); } catch (e2) {}
|
||||
runTaskEventAbortController = null;
|
||||
onRunTaskFinished(verifiedStatus);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (terminalStatus) {
|
||||
var verifiedStatus = await verifyTerminalTaskStatus(taskId, terminalStatus);
|
||||
if (verifiedStatus) {
|
||||
try { runTaskEventAbortController.abort(); } catch (e2) {}
|
||||
runTaskEventAbortController = null;
|
||||
onRunTaskFinished(verifiedStatus);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {}
|
||||
})();
|
||||
|
||||
@@ -938,7 +938,7 @@
|
||||
});
|
||||
}
|
||||
tick();
|
||||
pollTimer = setInterval(tick, 3000);
|
||||
pollTimer = setInterval(tick, 3000);
|
||||
}
|
||||
|
||||
document.getElementById('btnRun').onclick = function() {
|
||||
@@ -1148,11 +1148,11 @@
|
||||
});
|
||||
|
||||
loadTasks();
|
||||
setInterval(function() {
|
||||
if (cachedTasks.some(function(t) { return (t.status || '').toLowerCase() === 'running'; })) {
|
||||
loadTasks();
|
||||
}
|
||||
}, 3000);
|
||||
setInterval(function() {
|
||||
if (cachedTasks.some(function(t) { return (t.status || '').toLowerCase() === 'running'; })) {
|
||||
loadTasks();
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
if (window.addEventListener) {
|
||||
window.addEventListener('pywebviewready', function() {
|
||||
|
||||
17
new_web_source/appearance-patent.html
Normal file
17
new_web_source/appearance-patent.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<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="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
1
new_web_source/assets/appearance-patent-BPCrG75P.css
Normal file
1
new_web_source/assets/appearance-patent-BPCrG75P.css
Normal file
@@ -0,0 +1 @@
|
||||
.module-page[data-v-d71413c4]{min-height:100vh;background:#1a1a1a}.main-content[data-v-d71413c4]{display:flex;height:calc(100vh - 56px);min-height:calc(100vh - 56px)}.left-panel[data-v-d71413c4]{width:400px;background:#1e1e1e;padding:20px;overflow-y:auto;border-right:1px solid #2a2a2a}.right-panel[data-v-d71413c4]{flex:1;min-width:0;background:#1a1a1a;display:flex;flex-direction:column}.section-title[data-v-d71413c4],.subsection-title[data-v-d71413c4]{font-size:13px;color:#bbb;margin-bottom:10px}.upload-zone[data-v-d71413c4]{border:1px dashed #3a3a3a;border-radius:10px;padding:18px;background:#252525;margin-bottom:18px}.hint[data-v-d71413c4],.loading-msg[data-v-d71413c4],.files[data-v-d71413c4],.muted[data-v-d71413c4]{color:#888;font-size:12px;line-height:1.5}.link[data-v-d71413c4]{color:#6ea8fe;text-decoration:none}.link[data-v-d71413c4]:hover{color:#9fc5ff}.btns[data-v-d71413c4],.run-row[data-v-d71413c4]{display:flex;gap:10px;flex-wrap:wrap}.opt-btn[data-v-d71413c4],.btn-run[data-v-d71413c4],.btn-delete[data-v-d71413c4],.download[data-v-d71413c4]{border:none;cursor:pointer;border-radius:7px}.opt-btn[data-v-d71413c4]{padding:8px 14px;color:#ccc;background:#2a2a2a;border:1px solid #3a3a3a}.btn-run[data-v-d71413c4]{padding:10px 18px;color:#fff;background:#3498db;font-weight:600}.btn-queue[data-v-d71413c4]{background:#27ae60}.btn-run[data-v-d71413c4]:disabled{opacity:.55;cursor:not-allowed}.selected-files[data-v-d71413c4]{margin-top:14px;color:#999;font-size:12px;word-break:break-all}.selected-files span[data-v-d71413c4]{display:block;margin:4px 0}.prompt-card[data-v-d71413c4]{margin-bottom:18px}.prompt-input[data-v-d71413c4]{width:100%;box-sizing:border-box;resize:vertical;min-height:180px;padding:10px 12px;border:1px solid #333;border-radius:8px;background:#202020;color:#d8d8d8;font-size:12px;line-height:1.6;outline:none}.prompt-input[data-v-d71413c4]:focus{border-color:#3498db}.prompt-default-label[data-v-d71413c4]{margin-top:10px;color:#8d8d8d;font-size:12px}.prompt-preview[data-v-d71413c4]{margin-top:10px;padding:12px;border:1px solid #2a2a2a;border-radius:8px;background:#202020;color:#9ea7b3;font-size:12px;line-height:1.6;white-space:pre-wrap}.parse-card[data-v-d71413c4],.queue-payload[data-v-d71413c4]{margin-top:14px;padding:12px;border:1px solid #2a2a2a;border-radius:8px;background:#202020;color:#b8c1cc;font-size:12px}.queue-payload[data-v-d71413c4]{max-height:220px;overflow:auto;color:#8fd3ff;white-space:pre-wrap}.panel-header[data-v-d71413c4]{padding:16px 20px;border-bottom:1px solid #2a2a2a;font-size:15px;font-weight:600;color:#ddd}.task-list-wrap[data-v-d71413c4]{flex:1;padding:16px 20px;overflow:auto}.clean-result-summary[data-v-d71413c4]{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin-bottom:16px}.summary-card[data-v-d71413c4]{padding:14px 16px;border:1px solid #2a2a2a;border-radius:8px;background:#1e1e1e}.summary-card strong[data-v-d71413c4]{display:block;margin-top:8px;color:#eaf4ff;font-size:22px}.summary-label[data-v-d71413c4]{color:#8d8d8d;font-size:12px}.result-list-wrap[data-v-d71413c4]{border:1px solid #2a2a2a;border-radius:8px;background:#1e1e1e;min-height:180px;margin:0 0 16px}.result-list-header[data-v-d71413c4]{display:flex;justify-content:space-between;padding:12px 16px;border-bottom:1px solid #2a2a2a;color:#ddd;font-size:14px}.empty-tasks[data-v-d71413c4]{color:#666;font-size:13px;padding:18px;text-align:center}.result-table[data-v-d71413c4]{--el-table-bg-color: #222;--el-table-tr-bg-color: #222;--el-table-header-bg-color: #2a2a2a;--el-table-text-color: #ccc;--el-table-border-color: #333}.task-list[data-v-d71413c4]{list-style:none;margin:0;padding:12px}.task-item[data-v-d71413c4]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:12px 14px;border:1px solid #2a2a2a;border-radius:8px;margin-bottom:8px;background:#222}.left[data-v-d71413c4]{flex:1;min-width:0}.id[data-v-d71413c4]{color:#e0e0e0;font-size:13px;font-weight:600}.task-right[data-v-d71413c4]{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.status[data-v-d71413c4]{padding:4px 10px;border-radius:6px;font-size:12px}.status.success[data-v-d71413c4]{background:#2ecc712e;color:#2ecc71}.status.failed[data-v-d71413c4]{background:#e74c3c2e;color:#ff6b6b}.status.running[data-v-d71413c4]{background:#3498db2e;color:#3498db}.result-hint[data-v-d71413c4]{margin-top:6px;color:#e0b96d}.download[data-v-d71413c4]{padding:6px 10px;color:#d6ecff;background:#3498db2e}.btn-delete[data-v-d71413c4]{padding:6px 10px;color:#ff8f8f;background:#e74c3c1f}@media(max-width:1100px){.main-content[data-v-d71413c4]{flex-direction:column;height:auto}.left-panel[data-v-d71413c4]{width:100%;border-right:none;border-bottom:1px solid #2a2a2a}.clean-result-summary[data-v-d71413c4]{grid-template-columns:repeat(2,minmax(0,1fr))}}
|
||||
6
new_web_source/assets/appearance-patent.js
Normal file
6
new_web_source/assets/appearance-patent.js
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/brand-BZije8D7.js
Normal file
1
new_web_source/assets/brand-BZije8D7.js
Normal file
@@ -0,0 +1 @@
|
||||
import{aZ as r}from"./pywebview-C66x_2Dh.js";const n="";function a(e){return r(`${n}/api/brand/expand-folder-recursive`,{folder:e})}export{a as e};
|
||||
1
new_web_source/assets/convert-BKSNvX8i.css
Normal file
1
new_web_source/assets/convert-BKSNvX8i.css
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/convert.js
Normal file
1
new_web_source/assets/convert.js
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/dedupe-DNlVfFj-.css
Normal file
1
new_web_source/assets/dedupe-DNlVfFj-.css
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/dedupe.js
Normal file
1
new_web_source/assets/dedupe.js
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/delete-brand-BP3XWKAC.css
Normal file
1
new_web_source/assets/delete-brand-BP3XWKAC.css
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/delete-brand.js
Normal file
1
new_web_source/assets/delete-brand.js
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/el-input-xaztPnzw.css
Normal file
1
new_web_source/assets/el-input-xaztPnzw.css
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/el-table-column-Cy4YJvw0.css
Normal file
1
new_web_source/assets/el-table-column-Cy4YJvw0.css
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/listingFilters-BpGOU_pJ.js
Normal file
1
new_web_source/assets/listingFilters-BpGOU_pJ.js
Normal file
@@ -0,0 +1 @@
|
||||
const e=[{value:"SearchSuppressed",label:"在搜索结果中禁止显示"},{value:"ApprovalRequired",label:"需要批准"},{value:"Active",label:"在售"},{value:"DetailPageRemoved",label:"详情页面已删除"}];export{e as L};
|
||||
1
new_web_source/assets/listingFilters-CK58rX4v.css
Normal file
1
new_web_source/assets/listingFilters-CK58rX4v.css
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/patrol-delete-CSekhzSS.css
Normal file
1
new_web_source/assets/patrol-delete-CSekhzSS.css
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/patrol-delete.js
Normal file
1
new_web_source/assets/patrol-delete.js
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/price-track-z8RU_FlW.css
Normal file
1
new_web_source/assets/price-track-z8RU_FlW.css
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/price-track.js
Normal file
1
new_web_source/assets/price-track.js
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/product-risk-eXMv239F.css
Normal file
1
new_web_source/assets/product-risk-eXMv239F.css
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/product-risk.js
Normal file
1
new_web_source/assets/product-risk.js
Normal file
File diff suppressed because one or more lines are too long
55
new_web_source/assets/pywebview-C66x_2Dh.js
Normal file
55
new_web_source/assets/pywebview-C66x_2Dh.js
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/pywebview-Dp5dN8OO.css
Normal file
1
new_web_source/assets/pywebview-Dp5dN8OO.css
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/query-asin-Bv7Jtgqa.css
Normal file
1
new_web_source/assets/query-asin-Bv7Jtgqa.css
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/query-asin.js
Normal file
1
new_web_source/assets/query-asin.js
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/shop-match-BiZP8IGM.css
Normal file
1
new_web_source/assets/shop-match-BiZP8IGM.css
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/shop-match.js
Normal file
1
new_web_source/assets/shop-match.js
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/split-BoBVrLdC.css
Normal file
1
new_web_source/assets/split-BoBVrLdC.css
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/split.js
Normal file
1
new_web_source/assets/split.js
Normal file
File diff suppressed because one or more lines are too long
1
new_web_source/assets/zh-cn-CuE9Zzgz.js
Normal file
1
new_web_source/assets/zh-cn-CuE9Zzgz.js
Normal file
File diff suppressed because one or more lines are too long
@@ -10,7 +10,7 @@
|
||||
<link rel="modulepreload" crossorigin href="/assets/listingFilters-BpGOU_pJ.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/pywebview-Dp5dN8OO.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/listingFilters-CK58rX4v.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/shop-match-BmHsgsuC.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/shop-match-BiZP8IGM.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/el-table-column-Cy4YJvw0.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/el-input-xaztPnzw.css">
|
||||
</head>
|
||||
|
||||
321
ts.py
Normal file
321
ts.py
Normal file
@@ -0,0 +1,321 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
ROOT_DIR = Path(__file__).resolve().parent
|
||||
APP_DIR = ROOT_DIR / "app"
|
||||
sys.path.insert(0, str(APP_DIR))
|
||||
|
||||
from amazon.main import TaskMonitor # noqa: E402
|
||||
from amazon.patrol_delete import InventoryManage, PatrolDeleteTask # noqa: E402
|
||||
from config import ( # noqa: E402
|
||||
DELETE_BRAND_API_BASE,
|
||||
JAVA_API_BASE,
|
||||
JSON_TASK_QUEUE,
|
||||
ZN_COMPANY,
|
||||
ZN_PASSWORD,
|
||||
ZN_USERNAME,
|
||||
runing_task,
|
||||
)
|
||||
from main import WindowAPI # noqa: E402
|
||||
|
||||
|
||||
SHOP_NAME = "郭亚芳"
|
||||
USER_ID = 1
|
||||
COUNTRIES = [item.strip() for item in os.environ.get("PATROL_COUNTRIES", "德国,西班牙,意大利").split(",") if item.strip()]
|
||||
TS_MODE = os.environ.get("TS_MODE", "full").strip().lower()
|
||||
|
||||
|
||||
class EventSlot:
|
||||
def __iadd__(self, handler):
|
||||
return self
|
||||
|
||||
|
||||
class DummyWindow:
|
||||
def __init__(self):
|
||||
self.events = SimpleNamespace(maximized=EventSlot(), restored=EventSlot())
|
||||
|
||||
|
||||
def log(message, payload=None):
|
||||
print(f"[ts] {message}", flush=True)
|
||||
if payload is not None:
|
||||
print(json.dumps(payload, ensure_ascii=False, indent=2), flush=True)
|
||||
|
||||
|
||||
def unwrap(response):
|
||||
log(f"HTTP {response.request.method} {response.url} -> {response.status_code}")
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
if not data.get("success"):
|
||||
raise RuntimeError(data.get("message") or data.get("error") or response.text)
|
||||
return data.get("data")
|
||||
|
||||
|
||||
def get_match_item():
|
||||
data = unwrap(
|
||||
requests.post(
|
||||
f"{JAVA_API_BASE}/api/patrol-delete/match-shops",
|
||||
json={"user_id": USER_ID, "shop_names": [SHOP_NAME]},
|
||||
timeout=40,
|
||||
)
|
||||
)
|
||||
items = data.get("items") or []
|
||||
if not items:
|
||||
raise RuntimeError("match-shops did not return any items")
|
||||
|
||||
item = items[0]
|
||||
log("match result", item)
|
||||
if not item.get("matched"):
|
||||
raise RuntimeError(f"shop is not matched: {item}")
|
||||
return item
|
||||
|
||||
|
||||
def create_java_task(match_item):
|
||||
country_sections = [
|
||||
{
|
||||
"country": country,
|
||||
"rows": [
|
||||
{
|
||||
"status": "全部",
|
||||
"quantity": "",
|
||||
"deleteQuantity": "",
|
||||
"processStatus": "",
|
||||
}
|
||||
],
|
||||
}
|
||||
for country in COUNTRIES
|
||||
]
|
||||
cart_ratios = [{"country": country, "ratio": ""} for country in COUNTRIES]
|
||||
task_item = {
|
||||
"shopName": match_item.get("shopName") or SHOP_NAME,
|
||||
"matched": bool(match_item.get("matched")),
|
||||
"shopId": match_item.get("shopId"),
|
||||
"platform": match_item.get("platform"),
|
||||
"companyName": match_item.get("companyName"),
|
||||
"matchStatus": match_item.get("matchStatus"),
|
||||
"matchMessage": match_item.get("matchMessage"),
|
||||
"countrySections": country_sections,
|
||||
"cartRatios": cart_ratios,
|
||||
}
|
||||
data = unwrap(
|
||||
requests.post(
|
||||
f"{JAVA_API_BASE}/api/patrol-delete/tasks",
|
||||
json={"user_id": USER_ID, "items": [task_item]},
|
||||
timeout=40,
|
||||
)
|
||||
)
|
||||
log("created task", data)
|
||||
return data
|
||||
|
||||
|
||||
def build_queue_payload(created_task):
|
||||
task_id = created_task["taskId"]
|
||||
created_item = (created_task.get("items") or [])[0]
|
||||
sections = created_item.get("countrySections") or []
|
||||
ratios = created_item.get("cartRatios") or []
|
||||
payload = {
|
||||
"type": "patrol-delete-run",
|
||||
"ts": int(time.time() * 1000),
|
||||
"data": {
|
||||
"taskId": task_id,
|
||||
"user_id": USER_ID,
|
||||
"source": "ts-real-patrol-delete",
|
||||
"items": [
|
||||
{
|
||||
"shopName": created_item.get("shopName") or SHOP_NAME,
|
||||
"shopId": created_item.get("shopId"),
|
||||
"platform": created_item.get("platform"),
|
||||
"companyName": created_item.get("companyName"),
|
||||
"matched": created_item.get("matched"),
|
||||
"matchStatus": created_item.get("matchStatus"),
|
||||
"matchMessage": created_item.get("matchMessage"),
|
||||
}
|
||||
],
|
||||
"template_rows": [
|
||||
{
|
||||
"shopName": created_item.get("shopName") or SHOP_NAME,
|
||||
"countries": [
|
||||
{
|
||||
"country": section.get("country"),
|
||||
"status": (section.get("rows") or [{}])[0].get("status", ""),
|
||||
"quantity": (section.get("rows") or [{}])[0].get("quantity", ""),
|
||||
"deleteQuantity": (section.get("rows") or [{}])[0].get("deleteQuantity", ""),
|
||||
"processStatus": (section.get("rows") or [{}])[0].get("processStatus", ""),
|
||||
}
|
||||
for section in sections
|
||||
],
|
||||
"cartRatios": ratios,
|
||||
}
|
||||
],
|
||||
"country_sections": sections,
|
||||
"cart_ratios": ratios,
|
||||
},
|
||||
}
|
||||
log("queue payload", payload)
|
||||
return payload
|
||||
|
||||
|
||||
def make_monitor_without_startup_kill():
|
||||
monitor = object.__new__(TaskMonitor)
|
||||
monitor.running = True
|
||||
monitor.user_info = {
|
||||
"company": ZN_COMPANY,
|
||||
"username": ZN_USERNAME,
|
||||
"password": ZN_PASSWORD,
|
||||
}
|
||||
monitor.chunk_index = 1
|
||||
monitor.max_workers = 1
|
||||
monitor.executor = None
|
||||
return monitor
|
||||
|
||||
|
||||
def poll_java_task(task_id):
|
||||
for _ in range(60):
|
||||
try:
|
||||
data = unwrap(
|
||||
requests.post(
|
||||
f"{JAVA_API_BASE}/api/patrol-delete/tasks/progress/batch",
|
||||
json={"taskIds": [task_id]},
|
||||
timeout=40,
|
||||
)
|
||||
)
|
||||
log("java progress", data)
|
||||
items = data.get("items") or []
|
||||
if items and items[0].get("taskStatus") in {"SUCCESS", "FAILED", "COMPLETED"}:
|
||||
return items[0]
|
||||
except Exception as exc:
|
||||
log(f"java progress poll failed: {exc}")
|
||||
time.sleep(5)
|
||||
return None
|
||||
|
||||
|
||||
def drain_queue():
|
||||
while True:
|
||||
try:
|
||||
JSON_TASK_QUEUE.get_nowait()
|
||||
except Exception:
|
||||
return
|
||||
|
||||
|
||||
def make_user_info(company_name=None):
|
||||
return {
|
||||
"company": company_name or ZN_COMPANY,
|
||||
"username": ZN_USERNAME,
|
||||
"password": ZN_PASSWORD,
|
||||
}
|
||||
|
||||
|
||||
def complete_draft_payload_rows(tags):
|
||||
rows = []
|
||||
for item in tags:
|
||||
rows.append(
|
||||
{
|
||||
"status": "补全草稿",
|
||||
"tag": item.get("tag", ""),
|
||||
"type": "completeDraft",
|
||||
"quantity": str(item.get("quantity") if item.get("quantity") is not None else ""),
|
||||
"deleteQuantity": str(item.get("quantity") if item.get("quantity") is not None else ""),
|
||||
"processStatus": "已完成",
|
||||
"raw_text": item.get("raw_text", ""),
|
||||
}
|
||||
)
|
||||
return rows
|
||||
|
||||
|
||||
def run_complete_draft_real_browser():
|
||||
log("starting real complete-draft read test")
|
||||
log("scope", {"shop": SHOP_NAME, "countries": COUNTRIES, "user_id": USER_ID})
|
||||
match_item = get_match_item()
|
||||
driver = InventoryManage(make_user_info(match_item.get("companyName")))
|
||||
try:
|
||||
browser = driver.open_shop(match_item.get("shopName") or SHOP_NAME)
|
||||
if not browser or browser == "店铺不存在":
|
||||
raise RuntimeError(f"open shop failed: {browser}")
|
||||
if driver.need_login():
|
||||
raise RuntimeError("shop requires login; complete-draft read test cannot continue safely")
|
||||
|
||||
normalized_sections = []
|
||||
for country in COUNTRIES:
|
||||
log(f"switching country for complete-draft read: {country}")
|
||||
if not driver.switch_to_country(country):
|
||||
raise RuntimeError(f"switch country failed: {country}")
|
||||
tags = driver.get_complete_draft_quick_view_tags(match_item.get("shopName") or SHOP_NAME, country)
|
||||
payload_rows = complete_draft_payload_rows(tags)
|
||||
normalized = PatrolDeleteTask._normalize_country_sections_for_result(
|
||||
[{"country": country, "rows": payload_rows}]
|
||||
)[0]
|
||||
normalized_sections.append(normalized)
|
||||
log(
|
||||
"complete draft country result",
|
||||
{
|
||||
"country": country,
|
||||
"rawTags": tags,
|
||||
"payloadRowsBeforeNormalize": payload_rows,
|
||||
"normalizedForSubmit": normalized,
|
||||
},
|
||||
)
|
||||
|
||||
log("complete draft normalized sections", normalized_sections)
|
||||
finally:
|
||||
try:
|
||||
driver.close_store()
|
||||
except Exception as exc:
|
||||
log(f"close store failed: {exc}")
|
||||
|
||||
|
||||
def main():
|
||||
if TS_MODE == "complete-draft":
|
||||
run_complete_draft_real_browser()
|
||||
return
|
||||
|
||||
log("starting real patrol-delete automation")
|
||||
log("scope", {"shop": SHOP_NAME, "countries": COUNTRIES, "user_id": USER_ID})
|
||||
log("java api base", {"JAVA_API_BASE": JAVA_API_BASE, "DELETE_BRAND_API_BASE": DELETE_BRAND_API_BASE})
|
||||
log("ziniao env", {"company": bool(ZN_COMPANY), "username": bool(ZN_USERNAME), "password": bool(ZN_PASSWORD)})
|
||||
|
||||
drain_queue()
|
||||
match_item = get_match_item()
|
||||
created_task = create_java_task(match_item)
|
||||
task_id = created_task["taskId"]
|
||||
payload = build_queue_payload(created_task)
|
||||
|
||||
monitor = make_monitor_without_startup_kill()
|
||||
monitor_thread = threading.Thread(target=monitor.start, daemon=True)
|
||||
monitor_thread.start()
|
||||
time.sleep(0.5)
|
||||
|
||||
enqueue_result = WindowAPI(DummyWindow()).enqueue_json(payload)
|
||||
log("enqueue result", enqueue_result)
|
||||
if not enqueue_result.get("success"):
|
||||
raise RuntimeError(f"enqueue failed: {enqueue_result}")
|
||||
|
||||
deadline = time.time() + 60 * 45
|
||||
last_status = None
|
||||
while time.time() < deadline:
|
||||
state = runing_task.get(task_id)
|
||||
if state and state != last_status:
|
||||
log("python task state", state)
|
||||
last_status = dict(state)
|
||||
if state and state.get("status") in {"completed", "failed", "stopped"}:
|
||||
break
|
||||
time.sleep(5)
|
||||
|
||||
monitor.running = False
|
||||
JSON_TASK_QUEUE.put({"type": "__stop__"})
|
||||
monitor_thread.join(timeout=10)
|
||||
|
||||
log("python final state", runing_task.get(task_id))
|
||||
final_java = poll_java_task(task_id)
|
||||
log("java final", final_java)
|
||||
log("finished", {"taskId": task_id})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user