fix: update frontend

This commit is contained in:
koko
2026-04-28 21:42:30 +08:00
parent cd2b437be5
commit 1d9d138423
58 changed files with 462 additions and 37 deletions

321
ts.py Normal file
View 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()