feat: add first-run empty state guidance

This commit is contained in:
chengma
2026-07-02 09:57:06 +08:00
parent 9bad70f425
commit d8c3c5d548
5 changed files with 214 additions and 9 deletions
+141 -1
View File
@@ -165,6 +165,35 @@ if QT_IMPORT_ERROR is None:
return QIcon(pixmap)
def _build_empty_state_card(object_name, button_text="前往账号管理"):
card = QWidget()
card.setObjectName(object_name)
card.setStyleSheet(
f"QWidget#{object_name} {{ "
"background: #f6f8fa; border: 1px solid #d0d7de; "
"border-radius: 6px; padding: 10px; "
"}"
)
layout = QHBoxLayout(card)
layout.setContentsMargins(12, 10, 12, 10)
label = QLabel("")
label.setWordWrap(True)
button = QPushButton(button_text)
button.setObjectName(f"{object_name}Button")
button.setVisible(False)
layout.addWidget(label, 1)
layout.addWidget(button)
card.setVisible(False)
return card, label, button
def _set_empty_state(card, label, button, message=None, show_button=False):
active = bool(message)
card.setVisible(active)
label.setText(message or "")
button.setVisible(active and show_button)
def _database_path(db_path=None, config=None) -> str:
return db_path or appconfig.db_path(config)
@@ -696,11 +725,13 @@ if QT_IMPORT_ERROR is None:
status_callback=None,
title_prompt_path=None,
cover_prompts_dir=None,
open_accounts_callback=None,
):
super().__init__(parent)
self.config = appconfig.load_config() if config is None else config
self.db_path = _database_path(db_path, self.config)
self.status_callback = status_callback
self.open_accounts_callback = open_accounts_callback
self.title_prompt_path = title_prompt_path or prompts.TITLE_PROMPT_PATH
self.cover_prompts_dir = cover_prompts_dir or prompts.COVER_PROMPTS_DIR
self.current_cover_template = None
@@ -779,6 +810,13 @@ if QT_IMPORT_ERROR is None:
filter_layout.addWidget(self.refresh_button)
self.summary_label = QLabel("任务 0 条")
(
self.empty_state_card,
self.empty_state_label,
self.empty_state_button,
) = _build_empty_state_card("generateEmptyStateCard")
if self.open_accounts_callback is not None:
self.empty_state_button.clicked.connect(self.open_accounts_callback)
self.task_table = QTableView()
self.model = GenerateTaskTableModel(self.task_table, db_path=self.db_path, status_callback=self._set_status)
self.task_table.setModel(self.model)
@@ -799,6 +837,7 @@ if QT_IMPORT_ERROR is None:
right_layout.setContentsMargins(12, 0, 0, 0)
right_layout.addLayout(filter_layout)
right_layout.addWidget(self.summary_label)
right_layout.addWidget(self.empty_state_card)
right_layout.addWidget(self.task_table, 1)
right_layout.addWidget(QLabel("AI生成运行日志"))
right_layout.addWidget(self.run_log_view)
@@ -1271,12 +1310,42 @@ if QT_IMPORT_ERROR is None:
except Exception as exc:
self.model.set_tasks([], [])
self.summary_label.setText("任务读取失败")
_set_empty_state(self.empty_state_card, self.empty_state_label, self.empty_state_button)
self._set_status(f"AI 生成任务读取失败:{exc}")
return
self.model.set_tasks(filtered_tasks, accounts_rows)
self.summary_label.setText(
f"任务 {len(filtered_tasks)}/{len(batch_tasks)} 条"
)
self._update_empty_state(batch_tasks, filtered_tasks, accounts_rows)
def _update_empty_state(self, batch_tasks, filtered_tasks, account_rows):
if not account_rows:
_set_empty_state(
self.empty_state_card,
self.empty_state_label,
self.empty_state_button,
"第一步:前往『④账号管理』配置并登录账号,再回到②生成标题和封面。",
self.open_accounts_callback is not None,
)
return
if not batch_tasks:
_set_empty_state(
self.empty_state_card,
self.empty_state_label,
self.empty_state_button,
"还没有可生成任务。请先在①导入采集完成旧标题和旧封面采集。",
)
return
if not filtered_tasks:
_set_empty_state(
self.empty_state_card,
self.empty_state_label,
self.empty_state_button,
"当前筛选没有匹配的生成任务,请调整批次、店铺、商品ID或状态筛选。",
)
return
_set_empty_state(self.empty_state_card, self.empty_state_label, self.empty_state_button)
def _populate_batch_filter(self, batches, selected_batch):
previous = selected_batch if selected_batch in {batch.id for batch in batches} else None
@@ -1403,6 +1472,13 @@ if QT_IMPORT_ERROR is None:
self.summary_label = QLabel("任务 0 条")
self.risk_label = QLabel("可先点击「检查本轮更新」确认当前筛选范围;点击「开始更新」后会再次确认并按批提交线上。")
(
self.empty_state_card,
self.empty_state_label,
self.empty_state_button,
) = _build_empty_state_card("applyEmptyStateCard")
if self.open_accounts_callback is not None:
self.empty_state_button.clicked.connect(self.open_accounts_callback)
self.task_table = QTableView()
self.model = ApplyTaskTableModel(self.task_table)
self.task_table.setModel(self.model)
@@ -1449,6 +1525,7 @@ if QT_IMPORT_ERROR is None:
layout.addLayout(filter_layout)
layout.addWidget(self.risk_label)
layout.addWidget(self.summary_label)
layout.addWidget(self.empty_state_card)
layout.addWidget(self.task_table, 1)
layout.addWidget(QLabel("运行日志"))
layout.addWidget(self.run_log_view)
@@ -1499,14 +1576,44 @@ if QT_IMPORT_ERROR is None:
except Exception as exc:
self.model.set_tasks([], [])
self.summary_label.setText("任务读取失败")
_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(filtered_tasks, account_rows)
self.summary_label.setText(
f"任务 {len(filtered_tasks)}/{len(batch_tasks)} 条"
)
self._update_empty_state(batch_tasks, filtered_tasks, account_rows)
self._update_write_back_button()
def _update_empty_state(self, batch_tasks, filtered_tasks, account_rows):
if not account_rows:
_set_empty_state(
self.empty_state_card,
self.empty_state_label,
self.empty_state_button,
"第一步:前往『④账号管理』配置并登录账号,再回到③更新 Shopee。",
self.open_accounts_callback is not None,
)
return
if not batch_tasks:
_set_empty_state(
self.empty_state_card,
self.empty_state_label,
self.empty_state_button,
"还没有可更新任务。请先在②AI生成完成新标题或新封面。",
)
return
if not filtered_tasks:
_set_empty_state(
self.empty_state_card,
self.empty_state_label,
self.empty_state_button,
"当前筛选没有可更新任务,请调整批次、店铺、商品ID或状态筛选。",
)
return
_set_empty_state(self.empty_state_card, self.empty_state_label, self.empty_state_button)
def start_update(self, checked=False):
self._start_update(dry_run=False)
@@ -2184,12 +2291,20 @@ if QT_IMPORT_ERROR is None:
self.run_log_view.setPlaceholderText("采集运行日志")
self.empty_label = QLabel("")
(
self.empty_state_card,
self.empty_state_label,
self.empty_state_button,
) = _build_empty_state_card("collectEmptyStateCard")
if self.open_accounts_callback is not None:
self.empty_state_button.clicked.connect(self.open_accounts_callback)
layout = QVBoxLayout(self)
layout.setContentsMargins(18, 18, 18, 18)
layout.addLayout(toolbar)
layout.addLayout(summary_layout)
layout.addWidget(self.match_detail_label)
layout.addWidget(self.empty_state_card)
layout.addWidget(self.table, 1)
layout.addWidget(QLabel("采集运行日志"))
layout.addWidget(self.run_log_view)
@@ -2401,11 +2516,12 @@ if QT_IMPORT_ERROR is None:
except Exception as exc:
self.model.set_tasks([], [])
self.empty_label.setText("任务读取失败")
_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._update_summary(task_rows, account_rows)
self._update_empty_label(len(task_rows))
self._update_empty_state(task_rows, account_rows)
self._update_delete_batch_button()
def _populate_batch_filter(self, batches, selected_batch):
@@ -2774,6 +2890,29 @@ if QT_IMPORT_ERROR is None:
}
return sum(1 for task in task_rows if str(task.alias).strip() not in aliases)
def _update_empty_state(self, task_rows, account_rows):
if not account_rows:
self.empty_label.setText("")
_set_empty_state(
self.empty_state_card,
self.empty_state_label,
self.empty_state_button,
"第一步:前往『④账号管理』配置并登录账号,再回到①导入 Excel。",
self.open_accounts_callback is not None,
)
return
if not task_rows:
self.empty_label.setText("")
_set_empty_state(
self.empty_state_card,
self.empty_state_label,
self.empty_state_button,
"还没有导入任务。请点击「导入 Excel...」导入待处理商品。",
)
return
_set_empty_state(self.empty_state_card, self.empty_state_label, self.empty_state_button)
self._update_empty_label(len(task_rows))
def _update_empty_label(self, total_rows):
if total_rows == 0:
self.empty_label.setText("暂无任务")
@@ -5668,6 +5807,7 @@ if QT_IMPORT_ERROR is None:
db_path=self.db_path,
config=self.config,
status_callback=self.statusBar().showMessage,
open_accounts_callback=lambda: self.open_accounts_tab(),
)
if title == "③ 更新shopee":
return ApplyTab(