diff --git a/main.py b/main.py index 7478939..ca30f33 100644 --- a/main.py +++ b/main.py @@ -62,6 +62,11 @@ class LoginWindow(QMainWindow): self.disconnect_signals = DisconnectSignals() self.disconnect_signals.disconnected.connect(self._show_disconnect_dialog) + # 横幅动画相关 + self.promo_banner = None + self.banner_animation = None + self.banner_color_index = 0 + self.initUI() # 延迟设置版本检查器,确保WebSocket连接已建立 @@ -70,9 +75,9 @@ class LoginWindow(QMainWindow): def initUI(self): # 设置窗口基本属性 self.setWindowTitle(f'AI客服智能助手 v{config.APP_VERSION}') - self.setGeometry(300, 300, 450, 300) # 进一步减小窗口尺寸 - self.setMinimumSize(420, 280) # 设置更小的最小尺寸 - self.setMaximumSize(500, 350) # 设置最大尺寸,保持紧凑 + # 只设置宽度,高度自适应内容 + self.setFixedWidth(450) # 固定宽度 + # 不设置固定高度,让窗口根据内容自适应 # 窗口图标将由统一的任务栏修复模块设置,这里只做备用检查 print("[INFO] 窗口图标将由统一模块设置") @@ -81,34 +86,31 @@ class LoginWindow(QMainWindow): central_widget = QWidget() self.setCentralWidget(central_widget) - # 创建主布局 + # 创建主布局(最小化间距) main_layout = QVBoxLayout() - main_layout.setSpacing(15) # 减小间距 - main_layout.setContentsMargins(30, 20, 30, 20) # 减小边距 + main_layout.setSpacing(8) # 最小间距 + main_layout.setContentsMargins(25, 12, 25, 12) # 最小边距 central_widget.setLayout(main_layout) # 添加标题和副标题 title_label = QLabel('AI客服智能助手') title_label.setObjectName("title") title_label.setAlignment(Qt.AlignCenter) - title_label.setFont(QFont('Microsoft YaHei', 18, QFont.Bold)) # 减小字体 - title_label.setStyleSheet("color: #2c3e50; margin-bottom: 3px;") + title_label.setFont(QFont('Microsoft YaHei', 16, QFont.Bold)) # 稍微减小字体 + title_label.setStyleSheet("color: #2c3e50; margin-bottom: 2px;") main_layout.addWidget(title_label) # 添加副标题说明 subtitle_label = QLabel('智能连接多平台客服,提供AI自动回复服务') subtitle_label.setObjectName("subtitle") subtitle_label.setAlignment(Qt.AlignCenter) - subtitle_label.setFont(QFont('Microsoft YaHei', 9)) # 减小字体 - subtitle_label.setStyleSheet("color: #7f8c8d; margin-bottom: 10px;") + subtitle_label.setFont(QFont('Microsoft YaHei', 9)) + subtitle_label.setStyleSheet("color: #7f8c8d; margin-bottom: 5px;") main_layout.addWidget(subtitle_label) - # 添加少量垂直空间 - main_layout.addStretch(1) - - # 创建令牌输入区域 + # 创建令牌输入区域(移除额外间距) token_layout = QVBoxLayout() - token_layout.setSpacing(8) # 减小间距 + token_layout.setSpacing(6) # 最小间距 token_label = QLabel('访问令牌') token_label.setFont(QFont('Microsoft YaHei', 11, QFont.Bold)) # 减小字体 @@ -117,10 +119,10 @@ class LoginWindow(QMainWindow): self.token_input = QLineEdit() self.token_input.setPlaceholderText('请输入您的访问令牌以连接服务') self.token_input.setEchoMode(QLineEdit.Password) - self.token_input.setFont(QFont('Microsoft YaHei', 10)) # 减小字体 + self.token_input.setFont(QFont('Microsoft YaHei', 10)) # noinspection PyUnresolvedReferences self.token_input.returnPressed.connect(self.login) # 表示回车提交 - self.token_input.setMinimumHeight(38) # 减小输入框高度 + self.token_input.setMinimumHeight(34) # 最小输入框高度 # 预填已保存的令牌(如果存在) try: from config import get_saved_token @@ -136,8 +138,8 @@ class LoginWindow(QMainWindow): # 创建连接按钮 self.login_btn = QPushButton('连接服务') - self.login_btn.setFont(QFont('Microsoft YaHei', 11, QFont.Bold)) # 减小字体 - self.login_btn.setMinimumHeight(40) # 减小按钮高度 + self.login_btn.setFont(QFont('Microsoft YaHei', 11, QFont.Bold)) + self.login_btn.setMinimumHeight(36) # 最小按钮高度 self.login_btn.clicked.connect(self.login) # 表示点击提交 main_layout.addWidget(self.login_btn) @@ -145,12 +147,15 @@ class LoginWindow(QMainWindow): self.status_label = QLabel('等待连接...') self.status_label.setObjectName("status") self.status_label.setAlignment(Qt.AlignCenter) - self.status_label.setFont(QFont('Microsoft YaHei', 9)) # 减小字体 - self.status_label.setStyleSheet("color: #95a5a6; margin-top: 5px;") + self.status_label.setFont(QFont('Microsoft YaHei', 9)) + self.status_label.setStyleSheet("color: #95a5a6; margin-top: 2px;") main_layout.addWidget(self.status_label) - # 添加少量底部空间 - main_layout.addStretch(1) + # 添加最小间距(为横幅留出位置) + main_layout.addSpacing(8) + + # ============ 添加宣传横幅 ============ + self.create_promo_banner(main_layout) # 日志框已永久删除,只使用终端输出 self.log_display = None @@ -166,6 +171,161 @@ class LoginWindow(QMainWindow): # 系统初始化日志输出到终端 print("[INFO] 系统初始化完成") + + # 让窗口自适应内容高度(最小化) + self.adjustSize() + print("[INFO] 窗口已自适应内容大小") + + def create_promo_banner(self, layout): + """创建宣传横幅(带动态渐变效果)""" + try: + # 创建横幅容器(最小化高度) + banner_frame = QFrame() + banner_frame.setObjectName("promoBanner") + banner_frame.setCursor(Qt.PointingHandCursor) # 鼠标变手型 + banner_frame.setMinimumHeight(65) # 最小高度 + banner_frame.setMaximumHeight(65) # 固定高度 + + # 保存横幅引用,用于动画 + self.promo_banner = banner_frame + + # 横幅布局(最小内边距) + banner_layout = QHBoxLayout() + banner_layout.setContentsMargins(10, 6, 10, 6) # 最小内边距 + banner_layout.setSpacing(8) # 最小间距 + banner_frame.setLayout(banner_layout) + + # 左侧图标(最小化) + icon_label = QLabel("🎁") + icon_label.setFont(QFont('Microsoft YaHei', 22)) # 更小的图标字体 + icon_label.setAlignment(Qt.AlignCenter) + icon_label.setFixedSize(45, 45) # 更小的图标尺寸 + banner_layout.addWidget(icon_label) + + # 右侧文字区域 + text_layout = QVBoxLayout() + text_layout.setSpacing(1) # 最小文字间距 + + # 标题 + title_label = QLabel("🌟 限时优惠活动进行中") + title_label.setFont(QFont('Microsoft YaHei', 10, QFont.Bold)) # 更小字体 + title_label.setStyleSheet("color: white;") + text_layout.addWidget(title_label) + + # 副标题 + subtitle_label = QLabel("立即访问官网了解更多优惠详情 →") + subtitle_label.setFont(QFont('Microsoft YaHei', 8)) # 更小字体 + subtitle_label.setStyleSheet("color: rgba(255, 255, 255, 0.9);") + text_layout.addWidget(subtitle_label) + + banner_layout.addLayout(text_layout) + banner_layout.addStretch() + + # 初始样式(紫色渐变背景) + self.update_banner_style(0) + + # 添加阴影效果(更轻量) + shadow = QGraphicsDropShadowEffect() + shadow.setBlurRadius(10) # 减小模糊半径 + shadow.setXOffset(0) + shadow.setYOffset(2) # 减小偏移 + shadow.setColor(QColor(0, 0, 0, 40)) # 降低不透明度 + banner_frame.setGraphicsEffect(shadow) + + # 点击事件 - 跳转官网 + def open_official_website(): + try: + import webbrowser + official_url = "https://shuidrop.com/" + webbrowser.open(official_url) + self.add_log(f"已打开官网: {official_url}", "INFO") + except Exception as e: + self.add_log(f"打开官网失败: {e}", "ERROR") + + banner_frame.mousePressEvent = lambda event: open_official_website() + + # 添加到主布局 + layout.addWidget(banner_frame) + + # 启动颜色渐变动画 + self.start_banner_animation() + + print("[INFO] 宣传横幅已创建(带动态渐变效果)") + + except Exception as e: + print(f"[WARNING] 创建宣传横幅失败: {e}") + + def update_banner_style(self, color_index): + """更新横幅颜色样式""" + if not self.promo_banner: + return + + # 定义多组渐变颜色方案(呼吸效果) + color_schemes = [ + # 紫色(原色) + { + 'normal': ('667eea', '764ba2'), + 'hover': ('778ff5', '865cb3') + }, + # 深紫色(变暗) + { + 'normal': ('5a6dc8', '6a3f8f'), + 'hover': ('6b7ed9', '7b50a0') + }, + # 亮紫色(变亮) + { + 'normal': ('7890fc', '8658b4'), + 'hover': ('89a1ff', '9769c5') + }, + # 紫色(原色)- 循环 + { + 'normal': ('667eea', '764ba2'), + 'hover': ('778ff5', '865cb3') + } + ] + + scheme = color_schemes[color_index % len(color_schemes)] + + style = f""" + QFrame#promoBanner {{ + background: qlineargradient( + x1:0, y1:0, x2:1, y2:0, + stop:0 #{scheme['normal'][0]}, + stop:1 #{scheme['normal'][1]} + ); + border-radius: 12px; + border: 1px solid rgba(255, 255, 255, 0.2); + }} + QFrame#promoBanner:hover {{ + background: qlineargradient( + x1:0, y1:0, x2:1, y2:0, + stop:0 #{scheme['hover'][0]}, + stop:1 #{scheme['hover'][1]} + ); + }} + """ + + self.promo_banner.setStyleSheet(style) + + def start_banner_animation(self): + """启动横幅呼吸动画""" + try: + # 创建定时器,每2秒切换一次颜色 + self.banner_animation = QTimer(self) + self.banner_animation.timeout.connect(self.animate_banner_color) + self.banner_animation.start(2000) # 2秒间隔 + + print("[INFO] 横幅呼吸动画已启动") + except Exception as e: + print(f"[WARNING] 启动横幅动画失败: {e}") + + def animate_banner_color(self): + """动画:循环改变横幅颜色""" + try: + self.banner_color_index = (self.banner_color_index + 1) % 4 + self.update_banner_style(self.banner_color_index) + except Exception as e: + print(f"[WARNING] 横幅颜色动画失败: {e}") def apply_modern_styles(self): """应用现代化简约样式 - 精致美化版""" @@ -619,6 +779,11 @@ class LoginWindow(QMainWindow): """真正退出应用程序""" print("[INFO] 正在退出应用程序...") + # 停止横幅动画 + if hasattr(self, 'banner_animation') and self.banner_animation: + self.banner_animation.stop() + print("[INFO] 横幅动画已停止") + # 执行原来的关闭逻辑 try: # 使用 WebSocket 管理器断开所有连接 diff --git a/quick_build.py b/quick_build.py index 2a611ee..4bfc039 100644 --- a/quick_build.py +++ b/quick_build.py @@ -16,7 +16,7 @@ def clean_build(): # 跳过进程结束步骤,避免影响当前脚本运行 print("Skipping process termination step...") - + # 等待少量时间确保文件句柄释放 import time print("Waiting for file handles to release...") @@ -43,7 +43,7 @@ def clean_build(): print(f"ERROR: Failed to delete {dir_name}: {e}") else: print(f"INFO: {dir_name} does not exist, skipping") - + print("Cleaning phase completed") @@ -105,13 +105,13 @@ def build_with_command(): try: old_exe = 'dist/MultiPlatformGUI/MultiPlatformGUI.exe' new_exe = 'dist/MultiPlatformGUI/main.exe' - + if os.path.exists(new_exe): os.remove(new_exe) - + os.rename(old_exe, new_exe) print("Main executable renamed: MultiPlatformGUI.exe -> main.exe") - + exe_size = os.path.getsize(new_exe) / 1024 / 1024 print(f"Main executable verified: main.exe ({exe_size:.1f} MB)") except Exception as e: @@ -246,19 +246,20 @@ def verify_result(): print("TIP: Please check if PyInstaller executed successfully") return False + def _verify_directory(base_dir): """验证指定目录的打包结果""" # 检查可能的 exe 名称 exe_path = f"{base_dir}/main.exe" if not os.path.exists(exe_path): exe_path = f"{base_dir}/MultiPlatformGUI.exe" - + internal_dir = f"{base_dir}/_internal" dll_path = f"{base_dir}/_internal/Utils/PythonNew32/SaiNiuApi.dll" static_dir = f"{base_dir}/_internal/static" print(f"Verifying directory: {base_dir}") - + # 检查主程序 if os.path.exists(exe_path): size = os.path.getsize(exe_path) / 1024 / 1024 # MB @@ -304,8 +305,8 @@ def main(): print("Checking build dependencies...") try: import subprocess - result = subprocess.run(['pyinstaller', '--version'], - capture_output=True, text=True, check=False) + result = subprocess.run(['pyinstaller', '--version'], + capture_output=True, text=True, check=False) if result.returncode == 0: print(f"PyInstaller version: {result.stdout.strip()}") else: