- 实现基于 PySide6 的 GUI 界面 - 集成 FastAPI 知识库服务器 API - 支持查看、编辑、提交 Markdown 文件 - 包含完整的 pytest-qt 测试套件 - 添加功能列表文档
203 lines
7.2 KiB
Python
203 lines
7.2 KiB
Python
import sys
|
||
from PySide6.QtWidgets import (
|
||
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||
QLabel, QLineEdit, QPushButton, QListWidget, QTextEdit,
|
||
QMessageBox, QSplitter, QFileDialog
|
||
)
|
||
from PySide6.QtCore import Qt
|
||
from api_client import KnowledgeBaseAPI
|
||
|
||
|
||
class KnowledgeBaseApp(QMainWindow):
|
||
def __init__(self):
|
||
super().__init__()
|
||
self.api: Optional[KnowledgeBaseAPI] = None
|
||
self.current_filename: Optional[str] = None
|
||
self.init_ui()
|
||
|
||
def init_ui(self):
|
||
self.setWindowTitle('知识库管理器')
|
||
self.setGeometry(100, 100, 1200, 800)
|
||
|
||
central_widget = QWidget()
|
||
self.setCentralWidget(central_widget)
|
||
|
||
main_layout = QVBoxLayout(central_widget)
|
||
|
||
# 服务器地址配置区域
|
||
server_layout = QHBoxLayout()
|
||
server_label = QLabel('服务器地址:')
|
||
self.server_input = QLineEdit('http://43.134.1.17:8800/')
|
||
self.server_input.setMinimumWidth(300)
|
||
self.config_button = QPushButton('配置')
|
||
self.config_button.clicked.connect(self.configure_server)
|
||
self.refresh_button = QPushButton('刷新列表')
|
||
self.refresh_button.clicked.connect(self.refresh_file_list)
|
||
|
||
server_layout.addWidget(server_label)
|
||
server_layout.addWidget(self.server_input)
|
||
server_layout.addWidget(self.config_button)
|
||
server_layout.addWidget(self.refresh_button)
|
||
server_layout.addStretch()
|
||
|
||
main_layout.addLayout(server_layout)
|
||
|
||
# 主内容区域(使用分割器)
|
||
splitter = QSplitter(Qt.Horizontal)
|
||
|
||
# 左侧:文件列表
|
||
left_widget = QWidget()
|
||
left_layout = QVBoxLayout(left_widget)
|
||
|
||
list_label = QLabel('文件列表 (.md):')
|
||
self.file_list = QListWidget()
|
||
self.file_list.itemClicked.connect(self.load_file)
|
||
|
||
left_layout.addWidget(list_label)
|
||
left_layout.addWidget(self.file_list)
|
||
|
||
# 右侧:编辑区域
|
||
right_widget = QWidget()
|
||
right_layout = QVBoxLayout(right_widget)
|
||
|
||
filename_layout = QHBoxLayout()
|
||
filename_label = QLabel('文件名:')
|
||
self.filename_input = QLineEdit()
|
||
self.filename_input.setPlaceholderText('输入文件名(例如:example.md)')
|
||
|
||
filename_layout.addWidget(filename_label)
|
||
filename_layout.addWidget(self.filename_input)
|
||
|
||
self.text_editor = QTextEdit()
|
||
self.text_editor.setPlaceholderText('在此编辑 Markdown 内容...')
|
||
|
||
button_layout = QHBoxLayout()
|
||
self.save_button = QPushButton('保存到服务器')
|
||
self.save_button.clicked.connect(self.save_file)
|
||
self.post_button = QPushButton('提交新文件')
|
||
self.post_button.clicked.connect(self.post_new_file)
|
||
|
||
button_layout.addWidget(self.save_button)
|
||
button_layout.addWidget(self.post_button)
|
||
|
||
right_layout.addLayout(filename_layout)
|
||
right_layout.addWidget(self.text_editor)
|
||
right_layout.addLayout(button_layout)
|
||
|
||
splitter.addWidget(left_widget)
|
||
splitter.addWidget(right_widget)
|
||
splitter.setSizes([300, 900])
|
||
|
||
main_layout.addWidget(splitter)
|
||
|
||
# 状态栏
|
||
self.status_label = QLabel('就绪')
|
||
self.statusBar().addWidget(self.status_label)
|
||
|
||
def configure_server(self):
|
||
server_url = self.server_input.text().strip()
|
||
if not server_url:
|
||
QMessageBox.warning(self, '警告', '请输入服务器地址')
|
||
return
|
||
|
||
self.api = KnowledgeBaseAPI(server_url)
|
||
|
||
if self.api.test_connection():
|
||
self.status_label.setText(f'已连接到服务器: {server_url}')
|
||
QMessageBox.information(self, '成功', '服务器配置成功!')
|
||
self.refresh_file_list()
|
||
else:
|
||
QMessageBox.critical(self, '错误', '无法连接到服务器,请检查地址是否正确')
|
||
self.status_label.setText('连接失败')
|
||
|
||
def refresh_file_list(self):
|
||
if not self.api:
|
||
QMessageBox.warning(self, '警告', '请先配置服务器')
|
||
return
|
||
|
||
try:
|
||
files = self.api.get_file_list()
|
||
self.file_list.clear()
|
||
|
||
# 只显示 .md 文件
|
||
md_files = [f for f in files if f.endswith('.md')]
|
||
self.file_list.addItems(md_files)
|
||
|
||
self.status_label.setText(f'已加载 {len(md_files)} 个文件')
|
||
except Exception as e:
|
||
QMessageBox.critical(self, '错误', str(e))
|
||
self.status_label.setText('加载文件列表失败')
|
||
|
||
def load_file(self, item):
|
||
filename = item.text()
|
||
self.current_filename = filename
|
||
self.filename_input.setText(filename)
|
||
|
||
try:
|
||
content = self.api.get_file(filename)
|
||
self.text_editor.setPlainText(content)
|
||
self.status_label.setText(f'已加载文件: {filename}')
|
||
except Exception as e:
|
||
QMessageBox.critical(self, '错误', str(e))
|
||
self.status_label.setText('加载文件失败')
|
||
|
||
def save_file(self):
|
||
if not self.api:
|
||
QMessageBox.warning(self, '警告', '请先配置服务器')
|
||
return
|
||
|
||
if not self.current_filename:
|
||
QMessageBox.warning(self, '警告', '请先选择一个文件')
|
||
return
|
||
|
||
content = self.text_editor.toPlainText()
|
||
|
||
try:
|
||
self.api.post_file(self.current_filename, content)
|
||
QMessageBox.information(self, '成功', f'文件 {self.current_filename} 保存成功!')
|
||
self.status_label.setText(f'已保存文件: {self.current_filename}')
|
||
except Exception as e:
|
||
QMessageBox.critical(self, '错误', str(e))
|
||
self.status_label.setText('保存文件失败')
|
||
|
||
def post_new_file(self):
|
||
if not self.api:
|
||
QMessageBox.warning(self, '警告', '请先配置服务器')
|
||
return
|
||
|
||
filename = self.filename_input.text().strip()
|
||
|
||
if not filename:
|
||
QMessageBox.warning(self, '警告', '请输入文件名')
|
||
return
|
||
|
||
if not filename.endswith('.md'):
|
||
filename += '.md'
|
||
self.filename_input.setText(filename)
|
||
|
||
content = self.text_editor.toPlainText()
|
||
|
||
if not content:
|
||
QMessageBox.warning(self, '警告', '请输入文件内容')
|
||
return
|
||
|
||
try:
|
||
self.api.post_file(filename, content)
|
||
QMessageBox.information(self, '成功', f'文件 {filename} 提交成功!')
|
||
self.current_filename = filename
|
||
self.status_label.setText(f'已提交文件: {filename}')
|
||
self.refresh_file_list()
|
||
except Exception as e:
|
||
QMessageBox.critical(self, '错误', str(e))
|
||
self.status_label.setText('提交文件失败')
|
||
|
||
|
||
def main():
|
||
app = QApplication(sys.argv)
|
||
window = KnowledgeBaseApp()
|
||
window.show()
|
||
sys.exit(app.exec())
|
||
|
||
|
||
if __name__ == '__main__':
|
||
main() |