|
|
@@ -53,7 +53,7 @@ class MainWindow(FluentWindow):
|
|
|
self.setMinimumSize(WINDOW_MIN_WIDTH, WINDOW_MIN_HEIGHT)
|
|
|
self.resize(WINDOW_DEFAULT_WIDTH, WINDOW_DEFAULT_HEIGHT)
|
|
|
|
|
|
- # 配置导航界面(使用 FluentWindow 自带的 navigationInterface,关闭返回/菜单/折叠)
|
|
|
+ # 配置导航界面(使用 FluentWindow 自带的 navigationInterface,关闭返回/菜单/折叠,但不参与布局展示)
|
|
|
self.navigationInterface.setMenuButtonVisible(False)
|
|
|
self.navigationInterface.setReturnButtonVisible(False)
|
|
|
self.navigationInterface.setCollapsible(False)
|
|
|
@@ -77,8 +77,18 @@ class MainWindow(FluentWindow):
|
|
|
|
|
|
self.settingsInterface = self.create_settings_interface()
|
|
|
self.settingsInterface.setObjectName("设置")
|
|
|
-
|
|
|
- # 添加导航项
|
|
|
+
|
|
|
+ # 路由 key 对应的实际界面组件,用于侧边菜单切换
|
|
|
+ self.route_widgets = {
|
|
|
+ "充值": self.rechargeInterface,
|
|
|
+ "Steam账号": self.steamInterface,
|
|
|
+ "选品": self.selectionInterface,
|
|
|
+ "扫货": self.sweepInterface,
|
|
|
+ "公告": self.announcementInterface,
|
|
|
+ "设置": self.settingsInterface,
|
|
|
+ }
|
|
|
+
|
|
|
+ # 添加导航项(隐藏导航栏用作路由)
|
|
|
self.addSubInterface(
|
|
|
self.rechargeInterface,
|
|
|
qta.icon('fa5s.money-bill-wave', color='#666'),
|
|
|
@@ -127,6 +137,7 @@ class MainWindow(FluentWindow):
|
|
|
|
|
|
# 设置初始界面
|
|
|
self.navigationInterface.setCurrentItem("充值")
|
|
|
+ self.set_active_menu("充值")
|
|
|
|
|
|
def setup_shortcuts(self):
|
|
|
"""设置快捷键"""
|
|
|
@@ -136,7 +147,7 @@ class MainWindow(FluentWindow):
|
|
|
|
|
|
def setup_layout_structure(self):
|
|
|
"""自定义上下+左右布局结构"""
|
|
|
- # 将导航从基础布局中移除,便于重新布置
|
|
|
+ # 将导航从基础布局中移除,便于重新布置(导航只用于路由,不直接展示)
|
|
|
self.hBoxLayout.removeWidget(self.navigationInterface)
|
|
|
self.widgetLayout.removeWidget(self.stackedWidget)
|
|
|
self.widgetLayout.setContentsMargins(0, 0, 0, 0)
|
|
|
@@ -151,15 +162,16 @@ class MainWindow(FluentWindow):
|
|
|
self.headerBar = self.create_header_bar()
|
|
|
self.mainContainerLayout.addWidget(self.headerBar, 0)
|
|
|
|
|
|
- # 主体区域:左侧菜单 + 右侧内容
|
|
|
+ # 主体区域:左侧自定义菜单 + 右侧内容
|
|
|
self.bodyContainer = QWidget(self)
|
|
|
self.bodyLayout = QHBoxLayout(self.bodyContainer)
|
|
|
self.bodyLayout.setContentsMargins(0, 0, 0, 0)
|
|
|
self.bodyLayout.setSpacing(0)
|
|
|
|
|
|
- self.navigationInterface.setMinimumWidth(220)
|
|
|
- self.navigationInterface.setMaximumWidth(260)
|
|
|
- self.bodyLayout.addWidget(self.navigationInterface, 0)
|
|
|
+ # 左侧自定义菜单
|
|
|
+ self.sideMenu = self.create_side_menu()
|
|
|
+ self.bodyLayout.addWidget(self.sideMenu, 0)
|
|
|
+
|
|
|
self.bodyLayout.addWidget(self.stackedWidget, 1)
|
|
|
|
|
|
self.mainContainerLayout.addWidget(self.bodyContainer, 1)
|
|
|
@@ -201,12 +213,102 @@ class MainWindow(FluentWindow):
|
|
|
|
|
|
return logo_label
|
|
|
|
|
|
+ def create_side_menu(self) -> QWidget:
|
|
|
+ """创建左侧自定义菜单栏"""
|
|
|
+ from PyQt5.QtWidgets import QPushButton
|
|
|
+
|
|
|
+ menu = QWidget(self)
|
|
|
+ menu.setObjectName("SideMenu")
|
|
|
+ layout = QVBoxLayout(menu)
|
|
|
+ layout.setContentsMargins(8, 16, 8, 16)
|
|
|
+ layout.setSpacing(4)
|
|
|
+
|
|
|
+ self._side_menu_buttons = {}
|
|
|
+
|
|
|
+ def add_menu_button(route_key: str, text: str, icon):
|
|
|
+ btn = QPushButton(text, menu)
|
|
|
+ btn.setCheckable(True)
|
|
|
+ btn.setCursor(Qt.PointingHandCursor)
|
|
|
+ btn.setIcon(icon)
|
|
|
+ btn.clicked.connect(lambda: self.on_side_menu_clicked(route_key))
|
|
|
+ layout.addWidget(btn)
|
|
|
+ self._side_menu_buttons[route_key] = btn
|
|
|
+
|
|
|
+ add_menu_button("充值", "充值", qta.icon('fa5s.money-bill-wave', color='#666'))
|
|
|
+ add_menu_button("Steam账号", "Steam账号", qta.icon('fa5s.gamepad', color='#666'))
|
|
|
+ add_menu_button("选品", "选品", qta.icon('fa5s.shopping-cart', color='#666'))
|
|
|
+ add_menu_button("扫货", "扫货", FluentIcon.SEARCH.icon())
|
|
|
+ add_menu_button("公告", "公告", qta.icon('fa5s.bullhorn', color='#666'))
|
|
|
+
|
|
|
+ layout.addStretch(1)
|
|
|
+
|
|
|
+ # 底部设置按钮
|
|
|
+ settings_btn = QPushButton("设置", menu)
|
|
|
+ settings_btn.setCheckable(True)
|
|
|
+ settings_btn.setCursor(Qt.PointingHandCursor)
|
|
|
+ settings_btn.setIcon(FluentIcon.SETTING.icon())
|
|
|
+ settings_btn.clicked.connect(lambda: self.on_side_menu_clicked("设置"))
|
|
|
+ layout.addWidget(settings_btn)
|
|
|
+ self._side_menu_buttons["设置"] = settings_btn
|
|
|
+
|
|
|
+ menu.setFixedWidth(140)
|
|
|
+ menu.setStyleSheet("""
|
|
|
+ QWidget#SideMenu {
|
|
|
+ background-color: #f5f7fb;
|
|
|
+ border-right: 1px solid #e5e7eb;
|
|
|
+ }
|
|
|
+ QWidget#SideMenu QPushButton {
|
|
|
+ border: none;
|
|
|
+ text-align: left;
|
|
|
+ padding: 6px 12px;
|
|
|
+ border-radius: 6px;
|
|
|
+ color: #374151;
|
|
|
+ }
|
|
|
+ QWidget#SideMenu QPushButton:hover {
|
|
|
+ background-color: #e5f3ff;
|
|
|
+ }
|
|
|
+ QWidget#SideMenu QPushButton:checked {
|
|
|
+ background-color: #dbeafe;
|
|
|
+ color: #1d4ed8;
|
|
|
+ font-weight: 600;
|
|
|
+ }
|
|
|
+ """)
|
|
|
+
|
|
|
+ return menu
|
|
|
+
|
|
|
+ def on_side_menu_clicked(self, route_key: str):
|
|
|
+ """侧边菜单点击,切换到对应子界面"""
|
|
|
+ # 通过隐藏的 NavigationInterface 和路由映射切换实际页面
|
|
|
+ try:
|
|
|
+ self.navigationInterface.setCurrentItem(route_key)
|
|
|
+ except Exception:
|
|
|
+ pass
|
|
|
+
|
|
|
+ widget = getattr(self, "route_widgets", {}).get(route_key)
|
|
|
+ if widget is not None:
|
|
|
+ # 使用 FluentWindow 自带的切换方法,保持过渡效果一致
|
|
|
+ try:
|
|
|
+ self.switchTo(widget)
|
|
|
+ except Exception:
|
|
|
+ # 兜底:直接切换 QStackedWidget 当前页
|
|
|
+ self.stackedWidget.setCurrentWidget(widget)
|
|
|
+
|
|
|
+ self.set_active_menu(route_key)
|
|
|
+
|
|
|
+ def set_active_menu(self, route_key: str):
|
|
|
+ """高亮当前菜单按钮"""
|
|
|
+ if not hasattr(self, "_side_menu_buttons"):
|
|
|
+ return
|
|
|
+ for key, btn in self._side_menu_buttons.items():
|
|
|
+ btn.setChecked(key == route_key)
|
|
|
+
|
|
|
def create_header_bar(self) -> QWidget:
|
|
|
"""创建顶部标题栏"""
|
|
|
header = QWidget(self)
|
|
|
header.setObjectName("HeaderBar")
|
|
|
header_layout = QHBoxLayout(header)
|
|
|
- header_layout.setContentsMargins(24, 12, 24, 12)
|
|
|
+ # 右侧整体留白 10px
|
|
|
+ header_layout.setContentsMargins(24, 12, 10, 12)
|
|
|
header_layout.setSpacing(16)
|
|
|
|
|
|
# 左侧:logo + 软件名称
|
|
|
@@ -229,29 +331,69 @@ class MainWindow(FluentWindow):
|
|
|
|
|
|
header_layout.addWidget(left_container, 1)
|
|
|
|
|
|
- # 右侧:倒计时 + 用户名 + 退出按钮
|
|
|
+ # 右侧:窗口控制按钮 + 倒计时 + 用户名 + 退出按钮
|
|
|
right_container = QWidget(header)
|
|
|
- right_layout = QHBoxLayout(right_container)
|
|
|
+ right_layout = QVBoxLayout(right_container)
|
|
|
right_layout.setContentsMargins(0, 0, 0, 0)
|
|
|
- right_layout.setSpacing(12)
|
|
|
+ right_layout.setSpacing(4)
|
|
|
+
|
|
|
+ # 顶部:窗口控制按钮(最小化 / 全屏 / 关闭)
|
|
|
+ window_ctrl_layout = QHBoxLayout()
|
|
|
+ window_ctrl_layout.setContentsMargins(0, 0, 0, 0)
|
|
|
+ window_ctrl_layout.setSpacing(6)
|
|
|
+
|
|
|
+ # 先添加弹性空间,将按钮整体推到最右侧(距离右边 10px 由 header_layout 控制)
|
|
|
+ window_ctrl_layout.addStretch(1)
|
|
|
+
|
|
|
+ minimize_btn = QPushButton(right_container)
|
|
|
+ minimize_btn.setIcon(qta.icon('fa5s.window-minimize', color='#6b7280'))
|
|
|
+ minimize_btn.setFixedSize(26, 26)
|
|
|
+ minimize_btn.setFlat(True)
|
|
|
+ minimize_btn.setCursor(Qt.PointingHandCursor)
|
|
|
+ minimize_btn.clicked.connect(self.showMinimized)
|
|
|
+ window_ctrl_layout.addWidget(minimize_btn)
|
|
|
+
|
|
|
+ fullscreen_btn = QPushButton(right_container)
|
|
|
+ fullscreen_btn.setIcon(qta.icon('fa5s.expand-arrows-alt', color='#6b7280'))
|
|
|
+ fullscreen_btn.setFixedSize(26, 26)
|
|
|
+ fullscreen_btn.setFlat(True)
|
|
|
+ fullscreen_btn.setCursor(Qt.PointingHandCursor)
|
|
|
+ fullscreen_btn.clicked.connect(self.toggle_fullscreen)
|
|
|
+ window_ctrl_layout.addWidget(fullscreen_btn)
|
|
|
+
|
|
|
+ close_btn = QPushButton(right_container)
|
|
|
+ close_btn.setIcon(qta.icon('fa5s.times', color='#ef4444'))
|
|
|
+ close_btn.setFixedSize(26, 26)
|
|
|
+ close_btn.setFlat(True)
|
|
|
+ close_btn.setCursor(Qt.PointingHandCursor)
|
|
|
+ close_btn.clicked.connect(self.close)
|
|
|
+ window_ctrl_layout.addWidget(close_btn)
|
|
|
+ right_layout.addLayout(window_ctrl_layout)
|
|
|
+
|
|
|
+ # 底部:倒计时 + 用户名 + 退出按钮
|
|
|
+ info_layout = QHBoxLayout()
|
|
|
+ info_layout.setContentsMargins(0, 0, 0, 0)
|
|
|
+ info_layout.setSpacing(12)
|
|
|
|
|
|
expire_label = QLabel("卡密倒计时: 加载中...", right_container)
|
|
|
expire_label.setObjectName("HeaderExpireLabel")
|
|
|
self.register_expire_label(expire_label, prefix="卡密倒计时")
|
|
|
- right_layout.addWidget(expire_label, 0, Qt.AlignmentFlag.AlignVCenter)
|
|
|
+ info_layout.addWidget(expire_label, 0, Qt.AlignmentFlag.AlignVCenter)
|
|
|
|
|
|
username = self.user_info.get("username", "未知")
|
|
|
self.header_user_label = QLabel(f"当前用户: {username}", right_container)
|
|
|
self.header_user_label.setStyleSheet("color: #4b5563; font-size: 14px;")
|
|
|
- right_layout.addWidget(self.header_user_label, 0, Qt.AlignmentFlag.AlignVCenter)
|
|
|
+ info_layout.addWidget(self.header_user_label, 0, Qt.AlignmentFlag.AlignVCenter)
|
|
|
|
|
|
logout_btn = PrimaryPushButton("退出登录", right_container)
|
|
|
logout_btn.setIcon(qta.icon('fa5s.sign-out-alt', color='white'))
|
|
|
- logout_btn.setFixedHeight(36)
|
|
|
+ logout_btn.setFixedHeight(32)
|
|
|
logout_btn.clicked.connect(self.handle_logout)
|
|
|
- right_layout.addWidget(logout_btn, 0, Qt.AlignmentFlag.AlignVCenter)
|
|
|
+ info_layout.addWidget(logout_btn, 0, Qt.AlignmentFlag.AlignVCenter)
|
|
|
+
|
|
|
+ right_layout.addLayout(info_layout)
|
|
|
|
|
|
- header_layout.addWidget(right_container, 0)
|
|
|
+ header_layout.addWidget(right_container, 0, Qt.AlignmentFlag.AlignVCenter)
|
|
|
header_layout.setStretchFactor(left_container, 1)
|
|
|
|
|
|
header.setStyleSheet("""
|