feat: default workflow batch filters to latest batch
This commit is contained in:
@@ -376,14 +376,20 @@ class ApplyTab(QWidget):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _populate_batch_filter(self, batches, selected_batch):
|
def _populate_batch_filter(self, batches, selected_batch):
|
||||||
previous = selected_batch if selected_batch in {batch.id for batch in batches} else None
|
had_previous_items = self.batch_filter.count() > 0
|
||||||
self.batch_filter.blockSignals(True)
|
self.batch_filter.blockSignals(True)
|
||||||
self.batch_filter.clear()
|
self.batch_filter.clear()
|
||||||
self.batch_filter.addItem("全部批次", None)
|
self.batch_filter.addItem("全部批次", None)
|
||||||
for batch in batches:
|
for batch in batches:
|
||||||
self.batch_filter.addItem(self._batch_label(batch), batch.id)
|
self.batch_filter.addItem(self._batch_label(batch), batch.id)
|
||||||
index = self.batch_filter.findData(previous)
|
self.batch_filter.setCurrentIndex(
|
||||||
self.batch_filter.setCurrentIndex(index if index >= 0 else 0)
|
_batch_filter_current_index(
|
||||||
|
self.batch_filter,
|
||||||
|
batches,
|
||||||
|
selected_batch,
|
||||||
|
had_previous_items,
|
||||||
|
)
|
||||||
|
)
|
||||||
self.batch_filter.blockSignals(False)
|
self.batch_filter.blockSignals(False)
|
||||||
|
|
||||||
def _populate_shop_filter(self, tasks, account_rows, selected_shop):
|
def _populate_shop_filter(self, tasks, account_rows, selected_shop):
|
||||||
|
|||||||
@@ -375,15 +375,20 @@ class CollectTab(QWidget):
|
|||||||
self._update_delete_batch_button()
|
self._update_delete_batch_button()
|
||||||
|
|
||||||
def _populate_batch_filter(self, batches, selected_batch):
|
def _populate_batch_filter(self, batches, selected_batch):
|
||||||
batch_ids = {batch.id for batch in batches}
|
had_previous_items = self.batch_filter.count() > 0
|
||||||
previous = selected_batch if selected_batch in batch_ids else None
|
|
||||||
self.batch_filter.blockSignals(True)
|
self.batch_filter.blockSignals(True)
|
||||||
self.batch_filter.clear()
|
self.batch_filter.clear()
|
||||||
self.batch_filter.addItem("全部批次", None)
|
self.batch_filter.addItem("全部批次", None)
|
||||||
for batch in batches:
|
for batch in batches:
|
||||||
self.batch_filter.addItem(self._batch_label(batch), batch.id)
|
self.batch_filter.addItem(self._batch_label(batch), batch.id)
|
||||||
index = self.batch_filter.findData(previous)
|
self.batch_filter.setCurrentIndex(
|
||||||
self.batch_filter.setCurrentIndex(index if index >= 0 else 0)
|
_batch_filter_current_index(
|
||||||
|
self.batch_filter,
|
||||||
|
batches,
|
||||||
|
selected_batch,
|
||||||
|
had_previous_items,
|
||||||
|
)
|
||||||
|
)
|
||||||
self.batch_filter.blockSignals(False)
|
self.batch_filter.blockSignals(False)
|
||||||
|
|
||||||
def _batch_label(self, batch):
|
def _batch_label(self, batch):
|
||||||
|
|||||||
@@ -1000,14 +1000,20 @@ class GenerateTab(QWidget):
|
|||||||
_set_empty_state(self.empty_state_card, self.empty_state_label, self.empty_state_button)
|
_set_empty_state(self.empty_state_card, self.empty_state_label, self.empty_state_button)
|
||||||
|
|
||||||
def _populate_batch_filter(self, batches, selected_batch):
|
def _populate_batch_filter(self, batches, selected_batch):
|
||||||
previous = selected_batch if selected_batch in {batch.id for batch in batches} else None
|
had_previous_items = self.batch_filter.count() > 0
|
||||||
self.batch_filter.blockSignals(True)
|
self.batch_filter.blockSignals(True)
|
||||||
self.batch_filter.clear()
|
self.batch_filter.clear()
|
||||||
self.batch_filter.addItem("全部批次", None)
|
self.batch_filter.addItem("全部批次", None)
|
||||||
for batch in batches:
|
for batch in batches:
|
||||||
self.batch_filter.addItem(self._batch_label(batch), batch.id)
|
self.batch_filter.addItem(self._batch_label(batch), batch.id)
|
||||||
index = self.batch_filter.findData(previous)
|
self.batch_filter.setCurrentIndex(
|
||||||
self.batch_filter.setCurrentIndex(index if index >= 0 else 0)
|
_batch_filter_current_index(
|
||||||
|
self.batch_filter,
|
||||||
|
batches,
|
||||||
|
selected_batch,
|
||||||
|
had_previous_items,
|
||||||
|
)
|
||||||
|
)
|
||||||
self.batch_filter.blockSignals(False)
|
self.batch_filter.blockSignals(False)
|
||||||
|
|
||||||
def _populate_shop_filter(self, tasks, account_rows, selected_shop):
|
def _populate_shop_filter(self, tasks, account_rows, selected_shop):
|
||||||
|
|||||||
@@ -405,6 +405,19 @@ def _set_batch_progress_overview(label, tasks):
|
|||||||
label.setText(_format_batch_progress(summary) if active else "")
|
label.setText(_format_batch_progress(summary) if active else "")
|
||||||
|
|
||||||
|
|
||||||
|
def _batch_filter_current_index(combo, batches, selected_batch, had_previous_items):
|
||||||
|
batch_ids = {batch.id for batch in batches}
|
||||||
|
if selected_batch in batch_ids:
|
||||||
|
index = combo.findData(selected_batch)
|
||||||
|
if index >= 0:
|
||||||
|
return index
|
||||||
|
if selected_batch is None and had_previous_items:
|
||||||
|
index = combo.findData(None)
|
||||||
|
if index >= 0:
|
||||||
|
return index
|
||||||
|
return 1 if batches else 0
|
||||||
|
|
||||||
|
|
||||||
def _database_path(db_path=None, config=None) -> str:
|
def _database_path(db_path=None, config=None) -> str:
|
||||||
return db_path or appconfig.db_path(config)
|
return db_path or appconfig.db_path(config)
|
||||||
|
|
||||||
|
|||||||
+5
-2
@@ -3,7 +3,7 @@ id: T-550
|
|||||||
title: ①②③ 批次下拉默认选中最新批次
|
title: ①②③ 批次下拉默认选中最新批次
|
||||||
phase: 7
|
phase: 7
|
||||||
deps: [T-523, T-206]
|
deps: [T-523, T-206]
|
||||||
status: TODO
|
status: DONE
|
||||||
created: 2026-07-08
|
created: 2026-07-08
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -41,4 +41,7 @@ created: 2026-07-08
|
|||||||
|
|
||||||
## 执行记录
|
## 执行记录
|
||||||
|
|
||||||
(做完在此记录:改了哪些文件、跑的验证命令与结果、决策)
|
- 2026-07-08:完成 T-550。
|
||||||
|
- 代码:`app/gui/widgets.py` 新增批次下拉默认索引 helper;①`CollectTab`、②`GenerateTab`、③`ApplyTab` 的 `_populate_batch_filter` 改为“有效已选批次优先;用户手动选过全部批次则保留;无有效已记住选择且存在批次时默认选 index 1 最新批次;无批次回退 index 0”。
|
||||||
|
- 测试:`tests/test_gui.py` 新增 ①②③ 批次下拉默认最新批次、无批次回退、已记住批次优先、手动全部批次保留的覆盖;导入测试补充断言 ① 导入后仍自动选中新批次;原②③列表筛选测试显式手动选择「全部批次」,保持原测试目标。
|
||||||
|
- 验证:`py -3.10 -m unittest discover -s tests -p "test_gui.py"` 通过(103 tests);`python -m ruff check app tests main.py` 通过;`py -3.10 -m compileall app main.py` 通过;`git diff --check` 通过;`py -3.10 -m unittest discover -s tests` 通过(253 tests)。
|
||||||
|
|||||||
@@ -86,6 +86,17 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
|||||||
self.assertIsNotNone(value)
|
self.assertIsNotNone(value)
|
||||||
self.assertEqual(color, value.name())
|
self.assertEqual(color, value.name())
|
||||||
|
|
||||||
|
def set_batch_created_at(self, cfg, batch_id, created_at):
|
||||||
|
conn = db.connect(cfg["db_path"])
|
||||||
|
try:
|
||||||
|
with conn:
|
||||||
|
conn.execute(
|
||||||
|
"UPDATE batches SET created_at = ?, updated_at = ? WHERE id = ?",
|
||||||
|
(created_at, created_at, batch_id),
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
def make_fake_message_box(self, selected_label):
|
def make_fake_message_box(self, selected_label):
|
||||||
boxes = []
|
boxes = []
|
||||||
|
|
||||||
@@ -511,6 +522,53 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
|||||||
|
|
||||||
self.assert_removed(temp_dir)
|
self.assert_removed(temp_dir)
|
||||||
|
|
||||||
|
def test_workflow_batch_filters_default_to_latest_batch_and_remember_selection(self):
|
||||||
|
with self.make_temp_dir() as temp_dir:
|
||||||
|
cfg = self.make_config(temp_dir)
|
||||||
|
|
||||||
|
for tab_class in (CollectTab, GenerateTab, ApplyTab):
|
||||||
|
tab = tab_class(config=cfg)
|
||||||
|
self.addCleanup(tab.close)
|
||||||
|
self.assertEqual(0, tab.batch_filter.currentIndex())
|
||||||
|
self.assertIsNone(tab.batch_filter.currentData())
|
||||||
|
|
||||||
|
accounts.create_account("主店", "alias-a", debug_port=9222, config=cfg)
|
||||||
|
older_batch = db.create_batch(["older.xlsx"], path=cfg["db_path"])
|
||||||
|
newer_batch = db.create_batch(["newer.xlsx"], path=cfg["db_path"])
|
||||||
|
self.set_batch_created_at(cfg, older_batch, "2026-07-08T10:00:00")
|
||||||
|
self.set_batch_created_at(cfg, newer_batch, "2026-07-08T11:00:00")
|
||||||
|
for batch_id, item_id in ((older_batch, "1001"), (newer_batch, "2001")):
|
||||||
|
db.insert_tasks(
|
||||||
|
batch_id,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"source_file_abs": os.path.join(temp_dir, f"{item_id}.xlsx"),
|
||||||
|
"source_sheet": "商品",
|
||||||
|
"source_row": 2,
|
||||||
|
"account_name": "Excel主店",
|
||||||
|
"alias": "alias-a",
|
||||||
|
"item_id": item_id,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
path=cfg["db_path"],
|
||||||
|
)
|
||||||
|
|
||||||
|
for tab_class in (CollectTab, GenerateTab, ApplyTab):
|
||||||
|
tab = tab_class(config=cfg)
|
||||||
|
self.addCleanup(tab.close)
|
||||||
|
self.assertEqual(newer_batch, tab.batch_filter.currentData())
|
||||||
|
self.assertEqual(1, tab.batch_filter.currentIndex())
|
||||||
|
|
||||||
|
tab.batch_filter.setCurrentIndex(tab.batch_filter.findData(older_batch))
|
||||||
|
tab.refresh_tasks()
|
||||||
|
self.assertEqual(older_batch, tab.batch_filter.currentData())
|
||||||
|
|
||||||
|
tab.batch_filter.setCurrentIndex(tab.batch_filter.findData(None))
|
||||||
|
tab.refresh_tasks()
|
||||||
|
self.assertIsNone(tab.batch_filter.currentData())
|
||||||
|
|
||||||
|
self.assert_removed(temp_dir)
|
||||||
|
|
||||||
def test_settings_tab_loads_ai_models_and_masks_key_field(self):
|
def test_settings_tab_loads_ai_models_and_masks_key_field(self):
|
||||||
with self.make_temp_dir() as temp_dir:
|
with self.make_temp_dir() as temp_dir:
|
||||||
cfg = self.make_config(temp_dir)
|
cfg = self.make_config(temp_dir)
|
||||||
@@ -2750,6 +2808,7 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
|||||||
|
|
||||||
tab = ApplyTab(config=cfg)
|
tab = ApplyTab(config=cfg)
|
||||||
self.addCleanup(tab.close)
|
self.addCleanup(tab.close)
|
||||||
|
tab.batch_filter.setCurrentIndex(tab.batch_filter.findData(None))
|
||||||
|
|
||||||
self.assertIsInstance(tab.task_table, QTableView)
|
self.assertIsInstance(tab.task_table, QTableView)
|
||||||
self.assertEqual(["店铺", "商品ID", "新标题", "新封面", "阶段", "结果"], tab.model.HEADERS)
|
self.assertEqual(["店铺", "商品ID", "新标题", "新封面", "阶段", "结果"], tab.model.HEADERS)
|
||||||
@@ -3718,6 +3777,7 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
|||||||
|
|
||||||
tab = GenerateTab(config=cfg)
|
tab = GenerateTab(config=cfg)
|
||||||
self.addCleanup(tab.close)
|
self.addCleanup(tab.close)
|
||||||
|
tab.batch_filter.setCurrentIndex(tab.batch_filter.findData(None))
|
||||||
|
|
||||||
self.assertEqual("generateItemFilter", tab.item_filter.objectName())
|
self.assertEqual("generateItemFilter", tab.item_filter.objectName())
|
||||||
self.assertEqual(4, tab.model.rowCount())
|
self.assertEqual(4, tab.model.rowCount())
|
||||||
@@ -4243,9 +4303,11 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
|||||||
statuses = []
|
statuses = []
|
||||||
tab = CollectTab(config=cfg, status_callback=statuses.append)
|
tab = CollectTab(config=cfg, status_callback=statuses.append)
|
||||||
self.addCleanup(tab.close)
|
self.addCleanup(tab.close)
|
||||||
|
created = {}
|
||||||
|
|
||||||
def fake_import(file_paths, path=None):
|
def fake_import(file_paths, path=None):
|
||||||
batch_id = db.create_batch(file_paths, path=path)
|
batch_id = db.create_batch(file_paths, path=path)
|
||||||
|
created["batch_id"] = batch_id
|
||||||
db.insert_tasks(
|
db.insert_tasks(
|
||||||
batch_id,
|
batch_id,
|
||||||
[
|
[
|
||||||
@@ -4290,6 +4352,7 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
|||||||
self.assertIn("匹配1", tab.summary_label.text())
|
self.assertIn("匹配1", tab.summary_label.text())
|
||||||
self.assertEqual("", tab.show_unmatched_button.styleSheet())
|
self.assertEqual("", tab.show_unmatched_button.styleSheet())
|
||||||
self.assertIn("入库1", statuses[-1])
|
self.assertIn("入库1", statuses[-1])
|
||||||
|
self.assertEqual(created["batch_id"], tab.batch_filter.currentData())
|
||||||
|
|
||||||
self.assert_removed(temp_dir)
|
self.assert_removed(temp_dir)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user