SIT/ui/dialogs/field_dialog.py

259 lines
8.3 KiB
Python
Raw Normal View History

2026-01-29 09:22:54 +00:00
"""
字段编辑对话框
用于创建和编辑字段
"""
from PyQt5.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QFormLayout,
QLineEdit, QComboBox, QTextEdit, QPushButton,
QLabel, QMessageBox, QGroupBox
)
from PyQt5.QtCore import Qt, pyqtSignal
from models.field import Field
from config import FieldType
from utils.validator import Validator
from utils.logger import get_logger
logger = get_logger(__name__)
class FieldDialog(QDialog):
"""字段编辑对话框"""
field_saved = pyqtSignal(Field)
def __init__(self, parent=None, field: Field = None):
super().__init__(parent)
self.field = field
self.validator = Validator()
self.init_ui()
if field:
self.load_field_data(field)
self.setWindowTitle("编辑字段")
else:
self.setWindowTitle("新建字段")
def init_ui(self):
"""初始化UI"""
self.setModal(True)
self.setMinimumWidth(500)
# 主布局
main_layout = QVBoxLayout(self)
# 基本信息组
basic_group = QGroupBox("基本信息")
basic_layout = QFormLayout(basic_group)
# 完整名称
self.full_name_edit = QLineEdit()
self.full_name_edit.setPlaceholderText("例如: gis.map.location")
basic_layout.addRow("完整名称*:", self.full_name_edit)
# 域
self.domain_edit = QLineEdit()
self.domain_edit.setPlaceholderText("例如: gis")
basic_layout.addRow("域*:", self.domain_edit)
# 子域
self.sub_domains_edit = QLineEdit()
self.sub_domains_edit.setPlaceholderText("例如: map (多个用点号分隔)")
basic_layout.addRow("子域:", self.sub_domains_edit)
# 字段名
self.name_edit = QLineEdit()
self.name_edit.setPlaceholderText("例如: location")
basic_layout.addRow("字段名*:", self.name_edit)
# 类型
self.type_combo = QComboBox()
for field_type in FieldType:
self.type_combo.addItem(field_type.value, field_type)
basic_layout.addRow("类型*:", self.type_combo)
main_layout.addWidget(basic_group)
# 约束信息组
constraint_group = QGroupBox("约束信息")
constraint_layout = QFormLayout(constraint_group)
# 最小值
self.range_min_edit = QLineEdit()
self.range_min_edit.setPlaceholderText("可选")
constraint_layout.addRow("最小值:", self.range_min_edit)
# 最大值
self.range_max_edit = QLineEdit()
self.range_max_edit.setPlaceholderText("可选")
constraint_layout.addRow("最大值:", self.range_max_edit)
# 默认值
self.default_value_edit = QLineEdit()
self.default_value_edit.setPlaceholderText("可选")
constraint_layout.addRow("默认值:", self.default_value_edit)
# 单位
self.unit_edit = QLineEdit()
self.unit_edit.setPlaceholderText("例如: m, km/h")
constraint_layout.addRow("单位:", self.unit_edit)
main_layout.addWidget(constraint_group)
# 描述
desc_group = QGroupBox("描述")
desc_layout = QVBoxLayout(desc_group)
self.description_edit = QTextEdit()
self.description_edit.setPlaceholderText("字段的详细描述...")
self.description_edit.setMaximumHeight(100)
desc_layout.addWidget(self.description_edit)
main_layout.addWidget(desc_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.domain_edit.textChanged.connect(self.update_full_name)
self.sub_domains_edit.textChanged.connect(self.update_full_name)
self.name_edit.textChanged.connect(self.update_full_name)
def update_full_name(self):
"""自动更新完整名称"""
domain = self.domain_edit.text().strip()
sub_domains = self.sub_domains_edit.text().strip()
name = self.name_edit.text().strip()
if domain and name:
parts = [domain]
if sub_domains:
parts.extend(sub_domains.split('.'))
parts.append(name)
full_name = '.'.join(parts)
self.full_name_edit.setText(full_name)
def load_field_data(self, field: Field):
"""加载字段数据"""
self.full_name_edit.setText(field.full_name)
self.domain_edit.setText(field.domain)
if field.sub_domains:
self.sub_domains_edit.setText('.'.join(field.sub_domains))
self.name_edit.setText(field.name)
# 设置类型
index = self.type_combo.findData(field.type)
if index >= 0:
self.type_combo.setCurrentIndex(index)
if field.range_min:
self.range_min_edit.setText(field.range_min)
if field.range_max:
self.range_max_edit.setText(field.range_max)
if field.default_value:
self.default_value_edit.setText(field.default_value)
if field.unit:
self.unit_edit.setText(field.unit)
if field.description:
self.description_edit.setText(field.description)
def validate_input(self) -> tuple[bool, str]:
"""验证输入"""
# 必填项检查
if not self.full_name_edit.text().strip():
return False, "完整名称不能为空"
if not self.domain_edit.text().strip():
return False, "域不能为空"
if not self.name_edit.text().strip():
return False, "字段名不能为空"
# 验证字段名格式
is_valid, error_msg = self.validator.validate_field_name(
self.full_name_edit.text().strip()
)
if not is_valid:
return False, error_msg
# 验证域名格式
is_valid, error_msg = self.validator.validate_domain(
self.domain_edit.text().strip()
)
if not is_valid:
return False, error_msg
# 验证范围值
field_type = self.type_combo.currentData()
is_valid, error_msg = self.validator.validate_range(
self.range_min_edit.text().strip() or None,
self.range_max_edit.text().strip() or None,
field_type
)
if not is_valid:
return False, error_msg
return True, ""
def on_save(self):
"""保存字段"""
# 验证输入
is_valid, error_msg = self.validate_input()
if not is_valid:
QMessageBox.warning(self, "验证失败", error_msg)
return
# 构建字段对象
sub_domains_str = self.sub_domains_edit.text().strip()
sub_domains = sub_domains_str.split('.') if sub_domains_str else []
field_data = {
'full_name': self.full_name_edit.text().strip(),
'domain': self.domain_edit.text().strip(),
'sub_domains': sub_domains,
'name': self.name_edit.text().strip(),
'type': self.type_combo.currentData().value,
'range_min': self.range_min_edit.text().strip() or None,
'range_max': self.range_max_edit.text().strip() or None,
'default_value': self.default_value_edit.text().strip() or None,
'unit': self.unit_edit.text().strip() or None,
'description': self.description_edit.toPlainText().strip() or None,
}
if self.field:
field_data['id'] = self.field.id
try:
field = Field.from_dict(field_data)
self.field_saved.emit(field)
self.accept()
except Exception as e:
QMessageBox.critical(self, "错误", f"创建字段对象失败: {str(e)}")
logger.error(f"Failed to create field object: {e}")