feat: 增强应用详情和公告功能并添加下载支持

- 在应用详情窗口添加下载最新版本功能
- 为版本列表添加下载按钮和操作列
- 增强公告列表和详情的数据处理逻辑
- 优化错误处理和用户反馈
- 修改窗口标题为"LeonApp For PC"
This commit is contained in:
2025-09-21 18:17:37 +08:00
parent c841ac556d
commit 1586822845
3 changed files with 251 additions and 35 deletions

View File

@@ -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()