feat: align collect filters with workflow tabs

This commit is contained in:
chengma
2026-07-02 10:39:29 +08:00
parent b622925d74
commit 820612c3ab
5 changed files with 267 additions and 13 deletions
+109 -6
View File
@@ -2282,6 +2282,16 @@ if QT_IMPORT_ERROR is None:
class CollectTab(QWidget):
"""Tab 1: import Excel files and list imported tasks."""
STATUS_FILTERS = [
("全部状态", "all"),
("待采集", "to_collect"),
("已采集", "collected"),
("已生成", "generated"),
("已更新", "applied"),
("失败", "failed"),
("略过", "skipped"),
]
def __init__(
self,
parent=None,
@@ -2314,6 +2324,15 @@ if QT_IMPORT_ERROR is None:
self.stop_collect_button.setEnabled(False)
self.batch_filter = QComboBox()
self.batch_filter.setObjectName("collectBatchFilter")
self.shop_filter = QComboBox()
self.shop_filter.setObjectName("collectShopFilter")
self.item_filter = QLineEdit()
self.item_filter.setObjectName("collectItemFilter")
self.item_filter.setPlaceholderText("商品ID")
self.status_filter = QComboBox()
self.status_filter.setObjectName("collectStatusFilter")
for label, value in self.STATUS_FILTERS:
self.status_filter.addItem(label, value)
self.delete_batch_button = QPushButton("删除批次")
self.delete_batch_button.setObjectName("deleteBatchButton")
self.delete_batch_button.setStyleSheet(_danger_outline_button_style("deleteBatchButton"))
@@ -2322,14 +2341,22 @@ if QT_IMPORT_ERROR is None:
toolbar = QHBoxLayout()
toolbar.addWidget(self.import_button)
toolbar.addWidget(self.refresh_button)
toolbar.addWidget(QLabel("批次"))
toolbar.addWidget(self.batch_filter, 2)
toolbar.addWidget(self.delete_batch_button)
toolbar.addWidget(self.collect_button)
toolbar.addWidget(self.stop_collect_button)
toolbar.addWidget(self.write_back_button)
toolbar.addStretch(1)
filter_layout = QHBoxLayout()
filter_layout.addWidget(QLabel("批次"))
filter_layout.addWidget(self.batch_filter, 2)
filter_layout.addWidget(QLabel("店铺"))
filter_layout.addWidget(self.shop_filter, 1)
filter_layout.addWidget(QLabel("商品ID"))
filter_layout.addWidget(self.item_filter, 1)
filter_layout.addWidget(QLabel("状态"))
filter_layout.addWidget(self.status_filter, 1)
filter_layout.addWidget(self.delete_batch_button)
self.summary_label = QLabel("未导入任务")
self.summary_label.setTextFormat(Qt.RichText)
self.batch_progress_label = _build_batch_progress_overview("collectBatchProgressOverview")
@@ -2371,6 +2398,7 @@ if QT_IMPORT_ERROR is None:
layout = QVBoxLayout(self)
layout.setContentsMargins(18, 18, 18, 18)
layout.addLayout(toolbar)
layout.addLayout(filter_layout)
layout.addLayout(summary_layout)
layout.addWidget(self.match_detail_label)
layout.addWidget(self.batch_progress_label)
@@ -2383,6 +2411,9 @@ if QT_IMPORT_ERROR is None:
self.import_button.clicked.connect(self.import_excel)
self.refresh_button.clicked.connect(self.refresh_tasks)
self.batch_filter.currentIndexChanged.connect(self.refresh_tasks)
self.shop_filter.currentIndexChanged.connect(self.refresh_tasks)
self.item_filter.textChanged.connect(self.refresh_tasks)
self.status_filter.currentIndexChanged.connect(self.refresh_tasks)
self.delete_batch_button.clicked.connect(self.delete_current_batch)
self.collect_button.clicked.connect(self.collect_old_data)
self.stop_collect_button.clicked.connect(self.stop_collect)
@@ -2576,6 +2607,9 @@ if QT_IMPORT_ERROR is None:
db.init_db(self.db_path)
batches = db.list_batches(path=self.db_path)
selected_batch = self.batch_filter.currentData()
selected_shop = self.shop_filter.currentData()
selected_status = self.status_filter.currentData() or "all"
item_query = self.item_filter.text().strip()
if self.current_batch_id and self.batch_filter.findData(self.current_batch_id) < 0:
selected_batch = self.current_batch_id
self._populate_batch_filter(batches, selected_batch)
@@ -2583,6 +2617,14 @@ if QT_IMPORT_ERROR is None:
self.current_batch_id = selected_batch
task_rows = db.list_tasks(batch_id=selected_batch, path=self.db_path)
account_rows = accounts.list_accounts(path=self.db_path, config=self.config)
self._populate_shop_filter(task_rows, account_rows, selected_shop)
selected_shop = self.shop_filter.currentData()
filtered_rows = [
task for task in task_rows
if self._matches_shop(task, selected_shop)
and self._matches_item(task, item_query)
and self._matches_status(task, selected_status, account_rows)
]
except Exception as exc:
self.model.set_tasks([], [])
self.empty_label.setText("任务读取失败")
@@ -2590,7 +2632,7 @@ if QT_IMPORT_ERROR is None:
_set_empty_state(self.empty_state_card, self.empty_state_label, self.empty_state_button)
self._set_status(f"任务读取失败:{exc}")
return
self.model.set_tasks(task_rows, account_rows)
self.model.set_tasks(filtered_rows, account_rows)
self._update_summary(task_rows, account_rows)
_set_batch_progress_overview(self.batch_progress_label, task_rows)
self._update_empty_state(task_rows, account_rows)
@@ -2613,6 +2655,58 @@ if QT_IMPORT_ERROR is None:
first_file = os.path.basename(source_files[0]) if source_files else batch.id
return f"{batch.created_at} · {first_file}"
def _populate_shop_filter(self, task_rows, account_rows, selected_shop):
aliases = {str(task.alias).strip() for task in task_rows if str(task.alias).strip()}
previous = selected_shop if selected_shop in aliases else None
account_by_alias = {
str(account.alias).strip(): account
for account in account_rows
if str(account.alias).strip()
}
self.shop_filter.blockSignals(True)
self.shop_filter.clear()
self.shop_filter.addItem("全部店铺", None)
for alias in sorted(aliases):
self.shop_filter.addItem(self._shop_label(alias, account_by_alias), alias)
index = self.shop_filter.findData(previous)
self.shop_filter.setCurrentIndex(index if index >= 0 else 0)
self.shop_filter.blockSignals(False)
def _shop_label(self, alias, account_by_alias):
account = account_by_alias.get(alias)
if account is not None:
return f"{account.account_name} ({alias})"
return alias
def _matches_shop(self, task, selected_shop):
return selected_shop is None or str(task.alias).strip() == selected_shop
def _matches_item(self, task, item_query):
if not item_query:
return True
return item_query in str(getattr(task, "item_id", ""))
def _matches_status(self, task, selected_status, account_rows):
if selected_status in (None, "all"):
return True
if selected_status == "to_collect":
return task.stage == "imported" and task.status in {"pending", "success"}
if selected_status in {"collected", "generated", "applied"}:
return task.stage == selected_status
if selected_status == "failed":
return task.status == "failed"
if selected_status == "skipped":
return task.status == "skipped" or self._is_unmatched_task(task, account_rows)
return True
def _is_unmatched_task(self, task, account_rows):
aliases = {
str(account.alias).strip()
for account in account_rows
if str(account.alias).strip()
}
return str(task.alias).strip() not in aliases
def _selected_batch_id(self):
return self.batch_filter.currentData()
@@ -2670,7 +2764,7 @@ if QT_IMPORT_ERROR is None:
QMessageBox.information(self, "删除批次", message)
def collect_old_data(self, checked=False):
tasks = list(self.model.all_tasks)
tasks = list(self.model.tasks)
if not tasks:
self._set_status("没有可采集任务")
return
@@ -2756,6 +2850,9 @@ if QT_IMPORT_ERROR is None:
self.write_back_button.setEnabled(not running)
self.stop_collect_button.setEnabled(running)
self.batch_filter.setEnabled(not running)
self.shop_filter.setEnabled(not running)
self.item_filter.setEnabled(not running)
self.status_filter.setEnabled(not running)
self._update_delete_batch_button()
def _set_write_back_running(self, running):
@@ -2764,6 +2861,9 @@ if QT_IMPORT_ERROR is None:
self.collect_button.setEnabled(not running)
self.write_back_button.setEnabled(not running)
self.batch_filter.setEnabled(not running)
self.shop_filter.setEnabled(not running)
self.item_filter.setEnabled(not running)
self.status_filter.setEnabled(not running)
self._update_delete_batch_button()
def _forget_collect_thread(self, thread):
@@ -2990,7 +3090,10 @@ if QT_IMPORT_ERROR is None:
self.empty_label.setText("暂无任务")
return
if self.model.rowCount() == 0 and self.model.filter_mode == "unmatched":
self.empty_label.setText("没有未匹配任务")
self.empty_label.setText("当前筛选没有未匹配任务")
return
if self.model.rowCount() == 0:
self.empty_label.setText("当前筛选没有匹配任务")
return
unmatched = self.model.unmatched_count()
self.empty_label.setText(