feat(collect): show per-item collection activity timer
This commit is contained in:
+153
-6
@@ -65,6 +65,7 @@ from app.gui import (
|
||||
)
|
||||
from app.gui import file_manager
|
||||
import app.gui.workers as gui_workers
|
||||
from app.gui.tabs.collect import _format_collect_elapsed
|
||||
from app.gui.tabs.generate import CoverGalleryDialog, OriginalImageDialog
|
||||
from app.gui.main_window import _fit_and_center_window
|
||||
|
||||
@@ -7391,6 +7392,130 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_collect_activity_tracks_step_resets_each_task_and_freezes_on_stop(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
tab = CollectTab(config=self.make_config(temp_dir))
|
||||
self.addCleanup(tab.close)
|
||||
|
||||
self.assertEqual("collectActivityLabel", tab.collect_activity_label.objectName())
|
||||
self.assertTrue(tab.collect_activity_label.isHidden())
|
||||
self.assertEqual("1:01:01", _format_collect_elapsed(3661))
|
||||
|
||||
with mock.patch("app.gui.tabs.collect.time.monotonic", return_value=100.0):
|
||||
tab._start_collect_activity()
|
||||
self.assertTrue(tab._collect_elapsed_timer.isActive())
|
||||
self.assertIn("正在检查账号", tab.collect_activity_label.text())
|
||||
self.assertIn("00:00", tab.collect_activity_label.text())
|
||||
|
||||
with mock.patch("app.gui.tabs.collect.time.monotonic", return_value=105.0):
|
||||
tab._on_collect_activity(
|
||||
{
|
||||
"state": "preflight_started",
|
||||
"total": 2,
|
||||
"step": "preflight",
|
||||
}
|
||||
)
|
||||
self.assertIn("正在检查账号", tab.collect_activity_label.text())
|
||||
self.assertIn("00:05", tab.collect_activity_label.text())
|
||||
|
||||
with mock.patch("app.gui.tabs.collect.time.monotonic", return_value=110.0):
|
||||
tab._on_collect_activity(
|
||||
{
|
||||
"state": "task_started",
|
||||
"index": 1,
|
||||
"total": 2,
|
||||
"task_id": 1,
|
||||
"item_id": "51100639510",
|
||||
"alias": "alias-a",
|
||||
"step": "match_account",
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
"正在采集 1/2 · 匹配账号 · 本条 00:00",
|
||||
tab.collect_activity_label.text(),
|
||||
)
|
||||
|
||||
with mock.patch("app.gui.tabs.collect.time.monotonic", return_value=117.0):
|
||||
tab._on_collect_activity(
|
||||
{
|
||||
"state": "task_step",
|
||||
"index": 1,
|
||||
"total": 2,
|
||||
"task_id": 1,
|
||||
"item_id": "51100639510",
|
||||
"alias": "alias-a",
|
||||
"step": "wait_ready",
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
"正在采集 1/2 · 等待商品页加载 · 本条 00:07",
|
||||
tab.collect_activity_label.text(),
|
||||
)
|
||||
self.assertIn("商品ID:51100639510", tab.collect_activity_label.toolTip())
|
||||
self.assertIn("当前阶段:等待商品页加载", tab.collect_activity_label.toolTip())
|
||||
|
||||
with mock.patch("app.gui.tabs.collect.time.monotonic", return_value=120.0):
|
||||
tab._on_collect_activity(
|
||||
{
|
||||
"state": "task_started",
|
||||
"index": 2,
|
||||
"total": 2,
|
||||
"task_id": 2,
|
||||
"item_id": "51100639511",
|
||||
"alias": "alias-a",
|
||||
"step": "check_login",
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
"正在采集 2/2 · 检查账号登录 · 本条 00:00",
|
||||
tab.collect_activity_label.text(),
|
||||
)
|
||||
|
||||
with mock.patch("app.gui.tabs.collect.time.monotonic", return_value=125.0):
|
||||
tab._collect_stop_requested = True
|
||||
tab._refresh_collect_activity()
|
||||
self.assertEqual("正在停止 · 本条 00:05", tab.collect_activity_label.text())
|
||||
|
||||
with mock.patch("app.gui.tabs.collect.time.monotonic", return_value=130.0):
|
||||
tab._finish_collect_activity("cancelled")
|
||||
self.assertEqual("采集已停止 · 总用时 00:30", tab.collect_activity_label.text())
|
||||
self.assertFalse(tab._collect_elapsed_timer.isActive())
|
||||
|
||||
frozen_text = tab.collect_activity_label.text()
|
||||
with mock.patch("app.gui.tabs.collect.time.monotonic", return_value=999.0):
|
||||
tab._refresh_collect_activity()
|
||||
self.assertEqual(frozen_text, tab.collect_activity_label.text())
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_collect_activity_terminal_states_use_chinese_semantics(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
tab = CollectTab(config=self.make_config(temp_dir))
|
||||
self.addCleanup(tab.close)
|
||||
|
||||
with mock.patch("app.gui.tabs.collect.time.monotonic", return_value=10.0):
|
||||
tab._start_collect_activity()
|
||||
with mock.patch("app.gui.tabs.collect.time.monotonic", return_value=15.0):
|
||||
tab._finish_collect_activity("blocked")
|
||||
self.assertEqual("采集未开始 · 检查未通过", tab.collect_activity_label.text())
|
||||
self.assertFalse(tab._collect_elapsed_timer.isActive())
|
||||
|
||||
with mock.patch("app.gui.tabs.collect.time.monotonic", return_value=20.0):
|
||||
tab._start_collect_activity()
|
||||
with mock.patch("app.gui.tabs.collect.time.monotonic", return_value=25.0):
|
||||
tab._finish_collect_activity("error", {"error": "后台线程异常"})
|
||||
self.assertEqual("采集已结束 · 请查看运行日志", tab.collect_activity_label.text())
|
||||
self.assertEqual("采集异常结束,请查看下方采集运行日志", tab.collect_activity_label.toolTip())
|
||||
|
||||
with mock.patch("app.gui.tabs.collect.time.monotonic", return_value=30.0):
|
||||
tab._start_collect_activity()
|
||||
with mock.patch("app.gui.tabs.collect.time.monotonic", return_value=40.0):
|
||||
tab._finish_collect_activity("finished")
|
||||
self.assertEqual("采集完成 · 总用时 00:10", tab.collect_activity_label.text())
|
||||
self.assertFalse(tab._collect_elapsed_timer.isActive())
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_collect_tab_soft_deletes_batch_and_refreshes_workflow_tabs(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
@@ -7706,14 +7831,17 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
"old_cover_path": task["old_cover_path"],
|
||||
}
|
||||
|
||||
worker = CollectWorker(
|
||||
tasks,
|
||||
db_path=cfg["db_path"],
|
||||
config=cfg,
|
||||
preflight=False,
|
||||
)
|
||||
activity_events = []
|
||||
worker.activity.connect(activity_events.append)
|
||||
with mock.patch("app.gui.accounts.detect_login", side_effect=fake_login), \
|
||||
mock.patch("app.gui.editor.collect", side_effect=fake_collect) as collect:
|
||||
summary = CollectWorker(
|
||||
tasks,
|
||||
db_path=cfg["db_path"],
|
||||
config=cfg,
|
||||
preflight=False,
|
||||
).execute()
|
||||
summary = worker.execute()
|
||||
|
||||
self.assertTrue(summary["ok"])
|
||||
self.assertEqual(3, summary["total"])
|
||||
@@ -7728,6 +7856,25 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
self.assertEqual([batch_id], summary["batch_ids"])
|
||||
self.assertIsInstance(summary["run_id"], int)
|
||||
collect.assert_called_once()
|
||||
self.assertEqual("preflight_started", activity_events[0]["state"])
|
||||
self.assertEqual(3, activity_events[0]["total"])
|
||||
task_starts = [event for event in activity_events if event["state"] == "task_started"]
|
||||
self.assertEqual([1, 2, 3], [event["index"] for event in task_starts])
|
||||
self.assertEqual(
|
||||
["51100639510", "51100639511", "51100639512"],
|
||||
[event["item_id"] for event in task_starts],
|
||||
)
|
||||
self.assertTrue(
|
||||
any(
|
||||
event["state"] == "task_step" and event.get("step") == "download_cover"
|
||||
for event in activity_events
|
||||
)
|
||||
)
|
||||
task_finishes = [event for event in activity_events if event["state"] == "task_finished"]
|
||||
self.assertEqual(
|
||||
["success", "skipped", "skipped"],
|
||||
[event["result"] for event in task_finishes],
|
||||
)
|
||||
updated = db.list_tasks(batch_id=batch_id, path=cfg["db_path"])
|
||||
by_alias = {task.alias: task for task in updated}
|
||||
self.assertEqual("collected", by_alias["alias-a"].stage)
|
||||
|
||||
Reference in New Issue
Block a user