""" 消息编辑对话框 用于创建和编辑消息 """ from PyQt5.QtWidgets import ( QDialog, QVBoxLayout, QHBoxLayout, QFormLayout, QLineEdit, QComboBox, QTextEdit, QPushButton, QLabel, QMessageBox, QGroupBox, QListWidget, QListWidgetItem, QSplitter, QWidget ) from PyQt5.QtCore import Qt, pyqtSignal from models.message import Message from models.field import Field from config import ProtocolType, SerializationType from controllers.field_controller import FieldController from utils.logger import get_logger logger = get_logger(__name__) class MessageDialog(QDialog): """消息编辑对话框""" message_saved = pyqtSignal(Message) def __init__(self, parent=None, message: Message = None): super().__init__(parent) self.message = message self.field_controller = FieldController() self.selected_fields = [] self.init_ui() if message: self.load_message_data(message) self.setWindowTitle("编辑消息") else: self.setWindowTitle("新建消息") # 加载可用字段 self.load_available_fields() def init_ui(self): """初始化UI""" self.setModal(True) self.setMinimumSize(800, 600) # 主布局 main_layout = QVBoxLayout(self) # 基本信息组 basic_group = QGroupBox("基本信息") basic_layout = QFormLayout(basic_group) # 完整名称 self.full_name_edit = QLineEdit() self.full_name_edit.setPlaceholderText("例如: Radar.Receiver.v3") basic_layout.addRow("完整名称*:", self.full_name_edit) # 系统名 self.system_name_edit = QLineEdit() self.system_name_edit.setPlaceholderText("例如: Radar") basic_layout.addRow("系统名*:", self.system_name_edit) # 消息类型 self.message_type_edit = QLineEdit() self.message_type_edit.setPlaceholderText("例如: Receiver") basic_layout.addRow("消息类型*:", self.message_type_edit) # 版本号 self.version_edit = QLineEdit() self.version_edit.setPlaceholderText("例如: v3") basic_layout.addRow("版本号*:", self.version_edit) # 协议 self.protocol_combo = QComboBox() for protocol in ProtocolType: self.protocol_combo.addItem(protocol.value, protocol) basic_layout.addRow("传输协议*:", self.protocol_combo) # 序列化 self.serialization_combo = QComboBox() for serialization in SerializationType: self.serialization_combo.addItem(serialization.value, serialization) basic_layout.addRow("序列化格式*:", self.serialization_combo) # 描述 self.description_edit = QTextEdit() self.description_edit.setPlaceholderText("消息的详细描述...") self.description_edit.setMaximumHeight(60) basic_layout.addRow("描述:", self.description_edit) main_layout.addWidget(basic_group) # 字段选择组 field_group = QGroupBox("字段配置") field_layout = QVBoxLayout(field_group) # 创建分割器 splitter = QSplitter(Qt.Horizontal) # 左侧:可用字段 left_widget = QWidget() left_layout = QVBoxLayout(left_widget) left_layout.setContentsMargins(0, 0, 0, 0) left_label = QLabel("可用字段:") left_layout.addWidget(left_label) # 搜索框 self.field_search_edit = QLineEdit() self.field_search_edit.setPlaceholderText("搜索字段...") self.field_search_edit.textChanged.connect(self.filter_available_fields) left_layout.addWidget(self.field_search_edit) self.available_fields_list = QListWidget() self.available_fields_list.setSelectionMode(QListWidget.ExtendedSelection) left_layout.addWidget(self.available_fields_list) splitter.addWidget(left_widget) # 中间:操作按钮 middle_widget = QWidget() middle_layout = QVBoxLayout(middle_widget) middle_layout.setContentsMargins(5, 0, 5, 0) middle_layout.addStretch() self.add_field_btn = QPushButton(">>") self.add_field_btn.setMaximumWidth(50) self.add_field_btn.clicked.connect(self.on_add_fields) middle_layout.addWidget(self.add_field_btn) self.remove_field_btn = QPushButton("<<") self.remove_field_btn.setMaximumWidth(50) self.remove_field_btn.clicked.connect(self.on_remove_fields) middle_layout.addWidget(self.remove_field_btn) middle_layout.addStretch() splitter.addWidget(middle_widget) # 右侧:已选字段 right_widget = QWidget() right_layout = QVBoxLayout(right_widget) right_layout.setContentsMargins(0, 0, 0, 0) right_label = QLabel("已选字段:") right_layout.addWidget(right_label) self.selected_fields_list = QListWidget() self.selected_fields_list.setSelectionMode(QListWidget.ExtendedSelection) right_layout.addWidget(self.selected_fields_list) # 排序按钮 order_layout = QHBoxLayout() self.move_up_btn = QPushButton("上移") self.move_up_btn.clicked.connect(self.on_move_up) self.move_down_btn = QPushButton("下移") self.move_down_btn.clicked.connect(self.on_move_down) order_layout.addWidget(self.move_up_btn) order_layout.addWidget(self.move_down_btn) order_layout.addStretch() right_layout.addLayout(order_layout) splitter.addWidget(right_widget) splitter.setStretchFactor(0, 1) splitter.setStretchFactor(1, 0) splitter.setStretchFactor(2, 1) field_layout.addWidget(splitter) main_layout.addWidget(field_group) # 提示信息 hint_label = QLabel("* 标记为必填项,消息至少需要包含一个字段") hint_label.setStyleSheet("color: #666666; font-size: 11px;") main_layout.addWidget(hint_label) # 按钮 button_layout = QHBoxLayout() self.save_btn = QPushButton("保存") self.save_btn.clicked.connect(self.on_save) self.save_btn.setDefault(True) self.cancel_btn = QPushButton("取消") self.cancel_btn.clicked.connect(self.reject) button_layout.addStretch() button_layout.addWidget(self.save_btn) button_layout.addWidget(self.cancel_btn) main_layout.addLayout(button_layout) # 连接信号:自动生成完整名称 self.system_name_edit.textChanged.connect(self.update_full_name) self.message_type_edit.textChanged.connect(self.update_full_name) self.version_edit.textChanged.connect(self.update_full_name) def update_full_name(self): """自动更新完整名称""" system_name = self.system_name_edit.text().strip() message_type = self.message_type_edit.text().strip() version = self.version_edit.text().strip() if system_name and message_type and version: full_name = f"{system_name}.{message_type}.{version}" self.full_name_edit.setText(full_name) def load_available_fields(self): """加载可用字段""" fields, _ = self.field_controller.get_all_fields(page=1, page_size=1000) self.available_fields_list.clear() for field in fields: item = QListWidgetItem(f"{field.full_name} ({field.type.value})") item.setData(Qt.UserRole, field) self.available_fields_list.addItem(item) def filter_available_fields(self, text: str): """过滤可用字段""" for i in range(self.available_fields_list.count()): item = self.available_fields_list.item(i) item.setHidden(text.lower() not in item.text().lower()) def load_message_data(self, message: Message): """加载消息数据""" self.full_name_edit.setText(message.full_name) self.system_name_edit.setText(message.system_name) self.message_type_edit.setText(message.message_type) self.version_edit.setText(message.version) # 设置协议 index = self.protocol_combo.findData(message.protocol) if index >= 0: self.protocol_combo.setCurrentIndex(index) # 设置序列化 index = self.serialization_combo.findData(message.serialization) if index >= 0: self.serialization_combo.setCurrentIndex(index) if message.description: self.description_edit.setText(message.description) # 加载已选字段 self.selected_fields = message.fields.copy() for field in self.selected_fields: item = QListWidgetItem(f"{field.full_name} ({field.type.value})") item.setData(Qt.UserRole, field) self.selected_fields_list.addItem(item) def on_add_fields(self): """添加字段""" selected_items = self.available_fields_list.selectedItems() for item in selected_items: field = item.data(Qt.UserRole) # 检查是否已存在 if any(f.id == field.id for f in self.selected_fields): continue self.selected_fields.append(field) new_item = QListWidgetItem(f"{field.full_name} ({field.type.value})") new_item.setData(Qt.UserRole, field) self.selected_fields_list.addItem(new_item) def on_remove_fields(self): """移除字段""" selected_items = self.selected_fields_list.selectedItems() for item in selected_items: field = item.data(Qt.UserRole) # 从列表中移除 if field in self.selected_fields: self.selected_fields.remove(field) # 从UI中移除 row = self.selected_fields_list.row(item) self.selected_fields_list.takeItem(row) def on_move_up(self): """上移字段""" current_row = self.selected_fields_list.currentRow() if current_row > 0: item = self.selected_fields_list.takeItem(current_row) self.selected_fields_list.insertItem(current_row - 1, item) self.selected_fields_list.setCurrentRow(current_row - 1) # 更新字段列表 self.selected_fields[current_row], self.selected_fields[current_row - 1] = \ self.selected_fields[current_row - 1], self.selected_fields[current_row] def on_move_down(self): """下移字段""" current_row = self.selected_fields_list.currentRow() if current_row < self.selected_fields_list.count() - 1: item = self.selected_fields_list.takeItem(current_row) self.selected_fields_list.insertItem(current_row + 1, item) self.selected_fields_list.setCurrentRow(current_row + 1) # 更新字段列表 self.selected_fields[current_row], self.selected_fields[current_row + 1] = \ self.selected_fields[current_row + 1], self.selected_fields[current_row] def validate_input(self) -> tuple[bool, str]: """验证输入""" if not self.full_name_edit.text().strip(): return False, "完整名称不能为空" if not self.system_name_edit.text().strip(): return False, "系统名不能为空" if not self.message_type_edit.text().strip(): return False, "消息类型不能为空" if not self.version_edit.text().strip(): return False, "版本号不能为空" if len(self.selected_fields) == 0: return False, "消息至少需要包含一个字段" return True, "" def on_save(self): """保存消息""" # 验证输入 is_valid, error_msg = self.validate_input() if not is_valid: QMessageBox.warning(self, "验证失败", error_msg) return # 构建消息对象 message_data = { 'full_name': self.full_name_edit.text().strip(), 'system_name': self.system_name_edit.text().strip(), 'message_type': self.message_type_edit.text().strip(), 'version': self.version_edit.text().strip(), 'protocol': self.protocol_combo.currentData().value, 'serialization': self.serialization_combo.currentData().value, 'description': self.description_edit.toPlainText().strip() or None, 'fields': [f.to_dict() for f in self.selected_fields], } if self.message: message_data['id'] = self.message.id try: message = Message.from_dict(message_data) self.message_saved.emit(message) self.accept() except Exception as e: QMessageBox.critical(self, "错误", f"创建消息对象失败: {str(e)}") logger.error(f"Failed to create message object: {e}")