feat: add semantic status bar colors

This commit is contained in:
chengma
2026-07-07 15:42:19 +08:00
parent 8bd6a1df91
commit 9ce4d2442e
14 changed files with 171 additions and 43 deletions
+14 -9
View File
@@ -103,7 +103,7 @@ class MainWindow(QMainWindow):
self.tabs.addTab(self._build_tab(title), title)
self.tabs.setTabIcon(TAB_TITLES.index("③ 更新蝦皮"), _warning_dot_icon())
self.setCentralWidget(self.tabs)
self.statusBar().showMessage("就绪")
self.show_status("就绪", level="muted")
def showEvent(self, event):
super().showEvent(event)
@@ -111,12 +111,17 @@ class MainWindow(QMainWindow):
_fit_and_center_window(self)
self._initial_window_fit_applied_after_show = True
def show_status(self, message, level="muted"):
color = _status_level_color(level)
self.statusBar().setStyleSheet(f"QStatusBar {{ color: {color}; }}")
self.statusBar().showMessage(str(message))
def _build_tab(self, title):
if title == "① 导入采集":
return CollectTab(
db_path=self.db_path,
config=self.config,
status_callback=self.statusBar().showMessage,
status_callback=self.show_status,
open_accounts_callback=lambda: self.open_accounts_tab(),
refresh_workflow_callback=lambda: self.refresh_task_tabs(),
)
@@ -125,7 +130,7 @@ class MainWindow(QMainWindow):
db_path=self.db_path,
config=self.config,
config_path=self.config_path,
status_callback=self.statusBar().showMessage,
status_callback=self.show_status,
title_prompt_path=appconfig.title_prompt_path(self.config),
cover_prompts_dir=appconfig.cover_prompts_dir(self.config),
open_accounts_callback=lambda: self.open_accounts_tab(),
@@ -134,7 +139,7 @@ class MainWindow(QMainWindow):
return ApplyTab(
db_path=self.db_path,
config=self.config,
status_callback=self.statusBar().showMessage,
status_callback=self.show_status,
open_accounts_callback=lambda: self.open_accounts_tab(),
open_settings_callback=lambda: self.open_settings_tab(),
)
@@ -142,13 +147,13 @@ class MainWindow(QMainWindow):
return AccountsTab(
db_path=self.db_path,
config=self.config,
status_callback=self.statusBar().showMessage,
status_callback=self.show_status,
)
return SettingsTab(
config=self.config,
config_path=self.config_path,
ai_models_path=self.ai_models_path,
status_callback=self.statusBar().showMessage,
status_callback=self.show_status,
)
def refresh_task_tabs(self):
@@ -160,7 +165,7 @@ class MainWindow(QMainWindow):
def _on_tab_changed(self, index):
if self._reverting_tab_change:
self._last_tab_index = index
self.statusBar().showMessage(f"当前:{self.tabs.tabText(index)}")
self.show_status(f"当前:{self.tabs.tabText(index)}", level="muted")
return
previous = self._last_tab_index
if previous == self._settings_tab_index and index != previous:
@@ -171,10 +176,10 @@ class MainWindow(QMainWindow):
finally:
self._reverting_tab_change = False
self._last_tab_index = previous
self.statusBar().showMessage(f"当前:{self.tabs.tabText(previous)}")
self.show_status(f"当前:{self.tabs.tabText(previous)}", level="muted")
return
self._last_tab_index = index
self.statusBar().showMessage(f"当前:{self.tabs.tabText(index)}")
self.show_status(f"当前:{self.tabs.tabText(index)}", level="muted")
def _settings_tab(self):
return self.tabs.widget(self._settings_tab_index)
+2 -4
View File
@@ -256,9 +256,8 @@ class GenerateTaskTableModel(QAbstractTableModel):
and bool(getattr(task, "new_title", None))
)
def _set_status(self, message):
if self.status_callback is not None:
self.status_callback(message)
def _set_status(self, message, level=None):
_emit_status(self.status_callback, message, level=level)
def task_at(self, row):
if row < 0 or row >= len(self.tasks):
@@ -430,4 +429,3 @@ class ApplyTaskTableModel(QAbstractTableModel):
if getattr(task, "stage", None) == "applied" or getattr(task, "status", None) == "success":
return _qcolor(COLOR_SUCCESS)
return _qcolor(COLOR_PENDING)
+2 -4
View File
@@ -159,9 +159,8 @@ class AccountsTab(QWidget):
self.refresh_accounts()
def _set_status(self, message):
if self.status_callback is not None:
self.status_callback(message)
def _set_status(self, message, level=None):
_emit_status(self.status_callback, message, level=level)
def _selected_account(self):
selected = self.table.selectionModel().selectedRows()
@@ -449,4 +448,3 @@ class AccountsTab(QWidget):
PLAINTEXT_PASSWORD_WARNING,
)
+2 -3
View File
@@ -145,9 +145,8 @@ class ApplyTab(QWidget):
self.refresh_tasks()
self._show_current_run_log_empty()
def _set_status(self, message):
if self.status_callback is not None:
self.status_callback(message)
def _set_status(self, message, level=None):
_emit_status(self.status_callback, message, level=level)
def refresh_tasks(self, checked=False):
try:
+2 -4
View File
@@ -159,9 +159,8 @@ class CollectTab(QWidget):
self.refresh_tasks()
self._load_latest_collect_run_log()
def _set_status(self, message):
if self.status_callback is not None:
self.status_callback(message)
def _set_status(self, message, level=None):
_emit_status(self.status_callback, message, level=level)
def _on_collect_log(self, message):
self._append_collect_log(message)
@@ -836,4 +835,3 @@ class CollectTab(QWidget):
self.empty_label.setText(
"" if unmatched == 0 else f"{unmatched} 条任务别名未匹配账号,阶段显示为“略过”"
)
+2 -3
View File
@@ -249,9 +249,8 @@ class GenerateTab(QWidget):
self._show_current_run_log_empty()
self._update_cmhub_balance_label({})
def _set_status(self, message):
if self.status_callback is not None:
self.status_callback(message)
def _set_status(self, message, level=None):
_emit_status(self.status_callback, message, level=level)
def _on_generate_log(self, message):
self._append_generate_log(message)
+2 -3
View File
@@ -452,9 +452,8 @@ class SettingsTab(QWidget):
super().showEvent(event)
self._maybe_auto_refresh_cmhub_models()
def _set_status(self, message):
if self.status_callback is not None:
self.status_callback(message)
def _set_status(self, message, level=None):
_emit_status(self.status_callback, message, level=level)
@contextmanager
def _dirty_tracking_suspended(self):
+55
View File
@@ -91,6 +91,14 @@ COLOR_PENDING = "#9a6700"
COLOR_MUTED = "#6e7781"
COLOR_WARNING = "#bc4c00"
COLOR_DANGER_BG = "#ffebe9"
STATUS_LEVEL_COLORS = {
"muted": COLOR_MUTED,
"info": COLOR_INFO,
"success": COLOR_SUCCESS,
"warning": COLOR_WARNING,
"danger": COLOR_DANGER,
"pending": COLOR_PENDING,
}
BUTTON_RADIUS_PX = 4
BUTTON_BASE_STYLE = f"""
QPushButton {{
@@ -193,6 +201,53 @@ def _status_base_color(status):
return None
def _status_level_color(level):
return STATUS_LEVEL_COLORS.get(str(level or "muted"), COLOR_MUTED)
def _status_level_for_message(message, default="muted"):
text = str(message or "")
if any(keyword in text for keyword in ("失败", "错误", "异常", "未登录", "不可写", "点数不足", "阻止")):
return "danger"
if any(keyword in text for keyword in ("没有", "请先", "未配置", "不完整", "已取消", "不能", "无法")):
return "warning"
if any(
keyword in text
for keyword in (
"完成",
"成功",
"已保存",
"已回写",
"已新增",
"已删除",
"已软删除",
"已重置",
"已刷新",
"已修改",
"已启动",
"已复用",
"已生成",
"已新建",
"已另存为",
"已重命名",
)
):
return "success"
if any(keyword in text for keyword in ("正在", "开始", "进度", "检测中")):
return "info"
return default
def _emit_status(callback, message, level=None):
if callback is None:
return
actual_level = level or _status_level_for_message(message)
try:
callback(str(message), level=actual_level)
except TypeError:
callback(str(message))
def _danger_metric_text(text, active):
if not active:
return text