""" 主窗口 """ 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 = """

智能低代码开发平台 v1.0

快捷键:

功能说明:

使用提示:

""" QMessageBox.about(self, "帮助", help_text) def _show_welcome(self): """显示欢迎消息""" self.statusBar().showMessage( "欢迎使用智能低代码开发平台!按 Ctrl+N 创建新项目", 5000 )