diff --git a/APP Store.zip b/APP Store.zip index b730a83..f0b6be4 100644 Binary files a/APP Store.zip and b/APP Store.zip differ diff --git a/pyqt5fluentdesign/__pycache__/app_detail_window.cpython-312.pyc b/pyqt5fluentdesign/__pycache__/app_detail_window.cpython-312.pyc index 5db1fcf..37fca0e 100644 Binary files a/pyqt5fluentdesign/__pycache__/app_detail_window.cpython-312.pyc and b/pyqt5fluentdesign/__pycache__/app_detail_window.cpython-312.pyc differ diff --git a/pyqt5fluentdesign/leonapp_gui.py b/pyqt5fluentdesign/leonapp_gui.py index 322f3cf..c7e0449 100644 --- a/pyqt5fluentdesign/leonapp_gui.py +++ b/pyqt5fluentdesign/leonapp_gui.py @@ -240,10 +240,9 @@ class AppTab(QWidget): def show_app_detail(self, row, column): """显示应用详情""" app_id = self.table.item(row, 0).text() - # 直接创建应用详情窗口,而不是通过父对象调用方法 - from app_detail_window import AppDetailWindow - detail_window = AppDetailWindow(self.api_client, app_id, self) - detail_window.show() + # 直接创建应用详情窗口,使用文件顶部已导入的AppDetailWindow类 + self.app_detail_window = AppDetailWindow(self.api_client, app_id, self) + self.app_detail_window.show() def show_progress(self): """显示进度条""" @@ -353,6 +352,44 @@ class TagTab(QWidget): """隐藏进度条""" self.progress_bar.setVisible(False) + def download_version(self, version_id): + """下载指定版本""" + import webbrowser + + # 查找对应版本的文件路径 + file_path = None + for i in range(self.versions_table.rowCount()): + # 这里假设我们在填充表格时存储了版本ID作为item的data + version_item = self.versions_table.item(i, 0) + if version_item and hasattr(version_item, 'version_id') and version_item.version_id == version_id: + # 假设我们在填充表格时存储了文件路径 + if hasattr(version_item, 'file_path'): + file_path = version_item.file_path + break + + if file_path: + # 构建直接的文件URL + download_url = f"http://leonmmcoset.jjxmm.win:8010/{file_path}" + + try: + # 使用系统默认浏览器打开下载链接 + webbrowser.open(download_url) + + # 显示下载成功提示 + InfoBar.success( + title="下载开始", + content=f"下载已开始,请稍候...", + orient=Qt.Horizontal, + isClosable=True, + position=InfoBarPosition.BOTTOM_RIGHT, + duration=3000, + parent=self + ) + except Exception as e: + self.show_error(f"下载失败: {str(e)}") + else: + self.show_error("无法获取下载文件路径") + def show_error(self, message): """显示错误消息""" self.hide_progress() @@ -543,27 +580,76 @@ class AnnouncementTab(QWidget): """公告列表加载完成处理""" self.hide_progress() - if not data or 'announcements' not in data or 'pagination' not in data: - self.show_error("数据格式错误") + # 增强的数据格式验证,提供更具体的错误信息 + if data is None: + self.show_error("API返回数据为空") + return + + # 处理数据 - 如果是列表类型,转换为预期的字典格式 + processed_data = {} + if isinstance(data, list): + # API返回了列表,我们将其转换为预期的字典结构 + processed_data['announcements'] = data + # 构建简单的分页信息 + total_items = len(data) + total_pages = (total_items + self.items_per_page - 1) // self.items_per_page + processed_data['pagination'] = {'totalPages': total_pages} + elif isinstance(data, dict): + # 保留原有的字典处理逻辑,但添加更灵活的验证 + processed_data = data.copy() + + # 验证必要字段是否存在,如果不存在则使用默认值 + if 'announcements' not in processed_data: + processed_data['announcements'] = [] + elif not isinstance(processed_data['announcements'], list): + # 如果announcements不是列表,尝试转换或使用空列表 + try: + processed_data['announcements'] = [processed_data['announcements']] + except: + processed_data['announcements'] = [] + + if 'pagination' not in processed_data: + # 如果没有分页信息,计算简单的分页 + total_items = len(processed_data['announcements']) + total_pages = (total_items + self.items_per_page - 1) // self.items_per_page + processed_data['pagination'] = {'totalPages': total_pages} + elif not isinstance(processed_data['pagination'], dict): + # 如果pagination不是字典,创建默认分页信息 + processed_data['pagination'] = {'totalPages': 1} + + # 确保分页信息中有totalPages + if 'totalPages' not in processed_data['pagination']: + processed_data['pagination']['totalPages'] = 1 + else: + self.show_error(f"数据格式错误: 期望字典或列表类型,实际为{type(data).__name__}") return # 清空表格 self.announcement_list.setRowCount(0) - # 填充表格 - for announcement in data['announcements']: + # 填充表格,添加更健壮的数据处理 + for announcement in processed_data['announcements']: + # 确保announcement是字典类型 + if not isinstance(announcement, dict): + continue + row_pos = self.announcement_list.rowCount() self.announcement_list.insertRow(row_pos) - self.announcement_list.setItem(row_pos, 0, QTableWidgetItem(str(announcement.get('id', '')))) - self.announcement_list.setItem(row_pos, 1, QTableWidgetItem(announcement.get('title', ''))) - self.announcement_list.setItem(row_pos, 2, QTableWidgetItem(announcement.get('created_at', ''))) - self.announcement_list.setItem(row_pos, 3, QTableWidgetItem(str(announcement.get('admin_id', '')))) - - # 更新分页信息 - self.total_pages = data['pagination']['totalPages'] - self.page_label.setText(f"第 {self.current_page} 页,共 {self.total_pages} 页") + # 安全获取字段值,避免KeyError + self.announcement_list.setItem(row_pos, 0, QTableWidgetItem(str(announcement.get('id', '未知ID')))) + self.announcement_list.setItem(row_pos, 1, QTableWidgetItem(announcement.get('title', '无标题'))) + self.announcement_list.setItem(row_pos, 2, QTableWidgetItem(announcement.get('created_at', '未知时间'))) + self.announcement_list.setItem(row_pos, 3, QTableWidgetItem(str(announcement.get('admin_id', '未知管理员')))) + # 更新分页信息,增加异常处理 + try: + self.total_pages = int(processed_data['pagination']['totalPages']) + self.page_label.setText(f"第 {self.current_page} 页,共 {self.total_pages} 页") + except (ValueError, TypeError): + self.total_pages = 1 + self.page_label.setText(f"第 {self.current_page} 页,共 {self.total_pages} 页") + # 更新按钮状态 self.prev_button.setEnabled(self.current_page > 1) self.next_button.setEnabled(self.current_page < self.total_pages) @@ -584,20 +670,81 @@ class AnnouncementTab(QWidget): """显示公告详情""" announcement_id = self.announcement_list.item(row, 0).text() title = self.announcement_list.item(row, 1).text() + created_at = self.announcement_list.item(row, 2).text() + # 查找完整的公告数据 for i in range(self.announcement_list.rowCount()): if self.announcement_list.item(i, 0).text() == announcement_id: - # 这里可以添加获取公告详情的逻辑 - InfoBar.info( - title="公告详情", - content=f"标题: {title}\nID: {announcement_id}", - orient=Qt.Horizontal, - isClosable=True, - position=InfoBarPosition.BOTTOM_RIGHT, - duration=5000, - parent=self + # 获取完整的公告内容 + # 由于表格中没有直接存储content,我们需要重新获取 + self.show_progress() + self.detail_worker = WorkerThread( + self.api_client, + 'getacc', + {'page': 1, 'limit': 100} # 获取足够多的公告以确保找到目标公告 ) + self.detail_worker.finished.connect(lambda data, aid=announcement_id, t=title, ca=created_at: + self.on_announcement_detail_loaded(data, aid, t, ca)) + self.detail_worker.progress.connect(self.update_progress) + self.detail_worker.error.connect(self.show_error) + self.detail_worker.start() break + + def on_announcement_detail_loaded(self, data, announcement_id, title, created_at): + """公告详情加载完成处理""" + self.hide_progress() + + # 增强的数据格式验证 + if data is None: + self.show_error("获取公告详情失败: API返回数据为空") + return + + # 处理数据 - 支持字典或列表类型 + processed_data = {} + if isinstance(data, list): + # API返回了列表,转换为预期的字典结构 + processed_data['announcements'] = data + elif isinstance(data, dict): + # 保留字典处理逻辑,但添加更灵活的验证 + processed_data = data.copy() + + # 验证必要字段是否存在 + if 'announcements' not in processed_data: + processed_data['announcements'] = [] + elif not isinstance(processed_data['announcements'], list): + # 尝试转换announcements为列表类型 + try: + processed_data['announcements'] = [processed_data['announcements']] + except: + processed_data['announcements'] = [] + else: + self.show_error(f"获取公告详情失败: 数据格式错误,期望字典或列表类型,实际为{type(data).__name__}") + return + + # 查找特定的公告,增加异常处理 + content = "无内容" + try: + for announcement in processed_data['announcements']: + if not isinstance(announcement, dict): + continue + + if str(announcement.get('id', '')) == announcement_id: + content = announcement.get('content', '无内容') + break + except Exception as e: + self.show_error(f"查找公告详情时发生错误: {str(e)}") + return + + # 使用Sweet Alert风格的弹窗显示公告详情 + InfoBar.info( + title="公告详情", + content=f"标题: {title}\n\n发布时间: {created_at}\n\n内容:\n{content}", + orient=Qt.Horizontal, + isClosable=True, + position=InfoBarPosition.BOTTOM_RIGHT, + duration=10000, # 增加显示时间以便阅读 + parent=self + ) def show_progress(self): """显示进度条""" @@ -856,17 +1003,65 @@ class AppDetailWindow(QMainWindow): self.view_all_versions_button = PushButton("查看全部版本") self.view_all_versions_button.clicked.connect(lambda: self.view_all_versions()) self.info_layout.addWidget(self.view_all_versions_button) + + # 添加下载最新版本按钮 + if data['versions']: + # 保存最新版本信息用于下载 + self.latest_version = data['versions'][0] + download_layout = QHBoxLayout() + download_layout.addStretch(1) + + self.download_button = PushButton("下载最新版本") + self.download_button.setIcon(FluentIcon.DOWNLOAD) + self.download_button.clicked.connect(self.download_latest_version) + download_layout.addWidget(self.download_button) + + self.info_layout.addLayout(download_layout) def view_all_versions(self): """查看全部版本""" versions_window = AppVersionsWindow(self.api_client, self.app_id, self.app_title.text(), self) versions_window.show() - # 添加图片数量信息 - if 'images' in data and data['images']: - images_label = SubtitleLabel("图片") - self.info_layout.addWidget(images_label) - self.info_layout.addWidget(CaptionLabel(f"共 {len(data['images'])} 张图片")) + def download_latest_version(self): + """下载最新版本""" + if hasattr(self, 'latest_version'): + version_id = self.latest_version.get('id', '') + if version_id: + self.perform_download(version_id) + else: + self.show_error("无法获取版本ID") + else: + self.show_error("没有可下载的版本") + + def perform_download(self, version_id): + """执行下载操作""" + import webbrowser + + # 直接使用latest_version中的file_path进行下载 + if hasattr(self, 'latest_version') and 'file_path' in self.latest_version: + file_path = self.latest_version['file_path'] + # 构建直接的文件URL + download_url = f"http://leonmmcoset.jjxmm.win:8010/{file_path}" + + try: + # 使用系统默认浏览器打开下载链接 + webbrowser.open(download_url) + + # 显示下载成功提示 + InfoBar.success( + title="下载开始", + content=f"下载已开始,请稍候...", + orient=Qt.Horizontal, + isClosable=True, + position=InfoBarPosition.BOTTOM_RIGHT, + duration=3000, + parent=self + ) + except Exception as e: + self.show_error(f"下载失败: {str(e)}") + else: + self.show_error("无法获取下载文件路径") def show_progress(self): """显示进度条""" @@ -1323,8 +1518,8 @@ class AppVersionsWindow(QMainWindow): # 创建版本列表 self.versions_table = TableWidget() - self.versions_table.setColumnCount(5) - self.versions_table.setHorizontalHeaderLabels(["版本号", "发布日期", "操作系统", "文件大小", "下载量"]) + self.versions_table.setColumnCount(6) + self.versions_table.setHorizontalHeaderLabels(["版本号", "发布日期", "操作系统", "文件大小", "下载量", "操作"]) main_layout.addWidget(self.versions_table) # 创建分页控件 @@ -1385,12 +1580,33 @@ class AppVersionsWindow(QMainWindow): row_position = self.versions_table.rowCount() self.versions_table.insertRow(row_position) - # 添加版本数据 - self.versions_table.setItem(row_position, 0, QTableWidgetItem(version.get('version', '未知'))) + # 添加版本数据并存储版本ID和文件路径 + version_item = QTableWidgetItem(version.get('version', '未知')) + # 存储版本ID和文件路径信息 + version_item.version_id = version.get('id', '') + version_item.file_path = version.get('file_path', '') + self.versions_table.setItem(row_position, 0, version_item) + self.versions_table.setItem(row_position, 1, QTableWidgetItem(version.get('created_at', '未知'))) self.versions_table.setItem(row_position, 2, QTableWidgetItem(version.get('platform', '未知'))) self.versions_table.setItem(row_position, 3, QTableWidgetItem(version.get('file_size', '未知'))) self.versions_table.setItem(row_position, 4, QTableWidgetItem(str(version.get('download_count', 0)))) + + # 添加下载按钮 + download_button = PushButton("下载") + download_button.setIcon(FluentIcon.DOWNLOAD) + # 将版本ID绑定到按钮上 + version_id = version.get('id', '') + download_button.clicked.connect(lambda checked, vid=version_id: self.download_version(vid)) + + # 创建按钮容器并添加按钮 + button_container = QWidget() + button_layout = QHBoxLayout(button_container) + button_layout.setContentsMargins(5, 5, 5, 5) + button_layout.addWidget(download_button) + button_container.setLayout(button_layout) + + self.versions_table.setCellWidget(row_position, 5, button_container) # 自动调整列宽 self.versions_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) @@ -1440,7 +1656,7 @@ class LeonAppGUI(FluentWindow): # 初始化API客户端 self.api_client = APIClient() # 设置窗口标题和大小 - self.setWindowTitle("LeonApp GUI") + self.setWindowTitle("LeonApp For PC") self.resize(1000, 700) # 初始化UI self.init_ui()