update server

This commit is contained in:
2026-07-30 11:12:31 +08:00
commit 4312cb878c
99 changed files with 24034 additions and 0 deletions
+569
View File
@@ -0,0 +1,569 @@
# styles.py
"""界面样式集中管理模块:PySide6 QSS 样式表。
颜色主题:品牌蓝 #0960D1,主背景 #F8FAFC,成功绿 #0F955D。
通过 apply_app_style(app) 应用全局 QSS 样式,并拿到配色字典。
"""
from PySide6.QtWidgets import QApplication
from PySide6.QtGui import QPalette, QColor
# ==========================================
# 统一配色架构(与 Tkinter 版本保持一致)
# ==========================================
COLORS = {
"BG_COLOR": "#F8FAFC", # 浅色大背景(微冷超浅灰蓝)
"CARD_BG": "#FFFFFF", # 容器卡片背景
"BORDER_COLOR": "#E2E8F0", # 扁平化细边框
"TEXT_MAIN": "#1A1A1A", # 主文字颜色(高清晰度深灰)
"TEXT_MUTED": "#757575", # 辅助文字颜色(中灰)
"ACCENT_LIGHT": "#0960D1", # 主品牌色/高亮蓝
"ACCENT_DARK": "#0960D1", # 品牌色(统一)
"HOVER_BLUE": "#0856B8", # 悬停过渡色(品牌色加深)
"SUCCESS_GREEN": "#0F955D", # 连接成功绿
"SUCCESS_ACTIVE": "#0D8250", # 成功按钮按下态
"DISABLED": "#CBD5E1", # 禁用态灰
"ERROR_RED": "#FF2424", # 状态警示红
"NAV_BG": "#FFFFFF", # 导航栏背景(白色)
"NAV_BORDER": "#E2E8F0", # 导航栏底部边框
"NAV_TAB_ACTIVE_TEXT": "#0960D1", # Tab激活态文字色
"NAV_TAB_HOVER": "#F1F5F9", # Tab悬停背景
"FORM_LABEL": "#333333", # 表单标签色
"REFRESH_BORDER": "#CCDBF0", # 刷新按钮边框
}
# 科技蓝核心高亮统一为浅色主题色
COLORS["ACCENT_BLUE"] = COLORS["ACCENT_LIGHT"]
# 字体配置
BASE_FONT_FAMILY = "Microsoft YaHei, PingFang SC, SimHei, sans-serif"
BASE_FONT_SIZE = "14px"
BASE_FONT_SIZE_SM = "12px"
BASE_FONT_SIZE_LG = "16px"
BASE_FONT_SIZE_XL = "28px"
BASE_FONT_SIZE_NAV_TITLE = "22px"
QSS_STYLESHEET = f"""
/* ===== 全局默认 ===== */
QMainWindow, QWidget {{
background-color: {COLORS["BG_COLOR"]};
color: {COLORS["TEXT_MAIN"]};
font-family: "{BASE_FONT_FAMILY}";
font-size: {BASE_FONT_SIZE};
}}
/* ===== 标题行(Layer 1:纯白背景) ===== */
QWidget[cssClass="titleRow"] {{
background-color: #FFFFFF;
}}
/* ===== Tab 栏容器(Layer 2:一体化浅灰背景 #F8FAFC ===== */
QWidget[cssClass="tabRow"] {{
background-color: #F8FAFC;
}}
/* ===== QTabBar 导航标签 ===== */
QTabBar[cssClass="mainTab"]::tab {{
background: transparent;
padding: 10px 24px 10px 16px;
font-size: 15px;
color: #64748B;
border: none;
border-bottom: 3px solid transparent;
font-weight: normal;
}}
QTabBar[cssClass="mainTab"]::tab:selected {{
color: #0960D1;
font-weight: bold;
border-bottom: 3px solid #0960D1;
}}
QTabBar[cssClass="mainTab"]::tab:hover:!selected {{
color: #0960D1;
}}
/* ===== QGroupBox ===== */
QGroupBox {{
background-color: {COLORS["CARD_BG"]};
border: 1px solid {COLORS["BORDER_COLOR"]};
border-radius: 12px;
margin-top: 14px;
padding: 16px 12px 12px 12px;
font-weight: bold;
color: {COLORS["TEXT_MAIN"]};
font-size: {BASE_FONT_SIZE_LG};
}}
QGroupBox::title {{
subcontrol-origin: margin;
subcontrol-position: top left;
padding: 0 10px;
color: {COLORS["ACCENT_DARK"]};
font-weight: bold;
font-size: {BASE_FONT_SIZE_LG};
background-color: transparent;
}}
/* ===== Section 卡片(替代 QGroupBox 的轻量方案) ===== */
QFrame[cssClass="sectionCard"] {{
background-color: {COLORS["CARD_BG"]};
border: 1px solid {COLORS["BORDER_COLOR"]};
border-radius: 12px;
}}
/* ===== Section 标题 ===== */
QLabel[cssClass="sectionTitle"] {{
color: {COLORS["TEXT_MAIN"]};
font-weight: bold;
font-size: {BASE_FONT_SIZE_LG};
background-color: transparent;
}}
/* Section 标题左侧蓝色竖线(4px x 16px) */
QWidget[cssClass="sectionAccent"] {{
background-color: {COLORS["ACCENT_LIGHT"]};
border-radius: 2px;
}}
/* ===== 表单标签 ===== */
QLabel[cssClass="formLabel"] {{
color: {COLORS["FORM_LABEL"]};
font-size: 14px;
font-weight: bold;
background-color: transparent;
min-width: 140px;
}}
/* ===== QPushButton 基础 ===== */
QPushButton {{
background-color: {COLORS["ACCENT_BLUE"]};
color: white;
border: none;
border-radius: 6px;
padding: 9px 20px;
font-weight: bold;
font-size: {BASE_FONT_SIZE};
}}
QPushButton:hover {{
background-color: {COLORS["HOVER_BLUE"]};
}}
QPushButton:pressed {{
background-color: {COLORS["ACCENT_DARK"]};
}}
QPushButton:disabled {{
background-color: {COLORS["DISABLED"]};
color: #94A3B8;
}}
/* 主操作按钮(绿色 - 连接设备) */
QPushButton[cssClass="action"] {{
background-color: {COLORS["SUCCESS_GREEN"]};
border: none;
color: #FFFFFF;
padding: 8px 24px;
font-size: 14px;
font-weight: bold;
border-radius: 6px;
}}
QPushButton[cssClass="action"]:hover {{
background-color: #0D8250;
}}
QPushButton[cssClass="action"]:pressed {{
background-color: {COLORS["SUCCESS_ACTIVE"]};
}}
/* 次要按钮 / 刷新按钮 */
QPushButton[cssClass="refresh"] {{
background-color: #FFFFFF;
border: 1px solid {COLORS["REFRESH_BORDER"]};
color: {COLORS["ACCENT_LIGHT"]};
padding: 8px 20px;
font-size: 14px;
font-weight: bold;
border-radius: 6px;
}}
QPushButton[cssClass="refresh"]:hover {{
background-color: #F1F5F9;
border-color: {COLORS["ACCENT_LIGHT"]};
}}
QPushButton[cssClass="refresh"]:pressed {{
background-color: #E2E8F0;
}}
/* ===== 底部操作按钮(ID 选择器,精确控制高度与内边距,修复文字截断) ===== */
QPushButton#refresh_btn {{
background-color: #FFFFFF;
border: 1px solid #CCDBF0;
color: #0960D1;
border-radius: 6px;
min-height: 34px;
max-height: 34px;
padding: 0px 20px;
font-weight: bold;
font-size: 14px;
outline: none;
}}
QPushButton#refresh_btn:hover {{
background-color: #F0F4FA;
}}
QPushButton#refresh_btn:focus {{
outline: none;
}}
QPushButton#connect_btn {{
background-color: #0F955D;
border: none;
color: #FFFFFF;
border-radius: 6px;
min-height: 34px;
max-height: 34px;
padding: 0px 24px;
font-weight: bold;
font-size: 14px;
outline: none;
}}
QPushButton#connect_btn:hover {{
background-color: #0D8250;
}}
QPushButton#connect_btn:focus {{
outline: none;
}}
/* 危险按钮(红色,用于停止) */
QPushButton[cssClass="danger"] {{
background-color: #EF4444;
border: none;
color: #FFFFFF;
padding: 8px 24px;
font-size: 14px;
font-weight: bold;
border-radius: 6px;
}}
QPushButton[cssClass="danger"]:hover {{
background-color: #DC2626;
}}
QPushButton[cssClass="danger"]:pressed {{
background-color: #B91C1C;
}}
/* ===== QLineEdit 输入框 ===== */
QLineEdit {{
background-color: #FFFFFF;
border: 1px solid {COLORS["BORDER_COLOR"]};
border-radius: 6px;
padding-left: 12px;
color: #333333;
font-size: 14px;
min-height: 36px;
max-height: 36px;
}}
QLineEdit:focus {{
border: 1px solid {COLORS["ACCENT_LIGHT"]};
}}
QLineEdit:hover:!focus {{
border-color: #94A3B8;
}}
QLineEdit:disabled {{
background-color: #F1F5F9;
color: {COLORS["TEXT_MUTED"]};
border-color: #E2E8F0;
}}
/* ===== QComboBox 下拉框(增强鲁棒性,防止打包后黑底) ===== */
QComboBox {{
background-color: #FFFFFF;
border: 1px solid {COLORS["BORDER_COLOR"]};
border-radius: 6px;
padding: 7px 10px;
color: {COLORS["TEXT_MAIN"]};
font-size: 14px;
min-width: 100px;
min-height: 36px;
max-height: 36px;
outline: none;
}}
QComboBox:hover {{
border-color: #94A3B8;
}}
QComboBox:focus {{
border-color: {COLORS["ACCENT_LIGHT"]};
border-width: 1px;
}}
QComboBox:disabled {{
background-color: #F1F5F9;
color: {COLORS["TEXT_MUTED"]};
border-color: #E2E8F0;
}}
QComboBox::drop-down {{
subcontrol-origin: padding;
subcontrol-position: top right;
width: 28px;
border: none;
border-left: 1px solid {COLORS["BORDER_COLOR"]};
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
background-color: #F8FAFC;
}}
QComboBox::down-arrow {{
width: 12px;
height: 12px;
}}
/* 下拉弹出视图(最关键的修复点——保证白色背景) */
QComboBox QAbstractItemView {{
background-color: #FFFFFF;
border: 1px solid {COLORS["BORDER_COLOR"]};
border-radius: 4px;
selection-background-color: {COLORS["ACCENT_LIGHT"]};
selection-color: #FFFFFF;
color: {COLORS["TEXT_MAIN"]};
font-size: {BASE_FONT_SIZE};
padding: 4px;
outline: none;
}}
QComboBox QAbstractItemView::item {{
padding: 6px 10px;
border-radius: 3px;
color: {COLORS["TEXT_MAIN"]};
background-color: #FFFFFF;
}}
QComboBox QAbstractItemView::item:selected {{
background-color: {COLORS["ACCENT_LIGHT"]};
color: #FFFFFF;
}}
QComboBox QAbstractItemView::item:hover {{
background-color: #EFF6FF;
}}
/* 防止下拉滚动条区域也变黑 */
QComboBox QAbstractScrollArea {{
background-color: #FFFFFF;
color: {COLORS["TEXT_MAIN"]};
}}
/* ===== QRadioButton / QCheckBox ===== */
QRadioButton, QCheckBox {{
background-color: transparent;
color: {COLORS["TEXT_MAIN"]};
font-size: {BASE_FONT_SIZE};
spacing: 8px;
}}
QRadioButton::indicator {{
width: 18px;
height: 18px;
border-radius: 9px;
border: 2px solid {COLORS["BORDER_COLOR"]};
background-color: #FFFFFF;
}}
QRadioButton::indicator:checked {{
background-color: {COLORS["ACCENT_BLUE"]};
border-color: {COLORS["ACCENT_BLUE"]};
}}
QRadioButton::indicator:hover {{
border-color: {COLORS["ACCENT_BLUE"]};
}}
QRadioButton::indicator:checked:hover {{
background-color: {COLORS["ACCENT_DARK"]};
border-color: {COLORS["ACCENT_DARK"]};
}}
QRadioButton:disabled {{
color: {COLORS["DISABLED"]};
}}
QRadioButton::indicator:disabled {{
background-color: #F1F5F9;
border-color: {COLORS["DISABLED"]};
}}
QCheckBox::indicator {{
width: 18px;
height: 18px;
border-radius: 4px;
border: 2px solid {COLORS["BORDER_COLOR"]};
background-color: #FFFFFF;
}}
QCheckBox::indicator:checked {{
background-color: {COLORS["ACCENT_BLUE"]};
border-color: {COLORS["ACCENT_BLUE"]};
}}
QCheckBox::indicator:hover {{
border-color: {COLORS["ACCENT_BLUE"]};
}}
QCheckBox::indicator:checked:hover {{
background-color: {COLORS["ACCENT_DARK"]};
border-color: {COLORS["ACCENT_DARK"]};
}}
QCheckBox:disabled {{
color: {COLORS["DISABLED"]};
}}
QCheckBox::indicator:disabled {{
background-color: #F1F5F9;
border-color: {COLORS["DISABLED"]};
}}
/* ===== 仪表板卡片 ===== */
QFrame[cssClass="dashboardCard"] {{
background-color: {COLORS["CARD_BG"]};
border: 1px solid {COLORS["BORDER_COLOR"]};
border-radius: 12px;
padding: 12px;
}}
QFrame[cssClass="dashboardCard"] QLabel {{
background-color: transparent;
}}
QLabel[cssClass="dashboardLabel"] {{
color: {COLORS["TEXT_MUTED"]};
font-size: {BASE_FONT_SIZE_SM};
font-weight: normal;
}}
QLabel[cssClass="dashboardValue"] {{
font-family: "SF Mono, Menlo, Consolas, monospace";
font-size: {BASE_FONT_SIZE_XL};
font-weight: bold;
}}
/* ===== 底部状态栏 ===== */
QWidget[cssClass="bottomBar"] {{
background-color: #FFFFFF;
border-top: 1px solid {COLORS["BORDER_COLOR"]};
}}
QLabel[cssClass="logLabel"] {{
color: #757575;
font-family: "SF Mono, Consolas, Menlo, monospace";
font-size: 12px;
background-color: transparent;
}}
QLabel[cssClass="statusLabel"] {{
font-weight: bold;
font-size: 14px;
background-color: transparent;
}}
/* ===== 透明背景容器(避免 inline stylesheet 覆盖子控件 QSS ===== */
QWidget[cssClass="transparentBg"] {{
background-color: transparent;
}}
/* ===== QStackedWidget 页面 ===== */
QWidget[cssClass="tabPage"] {{
background-color: #FFFFFF;
}}
/* ===== 分组辅助标签 ===== */
QLabel[cssClass="section"] {{
color: {COLORS["ACCENT_DARK"]};
font-weight: bold;
font-size: {BASE_FONT_SIZE_LG};
background-color: transparent;
}}
/* ===== 导航栏标题 ===== */
QLabel[cssClass="navTitle"] {{
color: {COLORS["TEXT_MAIN"]};
font-size: 22px;
font-weight: bold;
background-color: transparent;
letter-spacing: 0px;
}}
QLabel[cssClass="navSubtitle"] {{
color: {COLORS["ACCENT_DARK"]};
font-size: 11px;
font-weight: normal;
background-color: transparent;
}}
QLabel[cssClass="navDivider"] {{
color: {COLORS["BORDER_COLOR"]};
background-color: transparent;
}}
/* 设置按钮(圆形,右上角) */
QPushButton[cssClass="navSettings"] {{
background-color: transparent;
border: 1.5px solid {COLORS["BORDER_COLOR"]};
border-radius: 18px;
padding: 4px;
min-width: 36px;
max-width: 36px;
min-height: 36px;
max-height: 36px;
}}
QPushButton[cssClass="navSettings"]:hover {{
background-color: {COLORS["BG_COLOR"]};
border-color: #CBD5E1;
}}
QPushButton[cssClass="navSettings"]:pressed {{
background-color: #E2E8F0;
}}
"""
def apply_app_style(app: QApplication):
"""配置全局 QSS 样式表与窗口默认调色板,返回配色字典供布局复用。"""
# ---- 强制使用 Fusion 风格(跨平台一致,避免 Windows 原生风格/深色模式干扰 QSS ----
app.setStyle("Fusion")
# 应用 QSS 样式表
app.setStyleSheet(QSS_STYLESHEET)
# 设置默认字体
font = app.font()
font.setFamily(BASE_FONT_FAMILY.split(",")[0].strip().strip('"'))
font.setPointSize(10)
app.setFont(font)
# 配置默认调色板(仅设置 Window/Base 等基础角色,不污染 Button/ComboBox
palette = QPalette()
palette.setColor(QPalette.Window, QColor(COLORS["BG_COLOR"]))
palette.setColor(QPalette.WindowText, QColor(COLORS["TEXT_MAIN"]))
palette.setColor(QPalette.Base, QColor("#FFFFFF"))
palette.setColor(QPalette.Text, QColor(COLORS["TEXT_MAIN"]))
palette.setColor(QPalette.Button, QColor("#FFFFFF")) # 白色底,避免黑色
palette.setColor(QPalette.ButtonText, QColor(COLORS["TEXT_MAIN"]))
palette.setColor(QPalette.Highlight, QColor(COLORS["ACCENT_LIGHT"]))
palette.setColor(QPalette.HighlightedText, QColor("#FFFFFF"))
app.setPalette(palette)
return COLORS