AIDeveloper-PC/gui_ai_developer/windows/main_window.py

681 lines
24 KiB
Python
Raw Normal View History

2026-01-31 09:32:00 +00:00
"""
主窗口
"""
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
2026-03-06 13:50:01 +00:00
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
2026-01-31 09:32:00 +00:00
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. 数据导出支持导出ExcelCSV格式
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
)