SIT/ui/widgets/field_tree_widget.py

323 lines
11 KiB
Python

"""
字段树形控件
用于显示和管理字段的树形结构
"""
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QTreeWidget, QTreeWidgetItem,
QPushButton, QLineEdit, QLabel, QComboBox, QMessageBox,
QSplitter, QGroupBox, QFormLayout, QTextEdit
)
from PyQt5.QtCore import Qt, pyqtSignal
from controllers.field_controller import FieldController
from models.field import Field
from config import FieldType
from utils.logger import get_logger
logger = get_logger(__name__)
class FieldManagementWidget(QWidget):
"""字段管理控件"""
field_selected = pyqtSignal(Field)
def __init__(self, controller: FieldController):
super().__init__()
self.controller = controller
self.current_field = None
self.init_ui()
self.load_fields()
def init_ui(self):
"""初始化UI"""
# 主布局
main_layout = QHBoxLayout(self)
# 创建分割器
splitter = QSplitter(Qt.Horizontal)
main_layout.addWidget(splitter)
# 左侧:树形结构和搜索
left_widget = QWidget()
left_layout = QVBoxLayout(left_widget)
# 搜索区域
search_group = QGroupBox("搜索")
search_layout = QVBoxLayout(search_group)
search_form = QFormLayout()
self.domain_input = QLineEdit()
self.domain_input.setPlaceholderText("输入域名...")
search_form.addRow("域名:", self.domain_input)
self.name_input = QLineEdit()
self.name_input.setPlaceholderText("输入字段名...")
search_form.addRow("字段名:", self.name_input)
self.type_combo = QComboBox()
self.type_combo.addItem("全部", None)
for field_type in FieldType:
self.type_combo.addItem(field_type.value, field_type)
search_form.addRow("类型:", self.type_combo)
search_layout.addLayout(search_form)
search_btn_layout = QHBoxLayout()
self.search_btn = QPushButton("搜索")
self.search_btn.clicked.connect(self.on_search)
self.clear_btn = QPushButton("清除")
self.clear_btn.clicked.connect(self.on_clear_search)
search_btn_layout.addWidget(self.search_btn)
search_btn_layout.addWidget(self.clear_btn)
search_layout.addLayout(search_btn_layout)
left_layout.addWidget(search_group)
# 字段树
self.field_tree = QTreeWidget()
self.field_tree.setHeaderLabels(["名称", "类型", "描述"])
self.field_tree.setColumnWidth(0, 200)
self.field_tree.itemClicked.connect(self.on_field_selected)
left_layout.addWidget(self.field_tree)
# 操作按钮
btn_layout = QHBoxLayout()
self.add_btn = QPushButton("新建")
self.add_btn.clicked.connect(self.on_add_field)
self.delete_btn = QPushButton("删除")
self.delete_btn.clicked.connect(self.on_delete_field)
self.refresh_btn = QPushButton("刷新")
self.refresh_btn.clicked.connect(self.load_fields)
btn_layout.addWidget(self.add_btn)
btn_layout.addWidget(self.delete_btn)
btn_layout.addWidget(self.refresh_btn)
btn_layout.addStretch()
left_layout.addLayout(btn_layout)
# 右侧:字段详情编辑
right_widget = QWidget()
right_layout = QVBoxLayout(right_widget)
detail_group = QGroupBox("字段详情")
detail_layout = QFormLayout(detail_group)
self.full_name_edit = QLineEdit()
detail_layout.addRow("完整名称:", self.full_name_edit)
self.domain_edit = QLineEdit()
detail_layout.addRow("域:", self.domain_edit)
self.name_edit = QLineEdit()
detail_layout.addRow("字段名:", self.name_edit)
self.type_edit = QComboBox()
for field_type in FieldType:
self.type_edit.addItem(field_type.value, field_type)
detail_layout.addRow("类型:", self.type_edit)
self.range_min_edit = QLineEdit()
detail_layout.addRow("最小值:", self.range_min_edit)
self.range_max_edit = QLineEdit()
detail_layout.addRow("最大值:", self.range_max_edit)
self.default_value_edit = QLineEdit()
detail_layout.addRow("默认值:", self.default_value_edit)
self.unit_edit = QLineEdit()
detail_layout.addRow("单位:", self.unit_edit)
self.description_edit = QTextEdit()
self.description_edit.setMaximumHeight(100)
detail_layout.addRow("描述:", self.description_edit)
right_layout.addWidget(detail_group)
# 保存按钮
save_btn_layout = QHBoxLayout()
self.save_btn = QPushButton("保存")
self.save_btn.clicked.connect(self.on_save_field)
self.cancel_btn = QPushButton("取消")
self.cancel_btn.clicked.connect(self.on_cancel_edit)
save_btn_layout.addWidget(self.save_btn)
save_btn_layout.addWidget(self.cancel_btn)
save_btn_layout.addStretch()
right_layout.addLayout(save_btn_layout)
right_layout.addStretch()
# 添加到分割器
splitter.addWidget(left_widget)
splitter.addWidget(right_widget)
splitter.setStretchFactor(0, 1)
splitter.setStretchFactor(1, 1)
def load_fields(self):
"""加载字段列表"""
self.field_tree.clear()
fields, total = self.controller.get_all_fields(page=1, page_size=1000)
# 按域分组
domain_items = {}
for field in fields:
# 获取或创建域节点
if field.domain not in domain_items:
domain_item = QTreeWidgetItem(self.field_tree)
domain_item.setText(0, field.domain)
domain_item.setData(0, Qt.UserRole, None)
domain_items[field.domain] = domain_item
# 创建字段节点
field_item = QTreeWidgetItem(domain_items[field.domain])
field_item.setText(0, field.full_name)
field_item.setText(1, field.type.value)
field_item.setText(2, field.description or "")
field_item.setData(0, Qt.UserRole, field)
self.field_tree.expandAll()
logger.info(f"Loaded {total} fields")
def on_field_selected(self, item: QTreeWidgetItem, column: int):
"""字段被选中"""
field = item.data(0, Qt.UserRole)
if field:
self.current_field = field
self.display_field_details(field)
self.field_selected.emit(field)
def display_field_details(self, field: Field):
"""显示字段详情"""
self.full_name_edit.setText(field.full_name)
self.domain_edit.setText(field.domain)
self.name_edit.setText(field.name)
# 设置类型
index = self.type_edit.findData(field.type)
if index >= 0:
self.type_edit.setCurrentIndex(index)
self.range_min_edit.setText(field.range_min or "")
self.range_max_edit.setText(field.range_max or "")
self.default_value_edit.setText(field.default_value or "")
self.unit_edit.setText(field.unit or "")
self.description_edit.setText(field.description or "")
def on_add_field(self):
"""新建字段"""
self.current_field = None
self.clear_field_details()
def on_delete_field(self):
"""删除字段"""
if not self.current_field:
QMessageBox.warning(self, "警告", "请先选择要删除的字段")
return
reply = QMessageBox.question(
self,
"确认删除",
f"确定要删除字段 '{self.current_field.full_name}' 吗?",
QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
success, msg = self.controller.delete_field(self.current_field.id)
if success:
QMessageBox.information(self, "成功", msg)
self.load_fields()
self.clear_field_details()
else:
QMessageBox.warning(self, "失败", msg)
def on_save_field(self):
"""保存字段"""
# 收集字段数据
field_data = {
'full_name': self.full_name_edit.text(),
'domain': self.domain_edit.text(),
'name': self.name_edit.text(),
'type': self.type_edit.currentData().value,
'range_min': self.range_min_edit.text() or None,
'range_max': self.range_max_edit.text() or None,
'default_value': self.default_value_edit.text() or None,
'unit': self.unit_edit.text() or None,
'description': self.description_edit.toPlainText() or None,
}
if self.current_field:
# 更新
field_data['id'] = self.current_field.id
success, msg = self.controller.update_field(field_data)
else:
# 创建
success, msg, field_id = self.controller.create_field(field_data)
if success:
QMessageBox.information(self, "成功", msg)
self.load_fields()
else:
QMessageBox.warning(self, "失败", msg)
def on_cancel_edit(self):
"""取消编辑"""
if self.current_field:
self.display_field_details(self.current_field)
else:
self.clear_field_details()
def clear_field_details(self):
"""清空字段详情"""
self.full_name_edit.clear()
self.domain_edit.clear()
self.name_edit.clear()
self.type_edit.setCurrentIndex(0)
self.range_min_edit.clear()
self.range_max_edit.clear()
self.default_value_edit.clear()
self.unit_edit.clear()
self.description_edit.clear()
def on_search(self):
"""搜索字段"""
search_params = {
'domain': self.domain_input.text() or None,
'name': self.name_input.text() or None,
'type': self.type_combo.currentData(),
'page': 1,
'page_size': 1000
}
fields, total = self.controller.search_fields(search_params)
# 更新树形显示
self.field_tree.clear()
domain_items = {}
for field in fields:
if field.domain not in domain_items:
domain_item = QTreeWidgetItem(self.field_tree)
domain_item.setText(0, field.domain)
domain_items[field.domain] = domain_item
field_item = QTreeWidgetItem(domain_items[field.domain])
field_item.setText(0, field.full_name)
field_item.setText(1, field.type.value)
field_item.setText(2, field.description or "")
field_item.setData(0, Qt.UserRole, field)
self.field_tree.expandAll()
def on_clear_search(self):
"""清除搜索"""
self.domain_input.clear()
self.name_input.clear()
self.type_combo.setCurrentIndex(0)
self.load_fields()