feat(gui): improve status scope dialogs

This commit is contained in:
chengma
2026-07-18 17:23:22 +08:00
parent 89f1b085dc
commit 7538009f94
8 changed files with 218 additions and 62 deletions
+17 -22
View File
@@ -750,30 +750,25 @@ class CollectTab(QWidget):
thread.start()
def _choose_collect_scope(self):
box = QMessageBox(self)
box.setIcon(QMessageBox.Question)
box.setWindowTitle("选择采集范围")
box.setText("请选择本轮要采集的商品范围。")
box.setInformativeText(
"程序会逐个打开商品详情页检测状态并保存结果。"
"采集所有状态商品包含未上架、审核中和状态未知商品,"
"可能增加采集时间,但本步骤不消耗 AI 点数。"
box = ProductStatusScopeDialog(
title="选择采集范围",
text="请选择本轮要采集的商品范围。",
informative_text=(
"程序会逐个打开商品详情页检测状态并保存结果。"
"采集所有状态商品包含未上架、审核中和状态未知商品,"
"可能增加采集时间,但本步骤不消耗 AI 点数。"
),
normal_text="只采集状态正常的商品",
all_text="采集所有状态的商品",
normal_value=product_status.COLLECT_SCOPE_NORMAL_ONLY,
all_value=product_status.COLLECT_SCOPE_ALL,
normal_object_name="collectNormalOnlyButton",
all_object_name="collectAllStatusesButton",
cancel_object_name="collectScopeCancelButton",
parent=self,
)
normal_button = box.addButton("只采集状态正常的商品", QMessageBox.AcceptRole)
normal_button.setObjectName("collectNormalOnlyButton")
all_button = box.addButton("采集所有状态的商品", QMessageBox.DestructiveRole)
all_button.setObjectName("collectAllStatusesButton")
all_button.setStyleSheet("color: #cf222e; font-weight: 600;")
cancel_button = box.addButton("取消", QMessageBox.RejectRole)
cancel_button.setObjectName("collectScopeCancelButton")
box.setDefaultButton(normal_button)
box.setEscapeButton(cancel_button)
box.exec()
if box.clickedButton() is normal_button:
return product_status.COLLECT_SCOPE_NORMAL_ONLY
if box.clickedButton() is all_button:
return product_status.COLLECT_SCOPE_ALL
return None
return box.choice()
def stop_collect(self, checked=False):
if self.collect_worker is not None:
+24 -29
View File
@@ -1828,37 +1828,32 @@ class GenerateTab(QWidget):
total = len(plan.get("base_candidates") or [])
non_normal_count = total - normal_count
box = QMessageBox(self)
box.setIcon(QMessageBox.Question)
box.setWindowTitle("选择生成范围")
box.setText("请选择本轮要生成的商品范围。")
box.setInformativeText(
"真实候选共{total}条:正常{normal},未上架{unlisted},审核中{reviewing},状态未知{unknown}。\n"
"生成所有状态的商品会让非正常状态商品也调用 AI,可能额外消耗点数。"
"状态未知商品请优先回到①重新采集确认。".format(
total=total,
normal=normal_count,
unlisted=unlisted_count,
reviewing=reviewing_count,
unknown=unknown_count,
)
box = ProductStatusScopeDialog(
title="选择生成范围",
text="请选择本轮要生成的商品范围。",
informative_text=(
"真实候选共{total}条:正常{normal},未上架{unlisted},审核中{reviewing},状态未知{unknown}。\n"
"生成所有状态的商品会让非正常状态商品也调用 AI,可能额外消耗点数。"
"状态未知商品请优先回到①重新采集确认。".format(
total=total,
normal=normal_count,
unlisted=unlisted_count,
reviewing=reviewing_count,
unknown=unknown_count,
)
),
normal_text="只生成状态正常的商品",
all_text="生成所有状态的商品",
normal_value=product_status.SCOPE_NORMAL_ONLY,
all_value=product_status.SCOPE_ALL,
normal_object_name="generateNormalOnlyButton",
all_object_name="generateAllStatusesButton",
cancel_object_name="generateScopeCancelButton",
all_enabled=non_normal_count > 0,
parent=self,
)
normal_button = box.addButton("只生成状态正常的商品", QMessageBox.AcceptRole)
normal_button.setObjectName("generateNormalOnlyButton")
all_button = box.addButton("生成所有状态的商品", QMessageBox.DestructiveRole)
all_button.setObjectName("generateAllStatusesButton")
all_button.setStyleSheet("color: #cf222e; font-weight: 600;")
all_button.setEnabled(non_normal_count > 0)
cancel_button = box.addButton("取消", QMessageBox.RejectRole)
cancel_button.setObjectName("generateScopeCancelButton")
box.setDefaultButton(normal_button)
box.setEscapeButton(cancel_button)
box.exec()
if box.clickedButton() is normal_button:
return product_status.SCOPE_NORMAL_ONLY
if all_button.isEnabled() and box.clickedButton() is all_button:
return product_status.SCOPE_ALL
return None
return box.choice()
def stop_generate(self, checked=False):
if self.generate_worker is not None:
+104
View File
@@ -292,6 +292,110 @@ def _danger_outline_button_style(object_name):
)
def _primary_button_style(object_name):
return (
f"QPushButton#{object_name} {{ "
f"background-color: {COLOR_INFO}; border-color: {COLOR_INFO}; "
"color: white; font-weight: 600; "
"}"
f"QPushButton#{object_name}:hover {{ "
"background-color: #0550ae; border-color: #0550ae; "
"}"
f"QPushButton#{object_name}:pressed {{ "
"background-color: #033d8b; border-color: #033d8b; "
"}"
)
class ProductStatusScopeDialog(QDialog):
"""供采集和生成复用的稳定中文范围选择框。"""
MINIMUM_WIDTH = 520
def __init__(
self,
title,
text,
informative_text,
normal_text,
all_text,
normal_value,
all_value,
normal_object_name,
all_object_name,
cancel_object_name,
all_enabled=True,
parent=None,
):
super().__init__(parent)
self._choice = None
self._informative_text = str(informative_text or "")
self.setWindowTitle(str(title or "选择范围"))
self.setModal(True)
self.setMinimumWidth(self.MINIMUM_WIDTH)
self.setStyleSheet(BUTTON_BASE_STYLE)
layout = QVBoxLayout(self)
layout.setContentsMargins(20, 18, 20, 18)
layout.setSpacing(10)
title_label = QLabel(str(text or ""))
title_label.setObjectName("productStatusScopeTitleLabel")
title_label.setWordWrap(True)
title_label.setStyleSheet("font-weight: 600; color: #24292f;")
layout.addWidget(title_label)
detail_label = QLabel(self._informative_text)
detail_label.setObjectName("productStatusScopeDetailLabel")
detail_label.setWordWrap(True)
detail_label.setStyleSheet("color: #57606a;")
layout.addWidget(detail_label)
layout.addSpacing(2)
self.normal_button = QPushButton(str(normal_text or ""))
self.normal_button.setObjectName(str(normal_object_name))
self.normal_button.setMinimumWidth(self.MINIMUM_WIDTH - 40)
self.normal_button.setMinimumHeight(34)
self.normal_button.setDefault(True)
self.normal_button.setFocus()
self.normal_button.setStyleSheet(_primary_button_style(normal_object_name))
self.normal_button.clicked.connect(lambda: self._accept_choice(normal_value))
layout.addWidget(self.normal_button)
self.all_button = QPushButton(str(all_text or ""))
self.all_button.setObjectName(str(all_object_name))
self.all_button.setMinimumWidth(self.MINIMUM_WIDTH - 40)
self.all_button.setMinimumHeight(34)
self.all_button.setEnabled(bool(all_enabled))
self.all_button.setStyleSheet(_warning_outline_button_style(all_object_name))
self.all_button.clicked.connect(lambda: self._accept_choice(all_value))
layout.addWidget(self.all_button)
self.cancel_button = QPushButton("取消")
self.cancel_button.setObjectName(str(cancel_object_name))
self.cancel_button.setMinimumWidth(self.MINIMUM_WIDTH - 40)
self.cancel_button.setMinimumHeight(32)
self.cancel_button.clicked.connect(self.reject)
layout.addWidget(self.cancel_button)
def defaultButton(self):
"""供调用方和 GUI 测试读取明确的默认按钮。"""
return self.normal_button
def informativeText(self):
"""按 QMessageBox 兼容接口返回说明文字。"""
return self._informative_text
def choice(self):
return self._choice
def _accept_choice(self, value):
self._choice = value
self.accept()
def _login_status_display(status):
return f"● {status or '未知'}"