AIDeveloper-PC/gui_ai_developer/windows/main_window.py

681 lines
24 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.

"""
主窗口
"""
from PyQt5.QtWidgets import (
QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QListWidget, QListWidgetItem, QTabWidget, QTextEdit,
QTreeWidget, QTreeWidgetItem, QPushButton, QLineEdit,
QAction, QMenu, QMessageBox, QFileDialog, QInputDialog, QLabel
)
from PyQt5.QtCore import Qt, QTimer, QSize
from PyQt5.QtGui import QFont
from gui_ai_developer.models import Project, Requirement, Module, Document
from gui_ai_developer.widgets import PanelWidget, ProjectItemWidget, RequirementItemWidget, ModuleItemWidget
from gui_ai_developer.dialogs import NewProjectDialog, CodeViewDialog, ModuleDetailDialog, PipelineDialog
class MainWindow(QMainWindow):
"""主窗口类"""
def __init__(self):
"""初始化主窗口"""
super().__init__()
self.projects = []
self.current_project = None
self._setup_window()
self._setup_toolbar()
self._setup_ui()
self._setup_statusbar()
# 加载示例数据
self._load_sample_data()
# 显示欢迎消息
QTimer.singleShot(500, self._show_welcome)
def _setup_window(self):
"""设置窗口属性"""
self.setWindowTitle("智能低代码开发平台 v1.0")
self.setMinimumSize(1400, 900)
def _setup_toolbar(self):
"""设置工具栏"""
toolbar = self.addToolBar("主工具栏")
toolbar.setMovable(False)
toolbar.setIconSize(QSize(24, 24))
# 新建项目
new_action = QAction("📁 新建项目", self)
new_action.setShortcut("Ctrl+N")
new_action.setToolTip("创建新项目 (Ctrl+N)")
new_action.triggered.connect(self._create_new_project)
toolbar.addAction(new_action)
toolbar.addSeparator()
# 保存
save_action = QAction("💾 保存", self)
save_action.setShortcut("Ctrl+S")
save_action.setToolTip("保存项目 (Ctrl+S)")
save_action.triggered.connect(self._save_project)
toolbar.addAction(save_action)
# 导出
export_action = QAction("📤 导出", self)
export_action.setToolTip("导出项目")
export_action.triggered.connect(self._export_project)
toolbar.addAction(export_action)
toolbar.addSeparator()
# 运行流水线
run_action = QAction("▶ 运行流水线", self)
run_action.setToolTip("运行CI/CD流水线")
run_action.triggered.connect(self._run_pipeline)
toolbar.addAction(run_action)
toolbar.addSeparator()
# 设置
settings_action = QAction("⚙ 设置", self)
settings_action.setToolTip("系统设置")
settings_action.triggered.connect(self._show_settings)
toolbar.addAction(settings_action)
# 帮助
help_action = QAction("❓ 帮助", self)
help_action.setToolTip("帮助文档")
help_action.triggered.connect(self._show_help)
toolbar.addAction(help_action)
def _setup_ui(self):
"""设置UI"""
# 创建中心部件
central = QWidget()
self.setCentralWidget(central)
main_layout = QHBoxLayout(central)
main_layout.setContentsMargins(10, 10, 10, 10)
main_layout.setSpacing(10)
# 左侧面板 - 项目列表
self._create_left_panel(main_layout)
# 中间面板 - 需求和功能
self._create_center_panel(main_layout)
# 右侧面板 - 文档和代码
self._create_right_panel(main_layout)
def _create_left_panel(self, parent_layout):
"""创建左侧面板"""
left_panel = PanelWidget("📁 项目列表")
left_panel.setMaximumWidth(320)
layout = QVBoxLayout()
# 新建项目按钮
new_btn = QPushButton("+ 新建项目")
new_btn.setMinimumHeight(40)
new_btn.clicked.connect(self._create_new_project)
layout.addWidget(new_btn)
# 搜索框
self.search_edit = QLineEdit()
self.search_edit.setPlaceholderText("🔍 搜索项目...")
self.search_edit.textChanged.connect(self._filter_projects)
layout.addWidget(self.search_edit)
# 项目列表
self.project_list = QListWidget()
self.project_list.itemClicked.connect(self._on_project_clicked)
self.project_list.setContextMenuPolicy(Qt.CustomContextMenu)
self.project_list.customContextMenuRequested.connect(self._show_project_context_menu)
layout.addWidget(self.project_list)
left_panel.layout().addLayout(layout)
parent_layout.addWidget(left_panel, 2)
def _create_center_panel(self, parent_layout):
"""创建中间面板"""
center_widget = QWidget()
layout = QVBoxLayout(center_widget)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(10)
# 需求面板
req_panel = PanelWidget("📋 需求管理")
req_layout = QVBoxLayout()
self.req_tabs = QTabWidget()
# 原始需求标签页
self.original_req_text = QTextEdit()
self.original_req_text.setPlaceholderText("原始需求内容将显示在这里...")
self.original_req_text.setReadOnly(True)
self.req_tabs.addTab(self.original_req_text, "原始需求")
# 需求列表标签页
self.req_list = QListWidget()
self.req_tabs.addTab(self.req_list, "需求列表")
req_layout.addWidget(self.req_tabs)
req_panel.layout().addLayout(req_layout)
layout.addWidget(req_panel)
# 功能模块面板
func_panel = PanelWidget("⚙️ 功能模块")
func_layout = QVBoxLayout()
self.module_list = QListWidget()
self.module_list.itemDoubleClicked.connect(self._show_module_detail)
func_layout.addWidget(self.module_list)
func_panel.layout().addLayout(func_layout)
layout.addWidget(func_panel)
parent_layout.addWidget(center_widget, 3)
def _create_right_panel(self, parent_layout):
"""创建右侧面板"""
right_widget = QWidget()
layout = QVBoxLayout(right_widget)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(10)
# 文档面板
doc_panel = PanelWidget("📚 项目文档")
doc_layout = QVBoxLayout()
# 文档工具栏
doc_toolbar = QHBoxLayout()
doc_toolbar.addStretch()
download_all_btn = QPushButton("⬇ 全部下载")
download_all_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #10b981, stop:1 #059669);
}
""")
download_all_btn.clicked.connect(self._download_all_documents)
doc_toolbar.addWidget(download_all_btn)
doc_layout.addLayout(doc_toolbar)
self.doc_list = QListWidget()
self.doc_list.itemDoubleClicked.connect(self._open_document)
self.doc_list.setContextMenuPolicy(Qt.CustomContextMenu)
self.doc_list.customContextMenuRequested.connect(self._show_doc_context_menu)
doc_layout.addWidget(self.doc_list)
doc_panel.layout().addLayout(doc_layout)
layout.addWidget(doc_panel)
# 代码结构面板
code_panel = PanelWidget("💻 代码结构")
code_layout = QVBoxLayout()
# 代码工具栏
code_toolbar = QHBoxLayout()
code_toolbar.addStretch()
download_code_btn = QPushButton("⬇ 下载代码")
download_code_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #10b981, stop:1 #059669);
}
""")
download_code_btn.clicked.connect(self._download_all_code)
code_toolbar.addWidget(download_code_btn)
code_layout.addLayout(code_toolbar)
self.code_tree = QTreeWidget()
self.code_tree.setHeaderLabel("文件")
self.code_tree.itemDoubleClicked.connect(self._open_code_file)
self.code_tree.setContextMenuPolicy(Qt.CustomContextMenu)
self.code_tree.customContextMenuRequested.connect(self._show_code_context_menu)
code_layout.addWidget(self.code_tree)
code_panel.layout().addLayout(code_layout)
layout.addWidget(code_panel)
parent_layout.addWidget(right_widget, 2)
def _setup_statusbar(self):
"""设置状态栏"""
self.statusBar().showMessage("就绪")
# 添加永久部件
self.status_label = QLabel("无项目")
self.statusBar().addPermanentWidget(self.status_label)
def _load_sample_data(self):
"""加载示例数据"""
# 项目1
p1 = Project("智能监控系统", "基于AI的实时监控平台", "进行中")
p1.original_requirement = """需要开发一个智能监控系统,包含以下功能:
1. 用户登录认证:支持用户名密码登录,集成多因素认证
2. 实时数据监控:实时采集设备数据,可视化展示
3. 数据导出支持导出Excel、CSV格式
4. 系统日志:记录所有操作日志"""
p1.add_requirement(Requirement("REQ-001", "用户登录认证", "支持用户名密码登录集成MFA", 95, ""))
p1.add_requirement(Requirement("REQ-002", "实时数据监控", "实时采集设备数据并可视化", 92, ""))
p1.add_requirement(Requirement("REQ-003", "数据导出功能", "支持导出Excel、CSV格式", 88, ""))
p1.add_requirement(Requirement("REQ-004", "系统日志管理", "记录所有操作日志", 85, ""))
m1 = Module("用户认证模块", "实现登录、注册、权限管理", ["REQ-001"])
m1.add_tech("Spring Boot")
m1.add_tech("Spring Security")
m1.add_tech("JWT")
m1.progress = 60
p1.add_module(m1)
m2 = Module("数据监控模块", "实时数据采集和可视化", ["REQ-002"])
m2.add_tech("WebSocket")
m2.add_tech("ECharts")
m2.add_tech("Redis")
m2.progress = 40
p1.add_module(m2)
m3 = Module("数据管理模块", "数据查询、导出、备份", ["REQ-003"])
m3.add_tech("MyBatis")
m3.add_tech("POI")
m3.add_tech("MySQL")
m3.progress = 30
p1.add_module(m3)
p1.add_document(Document("需求规格说明书.docx", "SRS", "2.3 MB"))
p1.add_document(Document("功能设计文档.docx", "功能设计", "1.8 MB"))
p1.add_document(Document("软件概要设计文档.docx", "概要设计", "3.1 MB"))
p1.add_document(Document("接口文档.pdf", "API", "1.2 MB"))
# 项目2
p2 = Project("数据分析平台", "大数据可视化分析工具", "已完成")
# 项目3
p3 = Project("物联网管理系统", "设备管理与数据采集", "进行中")
self.projects = [p1, p2, p3]
self._refresh_project_list()
def _refresh_project_list(self):
"""刷新项目列表"""
self.project_list.clear()
for project in self.projects:
item = QListWidgetItem()
item_widget = ProjectItemWidget(project)
item_widget.clicked.connect(self._load_project)
item.setSizeHint(item_widget.sizeHint())
item.setData(Qt.UserRole, project)
self.project_list.addItem(item)
self.project_list.setItemWidget(item, item_widget)
def _on_project_clicked(self, item):
"""项目点击事件"""
project = item.data(Qt.UserRole)
if project:
self._load_project(project)
def _load_project(self, project):
"""加载项目"""
self.current_project = project
self.status_label.setText(f"当前项目: {project.name}")
self.statusBar().showMessage(f"已加载项目: {project.name}")
# 加载原始需求
self.original_req_text.setText(project.original_requirement)
# 加载需求列表
self.req_list.clear()
for req in project.requirements:
item = QListWidgetItem()
item_widget = RequirementItemWidget(req)
item.setSizeHint(item_widget.sizeHint())
self.req_list.addItem(item)
self.req_list.setItemWidget(item, item_widget)
# 加载功能模块
self.module_list.clear()
for module in project.modules:
item = QListWidgetItem()
item_widget = ModuleItemWidget(module)
item.setSizeHint(item_widget.sizeHint())
item.setData(Qt.UserRole, module)
self.module_list.addItem(item)
self.module_list.setItemWidget(item, item_widget)
# 加载文档列表
self.doc_list.clear()
for doc in project.documents:
item = QListWidgetItem(f"{doc.icon} {doc.name}")
item.setData(Qt.UserRole, doc)
self.doc_list.addItem(item)
# 加载代码树
self._load_code_tree(project)
def _load_code_tree(self, project):
"""加载代码树"""
self.code_tree.clear()
root = QTreeWidgetItem(self.code_tree, [f"📁 {project.name}"])
# src目录
src = QTreeWidgetItem(root, ["📁 src"])
QTreeWidgetItem(src, ["📄 Application.java"])
# modules目录
modules = QTreeWidgetItem(src, ["📁 modules"])
for module in project.modules:
module_name = module.name.replace("模块", "Module").replace(" ", "")
QTreeWidgetItem(modules, [f"{module_name}.java"])
# utils目录
utils = QTreeWidgetItem(src, ["📁 utils"])
QTreeWidgetItem(utils, ["📄 HttpUtil.java"])
QTreeWidgetItem(utils, ["📄 DateUtil.java"])
QTreeWidgetItem(utils, ["📄 StringUtil.java"])
# 配置文件
QTreeWidgetItem(root, ["📋 pom.xml"])
QTreeWidgetItem(root, ["📋 application.yml"])
QTreeWidgetItem(root, ["📝 README.md"])
self.code_tree.expandAll()
def _create_new_project(self):
"""创建新项目"""
dialog = NewProjectDialog(self)
if dialog.exec_() == dialog.Accepted:
project = dialog.get_project()
if project:
self.projects.insert(0, project)
self._refresh_project_list()
self._load_project(project)
QMessageBox.information(
self,
"成功",
f"项目 '{project.name}' 创建成功!"
)
def _filter_projects(self, text):
"""过滤项目"""
for i in range(self.project_list.count()):
item = self.project_list.item(i)
project = item.data(Qt.UserRole)
if project:
visible = (
text.lower() in project.name.lower() or
text.lower() in project.description.lower()
)
item.setHidden(not visible)
def _show_project_context_menu(self, pos):
"""显示项目右键菜单"""
item = self.project_list.itemAt(pos)
if not item:
return
menu = QMenu(self)
open_action = menu.addAction("📂 打开项目")
open_action.triggered.connect(lambda: self._on_project_clicked(item))
menu.addSeparator()
rename_action = menu.addAction("✏ 重命名")
rename_action.triggered.connect(lambda: self._rename_project(item))
export_action = menu.addAction("📤 导出项目")
export_action.triggered.connect(self._export_project)
menu.addSeparator()
delete_action = menu.addAction("🗑 删除项目")
delete_action.triggered.connect(lambda: self._delete_project(item))
menu.exec_(self.project_list.mapToGlobal(pos))
def _show_doc_context_menu(self, pos):
"""显示文档右键菜单"""
item = self.doc_list.itemAt(pos)
if not item:
return
menu = QMenu(self)
open_action = menu.addAction("👁 预览")
open_action.triggered.connect(lambda: self._open_document(item))
download_action = menu.addAction("⬇ 下载")
download_action.triggered.connect(lambda: self._download_document(item))
menu.exec_(self.doc_list.mapToGlobal(pos))
def _show_code_context_menu(self, pos):
"""显示代码右键菜单"""
item = self.code_tree.itemAt(pos)
if not item:
return
menu = QMenu(self)
open_action = menu.addAction("👁 查看代码")
open_action.triggered.connect(lambda: self._open_code_file(item, 0))
download_action = menu.addAction("⬇ 下载文件")
download_action.triggered.connect(lambda: self._download_code_file(item))
menu.exec_(self.code_tree.mapToGlobal(pos))
def _show_module_detail(self, item):
"""显示模块详情"""
module = item.data(Qt.UserRole)
if module:
dialog = ModuleDetailDialog(module, self)
dialog.exec_()
def _open_document(self, item):
"""打开文档"""
doc = item.data(Qt.UserRole)
if doc:
QMessageBox.information(
self,
"文档预览",
f"正在打开文档: {doc.name}\n\n"
f"类型: {doc.doc_type}\n"
f"大小: {doc.size}"
)
def _download_document(self, item):
"""下载文档"""
doc = item.data(Qt.UserRole)
if doc:
file_path, _ = QFileDialog.getSaveFileName(
self,
"保存文档",
doc.name
)
if file_path:
QMessageBox.information(
self,
"下载",
f"文档已保存到:\n{file_path}"
)
self.statusBar().showMessage(f"已下载: {doc.name}", 3000)
def _download_all_documents(self):
"""下载所有文档"""
if not self.current_project:
QMessageBox.warning(self, "提示", "请先选择一个项目")
return
folder = QFileDialog.getExistingDirectory(self, "选择保存目录")
if folder:
QMessageBox.information(
self,
"下载",
f"所有文档已保存到:\n{folder}"
)
self.statusBar().showMessage("文档批量下载完成", 3000)
def _open_code_file(self, item, column):
"""打开代码文件"""
file_name = item.text(0)
if "📄" in file_name or "" in file_name or "📋" in file_name or "📝" in file_name:
file_name = file_name.replace("📄 ", "").replace("", "").replace("📋 ", "").replace("📝 ", "")
dialog = CodeViewDialog(file_name, self)
dialog.exec_()
def _download_code_file(self, item):
"""下载代码文件"""
file_name = item.text(0).replace("📄 ", "").replace("📁 ", "").replace("", "").replace("📋 ", "").replace(
"📝 ", "")
file_path, _ = QFileDialog.getSaveFileName(
self,
"保存代码文件",
file_name
)
if file_path:
QMessageBox.information(
self,
"下载",
f"文件已保存到:\n{file_path}"
)
self.statusBar().showMessage(f"已下载: {file_name}", 3000)
def _download_all_code(self):
"""下载所有代码"""
if not self.current_project:
QMessageBox.warning(self, "提示", "请先选择一个项目")
return
folder = QFileDialog.getExistingDirectory(self, "选择保存目录")
if folder:
QMessageBox.information(
self,
"下载",
f"项目代码已打包保存到:\n{folder}"
)
self.statusBar().showMessage("代码下载完成", 3000)
def _rename_project(self, item):
"""重命名项目"""
project = item.data(Qt.UserRole)
if project:
new_name, ok = QInputDialog.getText(
self,
"重命名项目",
"新项目名称:",
text=project.name
)
if ok and new_name:
project.name = new_name
self._refresh_project_list()
self.statusBar().showMessage(f"项目已重命名为: {new_name}", 3000)
def _delete_project(self, item):
"""删除项目"""
project = item.data(Qt.UserRole)
if project:
reply = QMessageBox.question(
self,
"确认删除",
f"确定要删除项目 '{project.name}' 吗?\n此操作不可恢复!",
QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
self.projects.remove(project)
self._refresh_project_list()
if self.current_project == project:
self.current_project = None
self.status_label.setText("无项目")
self.statusBar().showMessage(f"已删除项目: {project.name}", 3000)
def _save_project(self):
"""保存项目"""
if self.current_project:
QMessageBox.information(
self,
"保存",
f"项目 '{self.current_project.name}' 已保存"
)
self.statusBar().showMessage("项目已保存", 3000)
else:
QMessageBox.warning(self, "提示", "没有打开的项目")
def _export_project(self):
"""导出项目"""
if not self.current_project:
QMessageBox.warning(self, "提示", "请先选择一个项目")
return
file_path, _ = QFileDialog.getSaveFileName(
self,
"导出项目",
f"{self.current_project.name}.zip",
"ZIP文件 (*.zip)"
)
if file_path:
QMessageBox.information(
self,
"导出",
f"项目已导出到:\n{file_path}"
)
self.statusBar().showMessage("项目导出完成", 3000)
def _run_pipeline(self):
"""运行流水线"""
if not self.current_project:
QMessageBox.warning(self, "提示", "请先选择一个项目")
return
dialog = PipelineDialog(self.current_project, self)
dialog.exec_()
def _show_settings(self):
"""显示设置"""
QMessageBox.information(self, "设置", "设置功能开发中...")
def _show_help(self):
"""显示帮助"""
help_text = """
<h2>智能低代码开发平台 v1.0</h2>
<h3>快捷键:</h3>
<ul>
<li><b>Ctrl+N</b> - 新建项目</li>
<li><b>Ctrl+S</b> - 保存项目</li>
</ul>
<h3>功能说明:</h3>
<ul>
<li>支持基于AI的需求分析和功能生成</li>
<li>自动生成项目文档和代码结构</li>
<li>集成流水线进行编译、打包、部署</li>
<li>支持多种项目类型和技术栈</li>
</ul>
<h3>使用提示:</h3>
<ul>
<li>双击模块查看详细信息</li>
<li>右键点击项目/文档/代码可查看更多操作</li>
<li>使用搜索框快速定位项目</li>
</ul>
"""
QMessageBox.about(self, "帮助", help_text)
def _show_welcome(self):
"""显示欢迎消息"""
self.statusBar().showMessage(
"欢迎使用智能低代码开发平台!按 Ctrl+N 创建新项目",
5000
)