feat: 增强应用详情和公告功能并添加下载支持
- 在应用详情窗口添加下载最新版本功能 - 为版本列表添加下载按钮和操作列 - 增强公告列表和详情的数据处理逻辑 - 优化错误处理和用户反馈 - 修改窗口标题为"LeonApp For PC"
This commit is contained in:
BIN
APP Store.zip
BIN
APP Store.zip
Binary file not shown.
Binary file not shown.
@@ -240,10 +240,9 @@ class AppTab(QWidget):
|
|||||||
def show_app_detail(self, row, column):
|
def show_app_detail(self, row, column):
|
||||||
"""显示应用详情"""
|
"""显示应用详情"""
|
||||||
app_id = self.table.item(row, 0).text()
|
app_id = self.table.item(row, 0).text()
|
||||||
# 直接创建应用详情窗口,而不是通过父对象调用方法
|
# 直接创建应用详情窗口,使用文件顶部已导入的AppDetailWindow类
|
||||||
from app_detail_window import AppDetailWindow
|
self.app_detail_window = AppDetailWindow(self.api_client, app_id, self)
|
||||||
detail_window = AppDetailWindow(self.api_client, app_id, self)
|
self.app_detail_window.show()
|
||||||
detail_window.show()
|
|
||||||
|
|
||||||
def show_progress(self):
|
def show_progress(self):
|
||||||
"""显示进度条"""
|
"""显示进度条"""
|
||||||
@@ -353,6 +352,44 @@ class TagTab(QWidget):
|
|||||||
"""隐藏进度条"""
|
"""隐藏进度条"""
|
||||||
self.progress_bar.setVisible(False)
|
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):
|
def show_error(self, message):
|
||||||
"""显示错误消息"""
|
"""显示错误消息"""
|
||||||
self.hide_progress()
|
self.hide_progress()
|
||||||
@@ -543,27 +580,76 @@ class AnnouncementTab(QWidget):
|
|||||||
"""公告列表加载完成处理"""
|
"""公告列表加载完成处理"""
|
||||||
self.hide_progress()
|
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
|
return
|
||||||
|
|
||||||
# 清空表格
|
# 清空表格
|
||||||
self.announcement_list.setRowCount(0)
|
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()
|
row_pos = self.announcement_list.rowCount()
|
||||||
self.announcement_list.insertRow(row_pos)
|
self.announcement_list.insertRow(row_pos)
|
||||||
|
|
||||||
self.announcement_list.setItem(row_pos, 0, QTableWidgetItem(str(announcement.get('id', ''))))
|
# 安全获取字段值,避免KeyError
|
||||||
self.announcement_list.setItem(row_pos, 1, QTableWidgetItem(announcement.get('title', '')))
|
self.announcement_list.setItem(row_pos, 0, QTableWidgetItem(str(announcement.get('id', '未知ID'))))
|
||||||
self.announcement_list.setItem(row_pos, 2, QTableWidgetItem(announcement.get('created_at', '')))
|
self.announcement_list.setItem(row_pos, 1, QTableWidgetItem(announcement.get('title', '无标题')))
|
||||||
self.announcement_list.setItem(row_pos, 3, QTableWidgetItem(str(announcement.get('admin_id', ''))))
|
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} 页")
|
|
||||||
|
|
||||||
|
# 更新分页信息,增加异常处理
|
||||||
|
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.prev_button.setEnabled(self.current_page > 1)
|
||||||
self.next_button.setEnabled(self.current_page < self.total_pages)
|
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()
|
announcement_id = self.announcement_list.item(row, 0).text()
|
||||||
title = self.announcement_list.item(row, 1).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()):
|
for i in range(self.announcement_list.rowCount()):
|
||||||
if self.announcement_list.item(i, 0).text() == announcement_id:
|
if self.announcement_list.item(i, 0).text() == announcement_id:
|
||||||
# 这里可以添加获取公告详情的逻辑
|
# 获取完整的公告内容
|
||||||
InfoBar.info(
|
# 由于表格中没有直接存储content,我们需要重新获取
|
||||||
title="公告详情",
|
self.show_progress()
|
||||||
content=f"标题: {title}\nID: {announcement_id}",
|
self.detail_worker = WorkerThread(
|
||||||
orient=Qt.Horizontal,
|
self.api_client,
|
||||||
isClosable=True,
|
'getacc',
|
||||||
position=InfoBarPosition.BOTTOM_RIGHT,
|
{'page': 1, 'limit': 100} # 获取足够多的公告以确保找到目标公告
|
||||||
duration=5000,
|
|
||||||
parent=self
|
|
||||||
)
|
)
|
||||||
|
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
|
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):
|
def show_progress(self):
|
||||||
"""显示进度条"""
|
"""显示进度条"""
|
||||||
@@ -856,17 +1003,65 @@ class AppDetailWindow(QMainWindow):
|
|||||||
self.view_all_versions_button = PushButton("查看全部版本")
|
self.view_all_versions_button = PushButton("查看全部版本")
|
||||||
self.view_all_versions_button.clicked.connect(lambda: self.view_all_versions())
|
self.view_all_versions_button.clicked.connect(lambda: self.view_all_versions())
|
||||||
self.info_layout.addWidget(self.view_all_versions_button)
|
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):
|
def view_all_versions(self):
|
||||||
"""查看全部版本"""
|
"""查看全部版本"""
|
||||||
versions_window = AppVersionsWindow(self.api_client, self.app_id, self.app_title.text(), self)
|
versions_window = AppVersionsWindow(self.api_client, self.app_id, self.app_title.text(), self)
|
||||||
versions_window.show()
|
versions_window.show()
|
||||||
|
|
||||||
# 添加图片数量信息
|
def download_latest_version(self):
|
||||||
if 'images' in data and data['images']:
|
"""下载最新版本"""
|
||||||
images_label = SubtitleLabel("图片")
|
if hasattr(self, 'latest_version'):
|
||||||
self.info_layout.addWidget(images_label)
|
version_id = self.latest_version.get('id', '')
|
||||||
self.info_layout.addWidget(CaptionLabel(f"共 {len(data['images'])} 张图片"))
|
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):
|
def show_progress(self):
|
||||||
"""显示进度条"""
|
"""显示进度条"""
|
||||||
@@ -1323,8 +1518,8 @@ class AppVersionsWindow(QMainWindow):
|
|||||||
|
|
||||||
# 创建版本列表
|
# 创建版本列表
|
||||||
self.versions_table = TableWidget()
|
self.versions_table = TableWidget()
|
||||||
self.versions_table.setColumnCount(5)
|
self.versions_table.setColumnCount(6)
|
||||||
self.versions_table.setHorizontalHeaderLabels(["版本号", "发布日期", "操作系统", "文件大小", "下载量"])
|
self.versions_table.setHorizontalHeaderLabels(["版本号", "发布日期", "操作系统", "文件大小", "下载量", "操作"])
|
||||||
main_layout.addWidget(self.versions_table)
|
main_layout.addWidget(self.versions_table)
|
||||||
|
|
||||||
# 创建分页控件
|
# 创建分页控件
|
||||||
@@ -1385,12 +1580,33 @@ class AppVersionsWindow(QMainWindow):
|
|||||||
row_position = self.versions_table.rowCount()
|
row_position = self.versions_table.rowCount()
|
||||||
self.versions_table.insertRow(row_position)
|
self.versions_table.insertRow(row_position)
|
||||||
|
|
||||||
# 添加版本数据
|
# 添加版本数据并存储版本ID和文件路径
|
||||||
self.versions_table.setItem(row_position, 0, QTableWidgetItem(version.get('version', '未知')))
|
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, 1, QTableWidgetItem(version.get('created_at', '未知')))
|
||||||
self.versions_table.setItem(row_position, 2, QTableWidgetItem(version.get('platform', '未知')))
|
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, 3, QTableWidgetItem(version.get('file_size', '未知')))
|
||||||
self.versions_table.setItem(row_position, 4, QTableWidgetItem(str(version.get('download_count', 0))))
|
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)
|
self.versions_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
@@ -1440,7 +1656,7 @@ class LeonAppGUI(FluentWindow):
|
|||||||
# 初始化API客户端
|
# 初始化API客户端
|
||||||
self.api_client = APIClient()
|
self.api_client = APIClient()
|
||||||
# 设置窗口标题和大小
|
# 设置窗口标题和大小
|
||||||
self.setWindowTitle("LeonApp GUI")
|
self.setWindowTitle("LeonApp For PC")
|
||||||
self.resize(1000, 700)
|
self.resize(1000, 700)
|
||||||
# 初始化UI
|
# 初始化UI
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
|
|||||||
Reference in New Issue
Block a user