Files
leonapp/pyqt5fluentdesign/leonapp_gui.py
Leonmmcoset dd85397efa feat(app_detail_window): 新增应用详情窗口独立组件
refactor(leonapp_gui): 重构应用详情展示逻辑,直接创建窗口实例
fix(version_control.php): 修复文件路径处理和删除逻辑问题
feat(upload_app.php): 添加Markdown预览功能
style(dashboard.php): 移除冗余的padding样式
chore: 更新favicon和清理pyc缓存文件
2025-09-21 17:02:11 +08:00

1363 lines
49 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
LeonApp GUI - 基于PyQt5和Fluent Design的App Store API图形界面工具
"""
import sys
import json
import requests
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QTabWidget, QWidget, QVBoxLayout, QHBoxLayout,
QTableWidgetItem
)
from PyQt5.QtCore import Qt, pyqtSignal, QThread
from qfluentwidgets import (
CardWidget, TitleLabel, SubtitleLabel, CaptionLabel, PushButton,
PrimaryPushButton, LineEdit, ComboBox, ProgressBar, TableWidget,
ScrollArea, InfoBar, InfoBarPosition, NavigationInterface, NavigationItemPosition,
FluentWindow, FluentIcon
)
from qfluentwidgets import FluentTranslator
class APIClient:
"""API客户端类处理与API的通信"""
def __init__(self, api_base_url="http://leonmmcoset.jjxmm.win:8010/api.php"):
self.api_base_url = api_base_url
def make_request(self, endpoint_type, params=None):
"""基础API请求函数"""
if params is None:
params = {}
# 添加API类型参数
params['t'] = endpoint_type
try:
response = requests.get(self.api_base_url, params=params, timeout=30)
response.raise_for_status() # 抛出HTTP错误
data = response.json()
if data.get('status') == 'error':
return {'error': data.get('message', '未知错误')}
return {'success': True, 'data': data.get('data')}
except requests.exceptions.RequestException as e:
return {'error': f"请求异常: {str(e)}"}
except json.JSONDecodeError:
return {'error': "无法解析响应"}
class WorkerThread(QThread):
"""工作线程用于在后台执行API请求"""
# 使用object类型以接受任何数据类型dict、list等
finished = pyqtSignal(object)
progress = pyqtSignal(int)
error = pyqtSignal(str)
def __init__(self, api_client, endpoint_type, params=None):
super().__init__()
self.api_client = api_client
self.endpoint_type = endpoint_type
self.params = params or {}
def run(self):
"""线程运行函数"""
try:
self.progress.emit(10)
result = self.api_client.make_request(self.endpoint_type, self.params)
self.progress.emit(100)
if 'error' in result:
self.error.emit(result['error'])
else:
# 确保数据是可序列化的对象
if isinstance(result['data'], (dict, list, str, int, float, bool, type(None))):
self.finished.emit(result['data'])
else:
self.error.emit(f"API返回的数据类型不支持: {type(result['data'])}")
except Exception as e:
self.error.emit(f"执行错误: {str(e)}")
class AppTab(QWidget):
"""应用列表标签页"""
def __init__(self, api_client, parent=None):
super().__init__(parent)
self.api_client = api_client
# 先初始化分页相关变量因为init_ui()内部会调用load_apps()
self.current_page = 1
self.items_per_page = 20
self.total_pages = 1
self.init_ui()
def init_ui(self):
"""初始化界面"""
# 创建主布局
layout = QVBoxLayout(self)
layout.setContentsMargins(20, 20, 20, 20)
# 创建标题
title = TitleLabel("应用列表")
layout.addWidget(title)
# 创建搜索和过滤器区域
filter_layout = QHBoxLayout()
filter_layout.setContentsMargins(0, 10, 0, 10)
self.search_input = LineEdit()
self.search_input.setPlaceholderText("搜索应用...")
filter_layout.addWidget(self.search_input, 3)
filter_layout.addSpacing(10)
self.page_size_combo = ComboBox()
self.page_size_combo.addItems(["10", "20", "50", "100"])
self.page_size_combo.setCurrentText("20")
self.page_size_combo.currentTextChanged.connect(self.on_page_size_changed)
filter_layout.addWidget(CaptionLabel("每页显示:"))
filter_layout.addWidget(self.page_size_combo)
filter_layout.addSpacing(10)
search_button = PrimaryPushButton("搜索")
search_button.clicked.connect(self.search_apps)
filter_layout.addWidget(search_button)
layout.addLayout(filter_layout)
# 创建表格
self.table = TableWidget()
self.table.setColumnCount(5)
self.table.setHorizontalHeaderLabels(["ID", "应用名称", "版本", "评分", "下载量"])
self.table.horizontalHeader().setSectionResizeMode(1, 3)
self.table.cellDoubleClicked.connect(self.show_app_detail)
layout.addWidget(self.table)
# 创建分页控制
pagination_layout = QHBoxLayout()
pagination_layout.setContentsMargins(0, 10, 0, 0)
self.prev_button = PushButton("上一页")
self.prev_button.clicked.connect(self.prev_page)
pagination_layout.addWidget(self.prev_button)
self.page_label = CaptionLabel("第 1 页,共 1 页")
pagination_layout.addWidget(self.page_label, alignment=Qt.AlignCenter)
self.next_button = PushButton("下一页")
self.next_button.clicked.connect(self.next_page)
pagination_layout.addWidget(self.next_button)
layout.addLayout(pagination_layout)
# 创建进度条
self.progress_bar = ProgressBar()
self.progress_bar.setVisible(False)
layout.addWidget(self.progress_bar)
# 加载初始数据
self.load_apps()
def load_apps(self):
"""加载应用列表"""
self.show_progress()
self.worker = WorkerThread(
self.api_client,
'getallapps',
{'page': self.current_page, 'limit': self.items_per_page}
)
self.worker.finished.connect(self.on_apps_loaded)
self.worker.progress.connect(self.update_progress)
self.worker.error.connect(self.show_error)
self.worker.start()
def on_apps_loaded(self, data):
"""应用列表加载完成处理"""
self.hide_progress()
if not data or 'apps' not in data or 'pagination' not in data:
self.show_error("数据格式错误")
return
# 清空表格
self.table.setRowCount(0)
# 填充表格
for app in data['apps']:
row_pos = self.table.rowCount()
self.table.insertRow(row_pos)
self.table.setItem(row_pos, 0, QTableWidgetItem(str(app.get('id', ''))))
self.table.setItem(row_pos, 1, QTableWidgetItem(app.get('name', '')))
self.table.setItem(row_pos, 2, QTableWidgetItem(app.get('version', '')))
self.table.setItem(row_pos, 3, QTableWidgetItem(str(app.get('avg_rating', '暂无'))))
self.table.setItem(row_pos, 4, QTableWidgetItem(str(app.get('total_downloads', 0))))
# 更新分页信息
self.total_pages = data['pagination']['totalPages']
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)
def search_apps(self):
"""搜索应用"""
search_text = self.search_input.text().strip()
if search_text:
self.current_page = 1
self.show_progress()
self.worker = WorkerThread(
self.api_client,
'getallapps',
{'page': 1, 'limit': self.items_per_page, 'search': search_text}
)
self.worker.finished.connect(self.on_apps_loaded)
self.worker.progress.connect(self.update_progress)
self.worker.error.connect(self.show_error)
self.worker.start()
else:
self.load_apps()
def prev_page(self):
"""上一页"""
if self.current_page > 1:
self.current_page -= 1
self.load_apps()
def next_page(self):
"""下一页"""
if self.current_page < self.total_pages:
self.current_page += 1
self.load_apps()
def on_page_size_changed(self, value):
"""每页显示数量变化"""
self.items_per_page = int(value)
self.current_page = 1
self.load_apps()
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()
def show_progress(self):
"""显示进度条"""
self.progress_bar.setVisible(True)
self.progress_bar.setValue(0)
def update_progress(self, value):
"""更新进度条"""
self.progress_bar.setValue(value)
def hide_progress(self):
"""隐藏进度条"""
self.progress_bar.setVisible(False)
def show_error(self, message):
"""显示错误消息"""
self.hide_progress()
# 使用Sweet Alert风格的弹窗
InfoBar.error(
title="错误",
content=message,
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.BOTTOM_RIGHT,
duration=5000,
parent=self
)
class TagTab(QWidget):
"""标签管理标签页"""
def __init__(self, api_client, parent=None):
super().__init__(parent)
self.api_client = api_client
self.init_ui()
def init_ui(self):
"""初始化界面"""
# 创建主布局
layout = QVBoxLayout(self)
layout.setContentsMargins(20, 20, 20, 20)
# 创建标题
title = TitleLabel("标签管理")
layout.addWidget(title)
# 创建标签列表
self.tag_list = TableWidget()
self.tag_list.setColumnCount(2)
self.tag_list.setHorizontalHeaderLabels(["ID", "标签名称"])
self.tag_list.cellDoubleClicked.connect(self.show_tag_apps)
layout.addWidget(self.tag_list)
# 创建进度条
self.progress_bar = ProgressBar()
self.progress_bar.setVisible(False)
layout.addWidget(self.progress_bar)
# 加载标签数据
self.load_tags()
def load_tags(self):
"""加载标签数据"""
self.show_progress()
self.worker = WorkerThread(self.api_client, 'getalltags')
self.worker.finished.connect(self.on_tags_loaded)
self.worker.progress.connect(self.update_progress)
self.worker.error.connect(self.show_error)
self.worker.start()
def on_tags_loaded(self, data):
"""标签数据加载完成处理"""
self.hide_progress()
if not data:
self.show_error("数据加载失败")
return
# 清空表格
self.tag_list.setRowCount(0)
# 填充表格
for tag in data:
row_pos = self.tag_list.rowCount()
self.tag_list.insertRow(row_pos)
self.tag_list.setItem(row_pos, 0, QTableWidgetItem(str(tag.get('id', ''))))
self.tag_list.setItem(row_pos, 1, QTableWidgetItem(tag.get('name', '')))
def show_tag_apps(self, row, column):
"""显示标签下的应用"""
tag_id = self.tag_list.item(row, 0).text()
tag_name = self.tag_list.item(row, 1).text()
# 直接创建并显示标签应用窗口而不是调用parent方法
tag_apps_window = TagAppsWindow(self.api_client, tag_id, tag_name, self)
tag_apps_window.show()
def show_progress(self):
"""显示进度条"""
self.progress_bar.setVisible(True)
self.progress_bar.setValue(0)
def update_progress(self, value):
"""更新进度条"""
self.progress_bar.setValue(value)
def hide_progress(self):
"""隐藏进度条"""
self.progress_bar.setVisible(False)
def show_error(self, message):
"""显示错误消息"""
self.hide_progress()
InfoBar.error(
title="错误",
content=message,
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.BOTTOM_RIGHT,
duration=5000,
parent=self
)
class DeveloperTab(QWidget):
"""开发者管理标签页"""
def __init__(self, api_client, parent=None):
super().__init__(parent)
self.api_client = api_client
self.init_ui()
def init_ui(self):
"""初始化界面"""
# 创建主布局
layout = QVBoxLayout(self)
layout.setContentsMargins(20, 20, 20, 20)
# 创建标题
title = TitleLabel("开发者管理")
layout.addWidget(title)
# 创建开发者ID输入框和按钮
input_layout = QHBoxLayout()
input_layout.setContentsMargins(0, 10, 0, 10)
self.developer_id_input = LineEdit()
self.developer_id_input.setPlaceholderText("输入开发者ID...")
input_layout.addWidget(self.developer_id_input, 3)
input_layout.addSpacing(10)
app_list_button = PrimaryPushButton("查看应用列表")
app_list_button.clicked.connect(self.show_developer_apps)
input_layout.addWidget(app_list_button)
input_layout.addSpacing(10)
info_button = PushButton("查看开发者信息")
info_button.clicked.connect(self.show_developer_info)
input_layout.addWidget(info_button)
layout.addLayout(input_layout)
# 创建进度条
self.progress_bar = ProgressBar()
self.progress_bar.setVisible(False)
layout.addWidget(self.progress_bar)
def show_developer_apps(self):
"""查看开发者的应用列表"""
developer_id = self.developer_id_input.text().strip()
if developer_id:
# 直接创建并显示开发者应用窗口而不是调用parent方法
developer_apps_window = DeveloperAppsWindow(self.api_client, developer_id, self)
developer_apps_window.show()
else:
InfoBar.warning(
title="警告",
content="请输入开发者ID",
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.BOTTOM_RIGHT,
duration=3000,
parent=self
)
def show_developer_info(self):
"""查看开发者信息"""
developer_id = self.developer_id_input.text().strip()
if developer_id:
# 直接创建并显示开发者信息窗口而不是调用parent方法
developer_info_window = DeveloperInfoWindow(self.api_client, developer_id, self)
developer_info_window.show()
else:
InfoBar.warning(
title="警告",
content="请输入开发者ID",
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.BOTTOM_RIGHT,
duration=3000,
parent=self
)
def show_progress(self):
"""显示进度条"""
self.progress_bar.setVisible(True)
self.progress_bar.setValue(0)
def update_progress(self, value):
"""更新进度条"""
self.progress_bar.setValue(value)
def hide_progress(self):
"""隐藏进度条"""
self.progress_bar.setVisible(False)
def show_error(self, message):
"""显示错误消息"""
self.hide_progress()
InfoBar.error(
title="错误",
content=message,
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.BOTTOM_RIGHT,
duration=5000,
parent=self
)
class AnnouncementTab(QWidget):
"""公告管理标签页"""
def __init__(self, api_client, parent=None):
super().__init__(parent)
self.api_client = api_client
# 先初始化分页相关变量因为init_ui()内部会调用load_announcements()
self.current_page = 1
self.items_per_page = 20
self.total_pages = 1
self.init_ui()
def init_ui(self):
"""初始化界面"""
# 创建主布局
layout = QVBoxLayout(self)
layout.setContentsMargins(20, 20, 20, 20)
# 创建标题
title = TitleLabel("公告管理")
layout.addWidget(title)
# 创建分页控制
pagination_layout = QHBoxLayout()
pagination_layout.setContentsMargins(0, 10, 0, 10)
self.prev_button = PushButton("上一页")
self.prev_button.clicked.connect(self.prev_page)
pagination_layout.addWidget(self.prev_button)
self.page_label = CaptionLabel("第 1 页,共 1 页")
pagination_layout.addWidget(self.page_label, alignment=Qt.AlignCenter)
self.next_button = PushButton("下一页")
self.next_button.clicked.connect(self.next_page)
pagination_layout.addWidget(self.next_button)
layout.addLayout(pagination_layout)
# 创建公告列表
self.announcement_list = TableWidget()
self.announcement_list.setColumnCount(4)
self.announcement_list.setHorizontalHeaderLabels(["ID", "标题", "发布时间", "管理员ID"])
self.announcement_list.horizontalHeader().setSectionResizeMode(1, 3)
self.announcement_list.cellDoubleClicked.connect(self.show_announcement_detail)
layout.addWidget(self.announcement_list)
# 创建进度条
self.progress_bar = ProgressBar()
self.progress_bar.setVisible(False)
layout.addWidget(self.progress_bar)
# 加载初始数据
self.load_announcements()
def load_announcements(self):
"""加载公告列表"""
self.show_progress()
self.worker = WorkerThread(
self.api_client,
'getacc',
{'page': self.current_page, 'limit': self.items_per_page}
)
self.worker.finished.connect(self.on_announcements_loaded)
self.worker.progress.connect(self.update_progress)
self.worker.error.connect(self.show_error)
self.worker.start()
def on_announcements_loaded(self, data):
"""公告列表加载完成处理"""
self.hide_progress()
if not data or 'announcements' not in data or 'pagination' not in data:
self.show_error("数据格式错误")
return
# 清空表格
self.announcement_list.setRowCount(0)
# 填充表格
for announcement in data['announcements']:
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}")
# 更新按钮状态
self.prev_button.setEnabled(self.current_page > 1)
self.next_button.setEnabled(self.current_page < self.total_pages)
def prev_page(self):
"""上一页"""
if self.current_page > 1:
self.current_page -= 1
self.load_announcements()
def next_page(self):
"""下一页"""
if self.current_page < self.total_pages:
self.current_page += 1
self.load_announcements()
def show_announcement_detail(self, row, column):
"""显示公告详情"""
announcement_id = self.announcement_list.item(row, 0).text()
title = self.announcement_list.item(row, 1).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
)
break
def show_progress(self):
"""显示进度条"""
self.progress_bar.setVisible(True)
self.progress_bar.setValue(0)
def update_progress(self, value):
"""更新进度条"""
self.progress_bar.setValue(value)
def hide_progress(self):
"""隐藏进度条"""
self.progress_bar.setVisible(False)
def show_error(self, message):
"""显示错误消息"""
self.hide_progress()
InfoBar.error(
title="错误",
content=message,
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.BOTTOM_RIGHT,
duration=5000,
parent=self
)
class StatsTab(QWidget):
"""统计信息标签页"""
def __init__(self, api_client, parent=None):
super().__init__(parent)
self.api_client = api_client
self.init_ui()
def init_ui(self):
"""初始化界面"""
# 创建主布局
layout = QVBoxLayout(self)
layout.setContentsMargins(20, 20, 20, 20)
# 创建标题
title = TitleLabel("应用商店统计信息")
layout.addWidget(title)
# 创建统计卡片容器
cards_layout = QVBoxLayout()
cards_layout.setSpacing(20)
# 创建统计卡片
self.app_count_card = CardWidget()
self.app_count_card.setMinimumHeight(100)
self.app_count_layout = QVBoxLayout(self.app_count_card)
self.app_count_title = SubtitleLabel("应用总数")
self.app_count_value = TitleLabel("--")
self.app_count_layout.addWidget(self.app_count_title)
self.app_count_layout.addWidget(self.app_count_value, alignment=Qt.AlignCenter)
cards_layout.addWidget(self.app_count_card)
self.developer_count_card = CardWidget()
self.developer_count_card.setMinimumHeight(100)
self.developer_count_layout = QVBoxLayout(self.developer_count_card)
self.developer_count_title = SubtitleLabel("开发者总数")
self.developer_count_value = TitleLabel("--")
self.developer_count_layout.addWidget(self.developer_count_title)
self.developer_count_layout.addWidget(self.developer_count_value, alignment=Qt.AlignCenter)
cards_layout.addWidget(self.developer_count_card)
self.tag_count_card = CardWidget()
self.tag_count_card.setMinimumHeight(100)
self.tag_count_layout = QVBoxLayout(self.tag_count_card)
self.tag_count_title = SubtitleLabel("标签总数")
self.tag_count_value = TitleLabel("--")
self.tag_count_layout.addWidget(self.tag_count_title)
self.tag_count_layout.addWidget(self.tag_count_value, alignment=Qt.AlignCenter)
cards_layout.addWidget(self.tag_count_card)
self.announcement_count_card = CardWidget()
self.announcement_count_card.setMinimumHeight(100)
self.announcement_count_layout = QVBoxLayout(self.announcement_count_card)
self.announcement_count_title = SubtitleLabel("公告总数")
self.announcement_count_value = TitleLabel("--")
self.announcement_count_layout.addWidget(self.announcement_count_title)
self.announcement_count_layout.addWidget(self.announcement_count_value, alignment=Qt.AlignCenter)
cards_layout.addWidget(self.announcement_count_card)
self.download_count_card = CardWidget()
self.download_count_card.setMinimumHeight(100)
self.download_count_layout = QVBoxLayout(self.download_count_card)
self.download_count_title = SubtitleLabel("总下载量")
self.download_count_value = TitleLabel("--")
self.download_count_layout.addWidget(self.download_count_title)
self.download_count_layout.addWidget(self.download_count_value, alignment=Qt.AlignCenter)
cards_layout.addWidget(self.download_count_card)
layout.addLayout(cards_layout)
# 创建刷新按钮
refresh_button = PrimaryPushButton("刷新统计数据")
refresh_button.clicked.connect(self.load_stats)
layout.addWidget(refresh_button, alignment=Qt.AlignCenter)
# 创建进度条
self.progress_bar = ProgressBar()
self.progress_bar.setVisible(False)
layout.addWidget(self.progress_bar)
# 加载初始数据
self.load_stats()
def load_stats(self):
"""加载统计数据"""
self.show_progress()
self.worker = WorkerThread(self.api_client, 'getcount')
self.worker.finished.connect(self.on_stats_loaded)
self.worker.progress.connect(self.update_progress)
self.worker.error.connect(self.show_error)
self.worker.start()
def on_stats_loaded(self, data):
"""统计数据加载完成处理"""
self.hide_progress()
if not data:
self.show_error("数据加载失败")
return
# 更新统计数据
self.app_count_value.setText(str(data.get('total_apps', '--')))
self.developer_count_value.setText(str(data.get('total_developers', '--')))
self.tag_count_value.setText(str(data.get('total_tags', '--')))
self.announcement_count_value.setText(str(data.get('total_announcements', '--')))
self.download_count_value.setText(str(data.get('total_downloads', '--')))
def show_progress(self):
"""显示进度条"""
self.progress_bar.setVisible(True)
self.progress_bar.setValue(0)
def update_progress(self, value):
"""更新进度条"""
self.progress_bar.setValue(value)
def hide_progress(self):
"""隐藏进度条"""
self.progress_bar.setVisible(False)
def show_error(self, message):
"""显示错误消息"""
self.hide_progress()
InfoBar.error(
title="错误",
content=message,
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.BOTTOM_RIGHT,
duration=5000,
parent=self
)
class AppDetailWindow(QMainWindow):
"""应用详情窗口"""
def __init__(self, api_client, app_id, parent=None):
super().__init__(parent)
self.api_client = api_client
self.app_id = app_id
self.setWindowTitle("应用详情")
self.resize(800, 600)
self.init_ui()
self.load_app_detail()
def init_ui(self):
"""初始化界面"""
# 创建中心部件
central_widget = QWidget()
self.setCentralWidget(central_widget)
# 创建主布局
main_layout = QVBoxLayout(central_widget)
main_layout.setContentsMargins(20, 20, 20, 20)
# 创建标题
self.app_title = TitleLabel("加载中...")
main_layout.addWidget(self.app_title)
# 创建应用信息区域
self.info_card = CardWidget()
self.info_layout = QVBoxLayout(self.info_card)
main_layout.addWidget(self.info_card)
# 创建进度条
self.progress_bar = ProgressBar()
self.progress_bar.setVisible(False)
main_layout.addWidget(self.progress_bar)
def load_app_detail(self):
"""加载应用详情"""
self.show_progress()
self.worker = WorkerThread(self.api_client, 'getappinfo', {'id': self.app_id})
self.worker.finished.connect(self.on_app_detail_loaded)
self.worker.progress.connect(self.update_progress)
self.worker.error.connect(self.show_error)
self.worker.start()
def on_app_detail_loaded(self, data):
"""应用详情加载完成处理"""
self.hide_progress()
if not data:
self.show_error("应用详情加载失败")
return
# 更新标题
self.app_title.setText(data.get('name', '未知应用'))
# 清空之前的信息
while self.info_layout.count():
item = self.info_layout.takeAt(0)
widget = item.widget()
if widget:
widget.deleteLater()
# 添加应用信息
info_text = f"""
版本: {data.get('version', '未知')}
年龄分级: {data.get('age_rating', '未知')}
评分: {data.get('avg_rating', '暂无')}
下载量: {data.get('total_downloads', 0)}
"""
# 添加描述
description_label = SubtitleLabel("描述")
self.info_layout.addWidget(description_label)
description_text = CaptionLabel(data.get('description', '暂无描述'))
description_text.setWordWrap(True)
self.info_layout.addWidget(description_text)
# 添加标签信息
if 'tags' in data and data['tags']:
tags_label = SubtitleLabel("标签")
self.info_layout.addWidget(tags_label)
tags_text = ', '.join([tag['name'] for tag in data['tags']])
self.info_layout.addWidget(CaptionLabel(tags_text))
# 添加版本信息
if 'versions' in data and data['versions']:
versions_label = SubtitleLabel("版本历史")
self.info_layout.addWidget(versions_label)
versions_text = "\n".join([f"- 版本 {v['version']} ({v['download_count']} 下载)" for v in data['versions'][:3]])
self.info_layout.addWidget(CaptionLabel(versions_text))
# 添加图片数量信息
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 show_progress(self):
"""显示进度条"""
self.progress_bar.setVisible(True)
self.progress_bar.setValue(0)
def update_progress(self, value):
"""更新进度条"""
self.progress_bar.setValue(value)
def hide_progress(self):
"""隐藏进度条"""
self.progress_bar.setVisible(False)
def show_error(self, message):
"""显示错误消息"""
self.hide_progress()
InfoBar.error(
title="错误",
content=message,
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.BOTTOM_RIGHT,
duration=5000,
parent=self
)
class TagAppsWindow(QMainWindow):
"""标签下的应用列表窗口"""
def __init__(self, api_client, tag_id, tag_name, parent=None):
super().__init__(parent)
self.api_client = api_client
self.tag_id = tag_id
self.tag_name = tag_name
self.setWindowTitle(f"标签 '{tag_name}' 下的应用")
self.resize(800, 600)
self.current_page = 1
self.items_per_page = 20
self.total_pages = 1
self.init_ui()
self.load_tag_apps()
def init_ui(self):
"""初始化界面"""
# 创建中心部件
central_widget = QWidget()
self.setCentralWidget(central_widget)
# 创建主布局
main_layout = QVBoxLayout(central_widget)
main_layout.setContentsMargins(20, 20, 20, 20)
# 创建标题
title = TitleLabel(f"标签 '{self.tag_name}' 下的应用")
main_layout.addWidget(title)
# 创建应用列表
self.app_table = TableWidget()
self.app_table.setColumnCount(5)
self.app_table.setHorizontalHeaderLabels(["ID", "应用名称", "版本", "评分", "下载量"])
self.app_table.horizontalHeader().setSectionResizeMode(1, 3)
self.app_table.cellDoubleClicked.connect(self.show_app_detail)
main_layout.addWidget(self.app_table)
# 创建分页控制
pagination_layout = QHBoxLayout()
pagination_layout.setContentsMargins(0, 10, 0, 0)
self.prev_button = PushButton("上一页")
self.prev_button.clicked.connect(self.prev_page)
pagination_layout.addWidget(self.prev_button)
self.page_label = CaptionLabel("第 1 页,共 1 页")
pagination_layout.addWidget(self.page_label, alignment=Qt.AlignCenter)
self.next_button = PushButton("下一页")
self.next_button.clicked.connect(self.next_page)
pagination_layout.addWidget(self.next_button)
main_layout.addLayout(pagination_layout)
# 创建进度条
self.progress_bar = ProgressBar()
self.progress_bar.setVisible(False)
main_layout.addWidget(self.progress_bar)
def load_tag_apps(self):
"""加载标签下的应用"""
self.show_progress()
params = {
'id': self.tag_id,
'page': self.current_page,
'limit': self.items_per_page
}
self.worker = WorkerThread(self.api_client, 'gettagapp', params)
self.worker.finished.connect(self.on_tag_apps_loaded)
self.worker.progress.connect(self.update_progress)
self.worker.error.connect(self.show_error)
self.worker.start()
def on_tag_apps_loaded(self, data):
"""标签应用加载完成处理"""
self.hide_progress()
if not data or 'apps' not in data:
self.show_error("应用列表加载失败")
return
# 清空表格
self.app_table.setRowCount(0)
# 添加数据
for app in data['apps']:
row_position = self.app_table.rowCount()
self.app_table.insertRow(row_position)
# 添加应用数据到表格
self.app_table.setItem(row_position, 0, QTableWidgetItem(str(app.get('id', '--'))))
self.app_table.setItem(row_position, 1, QTableWidgetItem(app.get('name', '未知应用')))
self.app_table.setItem(row_position, 2, QTableWidgetItem(app.get('version', '未知')))
self.app_table.setItem(row_position, 3, QTableWidgetItem(str(app.get('avg_rating', '暂无'))))
self.app_table.setItem(row_position, 4, QTableWidgetItem(str(app.get('total_downloads', 0))))
# 更新分页信息
self.total_pages = data.get('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)
def prev_page(self):
"""上一页"""
if self.current_page > 1:
self.current_page -= 1
self.load_tag_apps()
def next_page(self):
"""下一页"""
if self.current_page < self.total_pages:
self.current_page += 1
self.load_tag_apps()
def show_app_detail(self, row, column):
"""显示应用详情"""
# 获取应用ID
app_id_item = self.app_table.item(row, 0)
if app_id_item:
app_id = int(app_id_item.text())
# 打开应用详情窗口
self.app_detail_window = AppDetailWindow(self.api_client, app_id, self)
self.app_detail_window.show()
def show_progress(self):
"""显示进度条"""
self.progress_bar.setVisible(True)
self.progress_bar.setValue(0)
def update_progress(self, value):
"""更新进度条"""
self.progress_bar.setValue(value)
def hide_progress(self):
"""隐藏进度条"""
self.progress_bar.setVisible(False)
def show_error(self, message):
"""显示错误消息"""
self.hide_progress()
InfoBar.error(
title="错误",
content=message,
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.BOTTOM_RIGHT,
duration=5000,
parent=self
)
class DeveloperAppsWindow(QMainWindow):
"""开发者的应用列表窗口"""
def __init__(self, api_client, developer_id, parent=None):
super().__init__(parent)
self.api_client = api_client
self.developer_id = developer_id
self.setWindowTitle(f"开发者ID {developer_id} 的应用")
self.resize(800, 600)
self.current_page = 1
self.items_per_page = 20
self.total_pages = 1
self.init_ui()
self.load_developer_apps()
def init_ui(self):
"""初始化界面"""
# 创建中心部件
central_widget = QWidget()
self.setCentralWidget(central_widget)
# 创建主布局
main_layout = QVBoxLayout(central_widget)
main_layout.setContentsMargins(20, 20, 20, 20)
# 创建标题
title = TitleLabel(f"开发者ID {self.developer_id} 的应用")
main_layout.addWidget(title)
# 创建应用列表
self.app_table = TableWidget()
self.app_table.setColumnCount(5)
self.app_table.setHorizontalHeaderLabels(["ID", "应用名称", "版本", "评分", "下载量"])
self.app_table.horizontalHeader().setSectionResizeMode(1, 3)
self.app_table.cellDoubleClicked.connect(self.show_app_detail)
main_layout.addWidget(self.app_table)
# 创建分页控制
pagination_layout = QHBoxLayout()
pagination_layout.setContentsMargins(0, 10, 0, 0)
self.prev_button = PushButton("上一页")
self.prev_button.clicked.connect(self.prev_page)
pagination_layout.addWidget(self.prev_button)
self.page_label = CaptionLabel("第 1 页,共 1 页")
pagination_layout.addWidget(self.page_label, alignment=Qt.AlignCenter)
self.next_button = PushButton("下一页")
self.next_button.clicked.connect(self.next_page)
pagination_layout.addWidget(self.next_button)
main_layout.addLayout(pagination_layout)
# 创建进度条
self.progress_bar = ProgressBar()
self.progress_bar.setVisible(False)
main_layout.addWidget(self.progress_bar)
def load_developer_apps(self):
"""加载开发者的应用"""
self.show_progress()
self.worker = WorkerThread(
self.api_client,
'getdeveloperapp',
{'id': self.developer_id, 'page': self.current_page, 'limit': self.items_per_page}
)
self.worker.finished.connect(self.on_developer_apps_loaded)
self.worker.progress.connect(self.update_progress)
self.worker.error.connect(self.show_error)
self.worker.start()
def on_developer_apps_loaded(self, data):
"""开发者应用加载完成处理"""
self.hide_progress()
if not data or 'apps' not in data or 'pagination' not in data:
self.show_error("数据格式错误")
return
# 清空表格
self.app_table.setRowCount(0)
# 填充表格
for app in data['apps']:
row_pos = self.app_table.rowCount()
self.app_table.insertRow(row_pos)
self.app_table.setItem(row_pos, 0, QTableWidgetItem(str(app.get('id', ''))))
self.app_table.setItem(row_pos, 1, QTableWidgetItem(app.get('name', '')))
self.app_table.setItem(row_pos, 2, QTableWidgetItem(app.get('version', '')))
self.app_table.setItem(row_pos, 3, QTableWidgetItem(str(app.get('avg_rating', '暂无'))))
self.app_table.setItem(row_pos, 4, QTableWidgetItem(str(app.get('total_downloads', 0))))
# 更新分页信息
self.total_pages = data['pagination']['totalPages']
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)
def prev_page(self):
"""上一页"""
if self.current_page > 1:
self.current_page -= 1
self.load_developer_apps()
def next_page(self):
"""下一页"""
if self.current_page < self.total_pages:
self.current_page += 1
self.load_developer_apps()
def show_app_detail(self, row, column):
"""显示应用详情"""
app_id = self.app_table.item(row, 0).text()
detail_window = AppDetailWindow(self.api_client, app_id, self)
detail_window.show()
def show_progress(self):
"""显示进度条"""
self.progress_bar.setVisible(True)
self.progress_bar.setValue(0)
def update_progress(self, value):
"""更新进度条"""
self.progress_bar.setValue(value)
def hide_progress(self):
"""隐藏进度条"""
self.progress_bar.setVisible(False)
def show_error(self, message):
"""显示错误消息"""
self.hide_progress()
InfoBar.error(
title="错误",
content=message,
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.BOTTOM_RIGHT,
duration=5000,
parent=self
)
class DeveloperInfoWindow(QMainWindow):
"""开发者信息窗口"""
def __init__(self, api_client, developer_id, parent=None):
super().__init__(parent)
self.api_client = api_client
self.developer_id = developer_id
self.setWindowTitle(f"开发者信息")
self.resize(600, 400)
self.init_ui()
self.load_developer_info()
def init_ui(self):
"""初始化界面"""
# 创建中心部件
central_widget = QWidget()
self.setCentralWidget(central_widget)
# 创建主布局
main_layout = QVBoxLayout(central_widget)
main_layout.setContentsMargins(20, 20, 20, 20)
# 创建标题
title = TitleLabel("开发者信息")
main_layout.addWidget(title)
# 创建信息卡片
self.info_card = CardWidget()
self.info_layout = QVBoxLayout(self.info_card)
main_layout.addWidget(self.info_card)
# 创建进度条
self.progress_bar = ProgressBar()
self.progress_bar.setVisible(False)
main_layout.addWidget(self.progress_bar)
def load_developer_info(self):
"""加载开发者信息"""
self.show_progress()
self.worker = WorkerThread(self.api_client, 'getdeveloperinfo', {'id': self.developer_id})
self.worker.finished.connect(self.on_developer_info_loaded)
self.worker.progress.connect(self.update_progress)
self.worker.error.connect(self.show_error)
self.worker.start()
def on_developer_info_loaded(self, data):
"""开发者信息加载完成处理"""
self.hide_progress()
if not data:
self.show_error("开发者信息加载失败")
return
# 清空之前的信息
while self.info_layout.count():
item = self.info_layout.takeAt(0)
widget = item.widget()
if widget:
widget.deleteLater()
# 添加开发者信息
info_items = [
("ID", data.get('id', '--')),
("用户名", data.get('username', '--')),
("邮箱", data.get('email', '--')),
("注册时间", data.get('created_at', '--')),
("是否验证", "" if data.get('is_verified', False) else ""),
("应用数量", data.get('app_count', 0))
]
for label_text, value_text in info_items:
label = CaptionLabel(f"{label_text}: {value_text}")
self.info_layout.addWidget(label)
# 添加验证时间(如果已验证)
if data.get('is_verified', False) and data.get('verified_at'):
verified_at_label = CaptionLabel(f"验证时间: {data.get('verified_at')}")
self.info_layout.addWidget(verified_at_label)
def show_progress(self):
"""显示进度条"""
self.progress_bar.setVisible(True)
self.progress_bar.setValue(0)
def update_progress(self, value):
"""更新进度条"""
self.progress_bar.setValue(value)
def hide_progress(self):
"""隐藏进度条"""
self.progress_bar.setVisible(False)
def show_error(self, message):
"""显示错误消息"""
self.hide_progress()
InfoBar.error(
title="错误",
content=message,
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.BOTTOM_RIGHT,
duration=5000,
parent=self
)
class LeonAppGUI(FluentWindow):
"""主应用窗口"""
def __init__(self):
super().__init__()
# 初始化API客户端
self.api_client = APIClient()
# 设置窗口标题和大小
self.setWindowTitle("LeonApp GUI")
self.resize(1000, 700)
# 初始化UI
self.init_ui()
def init_ui(self):
"""初始化界面"""
# 创建各个标签页
self.app_tab = AppTab(self.api_client, self)
self.app_tab.setObjectName("app")
self.tag_tab = TagTab(self.api_client, self)
self.tag_tab.setObjectName("tag")
self.developer_tab = DeveloperTab(self.api_client, self)
self.developer_tab.setObjectName("developer")
self.announcement_tab = AnnouncementTab(self.api_client, self)
self.announcement_tab.setObjectName("announcement")
self.stats_tab = StatsTab(self.api_client, self)
self.stats_tab.setObjectName("stats")
# 添加子界面到主窗口
self.addSubInterface(self.app_tab, FluentIcon.APPLICATION, "应用管理")
self.addSubInterface(self.tag_tab, FluentIcon.TAG, "标签管理")
self.addSubInterface(self.developer_tab, FluentIcon.DEVELOPER_TOOLS, "开发者管理")
self.addSubInterface(self.announcement_tab, FluentIcon.MEGAPHONE, "公告管理")
self.addSubInterface(self.stats_tab, FluentIcon.PIE_SINGLE, "统计信息")
# 设置默认选中的标签页
self.navigationInterface.setCurrentItem("app")
# 构建状态栏
# self.init_status_bar()
def show_app_detail(self, app_id):
"""显示应用详情"""
detail_window = AppDetailWindow(self.api_client, app_id, self)
detail_window.show()
def show_tag_apps(self, tag_id, tag_name):
"""显示标签下的应用"""
tag_apps_window = TagAppsWindow(self.api_client, tag_id, tag_name, self)
tag_apps_window.show()
def show_developer_apps(self, developer_id):
"""显示开发者的应用"""
developer_apps_window = DeveloperAppsWindow(self.api_client, developer_id, self)
developer_apps_window.show()
def show_developer_info(self, developer_id):
"""显示开发者信息"""
developer_info_window = DeveloperInfoWindow(self.api_client, developer_id, self)
developer_info_window.show()
def main():
"""主函数"""
# 创建应用实例
app = QApplication(sys.argv)
# 添加中文支持
translator = FluentTranslator()
app.installTranslator(translator)
# 创建并显示主窗口
window = LeonAppGUI()
window.show()
# 运行应用
sys.exit(app.exec_())
if __name__ == "__main__":
main()