diff --git a/.gitignore b/.gitignore index 9532559..176f001 100644 --- a/.gitignore +++ b/.gitignore @@ -204,3 +204,4 @@ __marimo__/ 测试数据/ model/ +output/ \ No newline at end of file diff --git a/MainWindow/mainwindow.py b/MainWindow/mainwindow.py index cf38dee..ef2f46f 100644 --- a/MainWindow/mainwindow.py +++ b/MainWindow/mainwindow.py @@ -1,12 +1,12 @@ -from PySide6.QtWidgets import (QMainWindow, QWidget, QGridLayout, +from PySide6.QtWidgets import (QMainWindow, QWidget, QGridLayout, QMessageBox, QPushButton, QSizePolicy, QSplitter, QToolBar) from PySide6.QtGui import QFontDatabase from PySide6.QtCore import Signal, Qt import os from info_core.defines import * -from info_core.MyQtClass import ConfigComboBoxGroup, FolderDropWidget - +from info_core.MyQtClass import (ConfigComboBoxGroup, FolderDropWidget, + OutputDirSelector, FolderBrowser) class ReportGeneratorUI(QMainWindow): send_baogao_choose_info = Signal(list[str]) @@ -49,8 +49,6 @@ class ReportGeneratorUI(QMainWindow): self.staff_group = ConfigComboBoxGroup("单次检查配置信息", is_project=False) # 第二行:导入图片路径、填写机组信息 self.picture_group = FolderDropWidget() - # self.image_analysis = - # self.main_layout.addWidget(self.image_analysis, 1, 1) # 第三行:生成报告按钮(跨两列) self.fill_turbine_info_button() self.fill_btn.clicked.connect(self.on_fill_clicked) @@ -79,15 +77,29 @@ class ReportGeneratorUI(QMainWindow): # 设置分割器初始比例 self.splitter.setStretchFactor(0, 1) self.splitter.setStretchFactor(1, 4) - + + self.init_toolbar() + self.create_warning_box() + self.create_info_fill_widget() + + def init_toolbar(self): self.toolbar = QToolBar() self.addToolBar(self.toolbar) self.toolbar.setMovable(False) self.toolbar.setFloatable(False) new_action = self.toolbar.addAction("重置布局比例") + + self.output_dir_selector = OutputDirSelector() + if not os.path.exists(os.getcwd() + "/output"): + os.mkdir(os.getcwd() + "/output") + self.output_dir_selector.set_output_dir(os.getcwd() + "/output") + output_dir_choose_action = self.toolbar.addAction("选择输出目录") + self.toolbar.addSeparator() + new_action.triggered.connect(self.reset_splitter) - + output_dir_choose_action.triggered.connect(self.choose_output_dir) + def reset_splitter(self): """重置分割器的比例""" total_size = sum(self.splitter.sizes()) # 获取当前总大小 @@ -96,12 +108,38 @@ class ReportGeneratorUI(QMainWindow): int(total_size * 0.8) # 第二部分占 80% ]) + def choose_output_dir(self): + """选择输出目录""" + self.output_dir_selector.show() + + def create_info_fill_widget(self): + self.info_fill_widget = FolderBrowser() + + def create_warning_box(self): + self.warning_box = QMessageBox(self) + self.warning_box.setWindowTitle("警告") + self.warning_box.setIcon(QMessageBox.Warning) + self.warning_box.setStyleSheet(WARNING_MESSAGE_BOX_STYLE + MESSAGE_BOX_BUTTON_STYLE) + def on_fill_clicked(self): """填写信息""" # 读取各个配置信息 - turbine_file_list = self.picture_group.get_selected_folders() - print(turbine_file_list) - + if len(self.picture_group.get_selected_folders()) <= 0: + self.warning_box.setText("请先选择机组目录") + self.warning_box.exec() + return + if self.project_group.get_current_config_file() is None: + self.warning_box.setText("请先选择/添加项目配置信息") + self.warning_box.exec() + return + if self.staff_group.get_current_config_file() is None: + self.warning_box.setText("请先选择/添加人员配置信息") + self.warning_box.exec() + return + + self.info_fill_widget.set_output_path(self.get_output_path()) + self.info_fill_widget.set_initial_folders(self.get_choosen_files()) + self.info_fill_widget.show() # search_file_list = [] # if self.image_analysis.check_is_waibu: # search_file_list.append("外汇总") @@ -111,6 +149,12 @@ class ReportGeneratorUI(QMainWindow): # search_file_list.append("防汇总") # self.send_baogao_choose_info.emit(search_file_list) + def get_choosen_files(self): + return self.picture_group.get_selected_folders() + + def get_output_path(self): + return self.output_dir_selector.get_output_dir() + def create_button(self, text): """创建统一风格的按钮""" btn = QPushButton(text) diff --git a/config/单次检查配置信息/1.json b/config/单次检查配置信息/1.json deleted file mode 100644 index 58e9535..0000000 --- a/config/单次检查配置信息/1.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "检查人员": "213", - "厂家人员": "213", - "业主人员": "213", - "数据处理人员": "213", - "报告编制人员": "123", - "机组型号": "123", - "机组厂家": "213", - "施工日期": "开始-结束", - "": "123", - "外部检查": true, - "内部检查": true, - "防雷检查": true, - "json路径": "/home/dtyx/桌面/yhh/ReportGenerator/config/单次检查配置信息" -} \ No newline at end of file diff --git a/config/单次检查配置信息/123.json b/config/单次检查配置信息/123.json new file mode 100644 index 0000000..2597abf --- /dev/null +++ b/config/单次检查配置信息/123.json @@ -0,0 +1,16 @@ +{ + "检查人员": "张三", + "厂家人员": "李四", + "业主人员": "王五", + "数据处理人员": "六麻子", + "报告编制人员": "赵六", + "机组型号": "model1", + "机组厂家": "某厂", + "叶片型号": "model--1", + "叶片厂家": "某场", + "施工日期": "2025/4/3-2025/4/30", + "外部检查": true, + "内部检查": true, + "防雷检查": true, + "json路径": "/home/dtyx/桌面/yhh/ReportGenerator/config/单次检查配置信息" +} \ No newline at end of file diff --git a/config/项目基本信息/123.json b/config/项目基本信息/123.json index 3169c4a..9963958 100644 --- a/config/项目基本信息/123.json +++ b/config/项目基本信息/123.json @@ -1,14 +1,14 @@ { - "项目名称": "123", - "风场名": "123", - "风场地址": "123", - "甲方公司": "123", - "甲方负责人": "123", - "甲方负责人电话": "123", + "项目名称": "某集团某场外部内部防雷检测项目", + "风场名": "某风场", + "风场地址": "某地", + "甲方公司": "甲", + "甲方负责人": "甲负责人", + "甲方负责人电话": "181xxxxxxxxx", "乙方公司": "武汉迪特聚能科技有限公司", - "乙方负责人": "123", - "乙方负责人电话": "123", - "项目规格": "123", - "项目工期": "123", + "乙方负责人": "乙负责人", + "乙方负责人电话": "181xxxxxxxx", + "项目规格": "20台", + "项目工期": "30天", "json路径": "/home/dtyx/桌面/yhh/ReportGenerator/config/项目基本信息" } \ No newline at end of file diff --git a/info_core/MyQtClass.py b/info_core/MyQtClass.py index 33f5764..e1027f1 100644 --- a/info_core/MyQtClass.py +++ b/info_core/MyQtClass.py @@ -3,11 +3,13 @@ from PySide6.QtWidgets import (QGroupBox, QVBoxLayout, QHBoxLayout, QCheckBox, QFileDialog, QMessageBox, QLabel, QWidget, QTextBrowser, QApplication, QCompleter, QFrame, QListWidgetItem, QListWidget, QAbstractItemView, - QStackedWidget, QStackedLayout) + QStackedWidget, QStackedLayout, QStyledItemDelegate, + QTreeView, QSplitter, QFileSystemModel) from PySide6.QtCore import (QDateTime,QTimer,QDateTime,Signal,QSettings, - QSortFilterProxyModel, QSize) + QSortFilterProxyModel, QSize, QDir) from PySide6.QtGui import (QPixmap, QDragEnterEvent, QDropEvent, Qt, QIcon, - QFontMetrics) + QFontMetrics, QStandardItem, QStandardItemModel, + QAction) import json, sys, os from info_core.defines import * @@ -144,7 +146,8 @@ class ConfigComboBoxGroup(QGroupBox): QMessageBox.warning(self, '警告', '没有选中任何项目。') def get_current_config_file(self): """获取当前选中的配置文件""" - return os.path.join(self.config_dir, self.combo_box.currentText() + ".json") + if self.combo_box.currentText(): + return os.path.join(self.config_dir, self.combo_box.currentText() + ".json") class AddProjectDialog(QDialog): @@ -1047,4 +1050,537 @@ class DraggableLine(QFrame): def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: - self.dragging = False \ No newline at end of file + self.dragging = False + +class OutputDirSelector(QWidget): + # 定义一个信号,当路径改变时发出 + path_changed = Signal(str) + + def __init__(self, parent=None): + super().__init__(parent) + self.output_dir = "" + self.init_ui() + self.set_style() + + def init_ui(self): + # 主布局 + layout = QVBoxLayout(self) + layout.setSpacing(10) + layout.setContentsMargins(0, 0, 0, 0) + + # 组框 + self.group_box = QFrame() + self.group_box.setFrameShape(QFrame.StyledPanel) + group_layout = QVBoxLayout(self.group_box) + group_layout.setSpacing(GROUP_BOX_SPACING) + group_layout.setContentsMargins(*GROUP_BOX_MARGINS) + + # 标题标签 + self.setWindowTitle("选择输出目录") + + # 路径显示标签 + self.path_label = QLabel("未选择文件夹") + self.path_label.setWordWrap(True) + self.path_label.setAlignment(Qt.AlignLeft | Qt.AlignTop) + + # 选择按钮 + self.select_button = QPushButton("选择输出文件夹") + self.select_button.clicked.connect(self.select_output_dir) + + # 添加部件到布局 + group_layout.addWidget(self.path_label) + group_layout.addWidget(self.select_button) + + # 添加组框到主布局 + layout.addWidget(self.group_box) + + def set_style(self): + # 设置组框样式 + self.group_box.setStyleSheet(GROUP_BOX_STYLE) + + # 设置路径显示样式 + self.path_label.setStyleSheet(PATH_DISPLAY_STYLE) + + # 设置按钮样式 + self.select_button.setStyleSheet(PRIMARY_BUTTON_STYLE) + + # 设置最小尺寸 + self.group_box.setMinimumSize(GROUP_BOX_MIN_WIDTH, GROUP_BOX_MIN_HEIGHT) + + def select_output_dir(self): + """打开文件夹选择对话框""" + dir_path = QFileDialog.getExistingDirectory( + self, + "选择输出文件夹", + "", # 默认路径为空,使用系统默认 + QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks + ) + + if dir_path: # 如果用户选择了文件夹 + self.output_dir = dir_path + self.path_label.setText(dir_path) + self.path_changed.emit(dir_path) # 发出路径改变信号 + + def get_output_dir(self): + """获取输出路径""" + return self.output_dir + + def set_output_dir(self, path): + """设置输出路径""" + if path: + self.output_dir = path + self.path_label.setText(path) + self.path_changed.emit(path) + + + +class JsonFileHandler: + """处理JSON文件的读写操作""" + + @staticmethod + def read_json(file_path): + """读取JSON文件""" + try: + with open(file_path, 'r', encoding='utf-8') as f: + return json.load(f) + except Exception as e: + print(f"Error reading JSON file {file_path}: {e}") + return None + + @staticmethod + def write_json(file_path, data): + try: + # 检查目录是否可写 + dir_path = os.path.dirname(file_path) + if not os.access(dir_path, os.W_OK): + print(f"错误:目录不可写 {dir_path}") + return False + + with open(file_path, 'w', encoding='utf-8') as f: + json.dump(data, f, ensure_ascii=False, indent=4) + print(f"成功写入文件:{file_path}") + return True + except Exception as e: + print(f"写入文件错误:{str(e)}") + return False + +class TreeModelManager: + """管理树形模型的数据操作""" + + @staticmethod + def create_left_tree_model(folder_list): + """创建左侧文件夹树模型""" + model = QStandardItemModel() + model.setHorizontalHeaderLabels(["Folder Structure"]) + folder_map = {} + + for folder_path in folder_list: + folder_name = os.path.basename(folder_path) + folder_map[folder_name] = folder_path + + parent_item = QStandardItem(folder_name) + model.appendRow(parent_item) + + try: + for child in os.listdir(folder_path): + child_path = os.path.join(folder_path, child) + if os.path.isdir(child_path): + child_item = QStandardItem(child) + parent_item.appendRow(child_item) + except Exception as e: + print(f"Error reading folder {folder_path}: {e}") + + return model, folder_map + + @staticmethod + def create_right_tree_model(folder_names): + """创建右侧可编辑树模型""" + model = QStandardItemModel() + model.setHorizontalHeaderLabels(["Name", "Value"]) + + json_data = {} + for folder_name in folder_names: + parent_item = QStandardItem(folder_name) + parent_item.setEditable(False) + + # 添加机组编号 + turbine_item = QStandardItem("turbinecode") + turbine_value = QStandardItem(folder_name.replace("机组", "").strip()) + turbine_value.setEditable(True) + parent_item.appendRow([turbine_item, turbine_value]) + + # 添加默认的三个子部件 + for i in range(1, 4): + part_item = QStandardItem(f"part{i}") + part_item.setEditable(False) + + code_item = QStandardItem("001") + code_item.setEditable(True) + + part_item.appendRow([QStandardItem("code"), code_item]) + parent_item.appendRow(part_item) + + model.appendRow(parent_item) + + # 初始化JSON数据 + json_data[folder_name] = { + "turbinecode": folder_name.replace("机组", "").strip(), + "part1": {"code": "001"}, + "part2": {"code": "001"}, + "part3": {"code": "001"} + } + + return model, json_data + + @staticmethod + def update_model_from_json(model, folder_name, json_data): + """根据JSON数据更新模型""" + parent_item = None + for i in range(model.rowCount()): + item = model.item(i) + if item and item.text() == folder_name: + parent_item = item + break + + if parent_item and folder_name in json_data: + data = json_data[folder_name] + + # 更新机组编号 + turbine_item = parent_item.child(0) + if turbine_item and turbine_item.child(0, 1): + turbine_item.child(0, 1).setText(data.get("turbinecode", "")) + + # 更新部件信息 + for j in range(1, 4): + part_item = parent_item.child(j) + if part_item: + part_name = part_item.text() + if part_name in data: + code_item = part_item.child(0, 1) + if code_item: + code_item.setText(data[part_name].get("code", "001")) + + @staticmethod + def update_json_from_model(model, json_data): + for i in range(model.rowCount()): + folder_index = model.index(i, 0) + folder_name = model.data(folder_index) + + if not folder_name: + continue + + # 确保数据结构存在 + if folder_name not in json_data: + json_data[folder_name] = {"turbinecode": "", "part1": {}, "part2": {}, "part3": {}} + + # 获取 turbinecode 值(从第二列获取) + turbine_index = model.index(0, 1, folder_index) # 第一行第二列 + if turbine_index.isValid(): + new_value = model.data(turbine_index) + print(f"更新 turbinecode: {json_data[folder_name]['turbinecode']} -> {new_value}") + json_data[folder_name]["turbinecode"] = new_value + + # 更新parts + for part_num in range(1, 4): + part_index = model.index(part_num, 0, folder_index) + if part_index.isValid(): + code_index = model.index(0, 1, part_index) + if code_index.isValid(): + json_data[folder_name][f"part{part_num}"]["code"] = model.data(code_index, Qt.DisplayRole) + +class DirectSaveDelegate(QStyledItemDelegate): + """直接保存的委托实现""" + def __init__(self, save_callback, parent=None): + super().__init__(parent) + self.save_callback = save_callback + + def setModelData(self, editor, model, index): + try: + # 提交数据前验证索引 + if not index.isValid(): + print("⚠️ 无效的模型索引") + return + + old_value = index.data(Qt.DisplayRole) + super().setModelData(editor, model, index) + new_value = index.data(Qt.DisplayRole) + + print(f"📝 数据变更: {old_value} → {new_value}") + + # 获取顶层文件夹索引 + top_index = index + while top_index.parent().isValid(): + top_index = top_index.parent() + + if model.hasIndex(top_index.row(), top_index.column(), top_index.parent()): + folder_name = model.data(top_index, Qt.DisplayRole) + self.save_callback(folder_name) + + except Exception as e: + print(f"❌ 委托错误: {str(e)}") + import traceback + traceback.print_exc() + +class FolderBrowser(QWidget): + """文件夹浏览编辑主窗口""" + data_changed = Signal(dict) # 数据变更信号 + + def __init__(self, parent=None): + super().__init__(parent) + self.output_path = QDir.currentPath() # 默认输出路径 + self.json_data = {} # 存储所有JSON数据 + self.folder_map = {} # 文件夹路径映射 + self.init_ui() + self.setup_connections() + + def init_ui(self): + """初始化用户界面""" + main_layout = QHBoxLayout(self) + splitter = QSplitter(Qt.Horizontal) + + # 左侧文件夹树视图 + self.left_model = QStandardItemModel() + self.left_model.setHorizontalHeaderLabels(["Folder Structure"]) + self.left_tree = QTreeView() + self.left_tree.setModel(self.left_model) + self.left_tree.setEditTriggers(QTreeView.NoEditTriggers) + + # 添加上下文菜单(复制功能) + self.left_tree.setContextMenuPolicy(Qt.ActionsContextMenu) + copy_action = QAction("Copy", self.left_tree) + copy_action.triggered.connect(self.copy_left_tree_text) + self.left_tree.addAction(copy_action) + + # 右侧可编辑树视图 + self.right_model = QStandardItemModel() + self.right_model.setHorizontalHeaderLabels(["Name", "Value"]) + self.right_tree = QTreeView() + self.right_tree.setModel(self.right_model) + self.right_tree.setItemDelegate( + DirectSaveDelegate(self.handle_immediate_save, self.right_tree) + ) + + # 添加到分割器 + splitter.addWidget(self.left_tree) + splitter.addWidget(self.right_tree) + splitter.setSizes([300, 500]) + main_layout.addWidget(splitter) + + def handle_immediate_save(self, folder_name): + print(f"🔧 保存触发 [{folder_name}]") + + try: + # 安全获取文件夹索引 + matches = self.right_model.match( + self.right_model.index(0, 0), + Qt.DisplayRole, + folder_name, + hits=1, + flags=Qt.MatchExactly + ) + + if not matches: + print(f"❌ 找不到文件夹: {folder_name}") + return + + folder_index = matches[0] + + # 获取 turbinecode 值(使用标准模型访问方式) + turbine_index = self.right_model.index(0, 1, folder_index) + turbine_value = self.right_model.data(turbine_index, Qt.DisplayRole) + + print(f"📊 当前值 - turbinecode: {turbine_value or '<空>'}") + + # 更新数据 + TreeModelManager.update_json_from_model(self.right_model, self.json_data) + self.save_to_json(folder_name) + + except Exception as e: + print(f"❌ 保存错误: {str(e)}") + + def setup_connections(self): + """设置信号和槽的连接""" + self.right_model.dataChanged.connect(self.on_right_data_changed) + self.left_tree.expanded.connect(self.sync_right_tree_expand) + self.left_tree.collapsed.connect(self.sync_right_tree_collapse) + self.right_tree.expanded.connect(self.sync_left_tree_expand) + self.right_tree.collapsed.connect(self.sync_left_tree_collapse) + + def refresh_views(self): + """刷新左右视图显示""" + self.left_tree.setModel(None) # 先重置模型 + self.left_tree.setModel(self.left_model) + + self.right_tree.setModel(None) + self.right_tree.setModel(self.right_model) + + # 展开第一层节点 + for i in range(self.left_model.rowCount()): + self.left_tree.expand(self.left_model.index(i, 0)) + self.right_tree.expand(self.right_model.index(i, 0)) + + def copy_left_tree_text(self): + """复制左侧树选中的文本""" + index = self.left_tree.currentIndex() + if index.isValid(): + text = self.left_model.data(index, Qt.DisplayRole) + QApplication.clipboard().setText(text) + + def sync_right_tree_expand(self, index): + """同步右侧树的展开状态(仅第一层)""" + if not index.parent().isValid(): # 只处理第一层 + right_index = self.right_model.index(index.row(), 0) + self.right_tree.expand(right_index) + + def sync_right_tree_collapse(self, index): + """同步右侧树的折叠状态(仅第一层)""" + if not index.parent().isValid(): # 只处理第一层 + right_index = self.right_model.index(index.row(), 0) + self.right_tree.collapse(right_index) + + def sync_left_tree_expand(self, index): + """同步左侧树的展开状态(仅第一层)""" + if not index.parent().isValid(): # 只处理第一层 + left_index = self.left_model.index(index.row(), 0) + self.left_tree.expand(left_index) + + def sync_left_tree_collapse(self, index): + """同步左侧树的折叠状态(仅第一层)""" + if not index.parent().isValid(): # 只处理第一层 + left_index = self.left_model.index(index.row(), 0) + self.left_tree.collapse(left_index) + + def set_output_path(self, path): + """设置JSON文件输出路径""" + self.output_path = path + if not os.path.exists(path): + os.makedirs(path) + + def set_initial_folders(self, folder_list): + """初始化文件夹结构""" + self.left_model.clear() + self.right_model.clear() + self.left_model.setHorizontalHeaderLabels(["Folder Structure"]) + self.right_model.setHorizontalHeaderLabels(["Name", "Value"]) + self.json_data = {} + self.folder_map = {} + + if not folder_list: # 添加空列表检查 + print("Warning: folder_list is empty") + return + self.folder_map = {} # 新增: {文件夹名: 初始文件名} + + for folder_path in folder_list: + folder_name = os.path.basename(folder_path) + # 使用初始 turbinecode 作为固定文件名 + initial_code = folder_name.replace("机组", "").strip() + self.folder_map[folder_name] = f"{initial_code}.json" # 存储固定文件名 + + # 创建左侧树模型 + self.left_model, self.folder_map = TreeModelManager.create_left_tree_model(folder_list) + + # 创建右侧树模型 + folder_names = [os.path.basename(f) for f in folder_list] + self.right_model, self.json_data = TreeModelManager.create_right_tree_model(folder_names) + + # 初始化JSON文件 + for folder_name in folder_names: + self.initialize_json_file(folder_name) + + self.refresh_views() # 添加视图刷新 + + def initialize_json_file(self, folder_name): + """初始化JSON文件""" + if not hasattr(self, 'output_path') or not self.output_path: + QMessageBox.warning(self, "Warning", "Output path not set!") + return + + json_filename = self.get_json_file_path(folder_name) + + # 如果文件已存在,则读取现有数据 + if os.path.exists(json_filename): + existing_data = JsonFileHandler.read_json(json_filename) + if existing_data: + self.json_data[folder_name].update(existing_data) + print(f"加载已有json文件: {json_filename},{existing_data}") + TreeModelManager.update_model_from_json( + self.right_model, folder_name, self.json_data + ) + else: + # 创建新JSON文件 + self.save_to_json(folder_name) + + def get_json_file_path(self, folder_name): + """ + 获取JSON文件路径 + 规则: 使用原始文件夹名 + .json后缀,保存到输出目录 + """ + # 确保文件夹名是有效的文件名 + safe_name = folder_name.strip() + # 只添加.json后缀,不做其他修改 + if not safe_name.lower().endswith('.json'): + safe_name += '.json' + return os.path.join(self.output_path, safe_name) + + def on_right_data_changed(self, top_left, bottom_right): + folder_item = self.right_model.itemFromIndex(top_left) + while folder_item and folder_item.parent() is not None: + folder_item = folder_item.parent() + print(f"开始更改") + if folder_item: + folder_name = folder_item.text() + print(f"变更检测到文件夹:{folder_name}") + + # 调试:打印变更前的数据 + print("变更前数据:", self.json_data.get(folder_name)) + + # 更新数据 + TreeModelManager.update_json_from_model(self.right_model, self.json_data) + + # 调试:打印变更后的数据 + print("变更后数据:", self.json_data.get(folder_name)) + + self.save_to_json(folder_name) + self.data_changed.emit(self.json_data) + + def save_to_json(self, folder_name): + json_path = self.get_json_file_path(folder_name) + print(f"🛠️ 准备保存到: {json_path}") + + # 验证路径 + if os.path.isdir(json_path): + print(f"❌ 错误:路径是目录,自动添加.json后缀") + json_path += '.json' + + try: + # 确保目录存在 + os.makedirs(os.path.dirname(json_path), exist_ok=True) + + # 写入文件 + with open(json_path, 'w', encoding='utf-8') as f: + json.dump(self.json_data[folder_name], f, ensure_ascii=False, indent=4) + print(f"✅ 成功保存: {json_path}") + return True + except Exception as e: + print(f"❌ 保存失败: {str(e)}") + return False + + def batch_update_folders(self, folder_mapping): + """批量更新文件夹结构""" + for folder_name, new_data in folder_mapping.items(): + if folder_name in self.json_data: + self.json_data[folder_name].update(new_data) + TreeModelManager.update_model_from_json( + self.right_model, folder_name, self.json_data + ) + self.save_to_json(folder_name) + + self.data_changed.emit(self.json_data) + + def get_output_path(self): + """获取当前输出路径""" + return self.output_path + + def get_current_data(self): + """获取当前所有数据""" + return self.json_data \ No newline at end of file diff --git a/info_core/defines.py b/info_core/defines.py index a40ac78..ce52253 100644 --- a/info_core/defines.py +++ b/info_core/defines.py @@ -204,4 +204,87 @@ SPLITTER_STYLE = """ QSplitter::handle:hover { background: #808080; /* 鼠标悬停时颜色 */ } +""" + +# ====================== QMessageBox 样式宏定义 ====================== +# 基础消息框样式 +MESSAGE_BOX_STYLE = f""" + QMessageBox {{ + font-family: "{FONT_FAMILY}"; + font-size: {CONTENT_FONT_SIZE}pt; + background-color: {LIGHT_COLOR}; + color: {TEXT_COLOR}; + }} + QMessageBox QLabel {{ + {LABEL_STYLE} + min-width: 300px; + min-height: 60px; + }} + QMessageBox QPushButton {{ + {BUTTON_STYLE} + min-width: 80px; + }} +""" + +# 信息消息框样式 +INFO_MESSAGE_BOX_STYLE = f""" + {MESSAGE_BOX_STYLE} + QMessageBox {{ + border-top: 4px solid {ACCENT_COLOR}; + }} + QMessageBox QLabel[text^=""] {{ + color: {PRIMARY_COLOR}; + }} +""" + +# 警告消息框样式 +WARNING_MESSAGE_BOX_STYLE = f""" + {MESSAGE_BOX_STYLE} + QMessageBox {{ + border-top: 4px solid #f39c12; + }} + QMessageBox QLabel[text^=""] {{ + color: #e67e22; + }} +""" + +# 错误消息框样式 +CRITICAL_MESSAGE_BOX_STYLE = f""" + {MESSAGE_BOX_STYLE} + QMessageBox {{ + border-top: 4px solid #e74c3c; + }} + QMessageBox QLabel[text^=""] {{ + color: #c0392b; + }} +""" + +# 提问消息框样式 +QUESTION_MESSAGE_BOX_STYLE = f""" + {MESSAGE_BOX_STYLE} + QMessageBox {{ + border-top: 4px solid {SUCCESS_COLOR}; + }} + QMessageBox QLabel[text^=""] {{ + color: {SECONDARY_COLOR}; + }} +""" + +# 消息框按钮样式 +MESSAGE_BOX_BUTTON_STYLE = f""" + QMessageBox QPushButton {{ + {PRIMARY_BUTTON_STYLE} + min-width: 80px; + max-width: 120px; + }} + QMessageBox QPushButton[text="Yes"], + QMessageBox QPushButton[text="OK"] {{ + background-color: {SUCCESS_COLOR}; + color: {LIGHT_TEXT_COLOR}; + }} + QMessageBox QPushButton[text="No"], + QMessageBox QPushButton[text="Cancel"] {{ + background-color: #e74c3c; + color: {LIGHT_TEXT_COLOR}; + }} """ \ No newline at end of file