import sys from PyQt5 import QtCore from PyQt5.QtCore import QAbstractTableModel, QModelIndex, pyqtSignal, QSize from PyQt5.QtGui import QFont, QBrush, QColor from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QTableView, QPushButton, QLabel, QLineEdit, QComboBox, QDialog, QFormLayout, QDialogButtonBox, QMessageBox, QHeaderView, QMenu, QAction, QToolBar, QSpinBox) import qtawesome as qta from datetime import datetime class KeywordTableModel(QAbstractTableModel): """关键词表格模型""" columns = ['ID', '关键词', '操作类型', '描述', '创建时间'] def __init__(self, dbManager): super().__init__() self.dbManager = dbManager self.keywordData = [] self.loadData() def loadData(self): """加载数据""" self.beginResetModel() self.keywordData = self.dbManager.getStepKeywords() # 按ID排序确保顺序正确 if self.keywordData: self.keywordData.sort(key=lambda x: x[0]) # 按第一列(ID)排序 self.endResetModel() def rowCount(self, parent=QModelIndex()): return len(self.keywordData) def columnCount(self, parent=QModelIndex()): return len(self.columns) def data(self, index, role=QtCore.Qt.DisplayRole): if not index.isValid(): return None row = index.row() col = index.column() if row >= len(self.keywordData): return None keywordInfo = self.keywordData[row] if role == QtCore.Qt.DisplayRole: if col == 0: return str(row + 1) # 显示行号作为ID elif col == 1: return keywordInfo[1] # 关键词 elif col == 2: return keywordInfo[2] # 操作类型 elif col == 3: return keywordInfo[3] or "" # 描述 elif col == 4: return keywordInfo[4] # 创建时间 elif role == QtCore.Qt.BackgroundRole: if row % 2 == 0: return QBrush(QColor(245, 245, 245)) else: return QBrush(QColor(255, 255, 255)) elif role == QtCore.Qt.FontRole: font = QFont() if col == 1: # 关键词列加粗 font.setBold(True) return font return None def headerData(self, section, orientation, role): if role == QtCore.Qt.DisplayRole and orientation == QtCore.Qt.Horizontal: return self.columns[section] return None def getKeywordInfo(self, row): """获取指定行的关键词信息""" if 0 <= row < len(self.keywordData): return { 'id': self.keywordData[row][0], 'keyword': self.keywordData[row][1], 'operationType': self.keywordData[row][2], 'description': self.keywordData[row][3], 'createdAt': self.keywordData[row][4] } return None class KeywordEditDialog(QDialog): """关键词编辑对话框""" def __init__(self, parent=None, keywordInfo=None): super().__init__(parent) self.keywordInfo = keywordInfo self.isEdit = keywordInfo is not None self.setWindowTitle("编辑关键词" if self.isEdit else "添加关键词") self.setFixedSize(500, 300) self.setupUi() if self.isEdit: self.loadKeywordInfo() def setupUi(self): """设置界面""" layout = QVBoxLayout() formLayout = QFormLayout() self.keywordEdit = QLineEdit() self.keywordEdit.setPlaceholderText("请输入关键词") formLayout.addRow("关键词:", self.keywordEdit) self.operationTypeCombo = QComboBox() self.operationTypeCombo.addItems(['set', 'check', 'wait', 'deltaT']) formLayout.addRow("操作类型:", self.operationTypeCombo) self.descriptionEdit = QLineEdit() self.descriptionEdit.setPlaceholderText("请输入描述(可选)") formLayout.addRow("描述:", self.descriptionEdit) layout.addLayout(formLayout) buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.reject) layout.addWidget(buttonBox) self.setLayout(layout) def loadKeywordInfo(self): """加载关键词信息""" if self.keywordInfo: self.keywordEdit.setText(self.keywordInfo['keyword']) self.operationTypeCombo.setCurrentText(self.keywordInfo['operationType']) self.descriptionEdit.setText(self.keywordInfo['description'] or "") def getKeywordData(self): """获取关键词数据""" return { 'keyword': self.keywordEdit.text().strip(), 'operationType': self.operationTypeCombo.currentText(), 'description': self.descriptionEdit.text().strip() } class KeywordManagerWidget(QWidget): """关键词字段库管理界面""" def __init__(self, dbManager, parent=None): super().__init__(parent) self.dbManager = dbManager self.setupUi() self.setupToolbar() self.setupContextMenu() def setupUi(self): """设置界面""" layout = QVBoxLayout() # 创建工具栏 self.toolbar = QToolBar("关键词管理工具栏") self.toolbar.setIconSize(QSize(24, 24)) layout.addWidget(self.toolbar) # 创建表格 self.tableModel = KeywordTableModel(self.dbManager) self.tableView = QTableView() self.tableView.setModel(self.tableModel) self.tableView.setSelectionBehavior(QTableView.SelectRows) self.tableView.setSelectionMode(QTableView.SingleSelection) self.tableView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.tableView.customContextMenuRequested.connect(self.showContextMenu) # 设置表格样式 self.setupTableStyle() layout.addWidget(self.tableView) # 创建状态栏 self.statusLabel = QLabel("就绪") layout.addWidget(self.statusLabel) self.setLayout(layout) def setupToolbar(self): """设置工具栏""" # 添加关键词 addAction = QAction(qta.icon('fa5s.plus', color='green'), "添加关键词", self) addAction.triggered.connect(self.addKeyword) self.toolbar.addAction(addAction) # 编辑关键词 editAction = QAction(qta.icon('fa5s.edit', color='blue'), "编辑关键词", self) editAction.triggered.connect(self.editKeyword) self.toolbar.addAction(editAction) # 删除关键词 deleteAction = QAction(qta.icon('fa5s.trash', color='red'), "删除关键词", self) deleteAction.triggered.connect(self.deleteKeyword) self.toolbar.addAction(deleteAction) self.toolbar.addSeparator() # 刷新 refreshAction = QAction(qta.icon('fa5s.sync', color='orange'), "刷新", self) refreshAction.triggered.connect(self.refreshData) self.toolbar.addAction(refreshAction) def setupTableStyle(self): """设置表格样式""" header = self.tableView.horizontalHeader() if header: header.setSectionResizeMode(0, QHeaderView.ResizeToContents) # ID header.setSectionResizeMode(1, QHeaderView.Stretch) # 关键词 header.setSectionResizeMode(2, QHeaderView.ResizeToContents) # 操作类型 header.setSectionResizeMode(3, QHeaderView.Stretch) # 描述 header.setSectionResizeMode(4, QHeaderView.ResizeToContents) # 创建时间 # 设置交替行颜色 self.tableView.setAlternatingRowColors(True) # 设置表格不可编辑 self.tableView.setEditTriggers(QTableView.NoEditTriggers) def setupContextMenu(self): """设置右键菜单""" self.tableView.customContextMenuRequested.connect(self.showContextMenu) def showContextMenu(self, pos): """显示右键菜单""" index = self.tableView.indexAt(pos) if not index.isValid(): return menu = QMenu() editAction = menu.addAction("编辑关键词") editAction.triggered.connect(self.editKeyword) deleteAction = menu.addAction("删除关键词") deleteAction.triggered.connect(self.deleteKeyword) if hasattr(self.tableView, 'viewport') and hasattr(self.tableView.viewport(), 'mapToGlobal'): menu.exec_(self.tableView.viewport().mapToGlobal(pos)) def addKeyword(self): """添加关键词""" dialog = KeywordEditDialog(self) if dialog.exec_() == QDialog.Accepted: keywordData = dialog.getKeywordData() if not keywordData['keyword']: QMessageBox.warning(self, "输入错误", "关键词不能为空") return keywordId = self.dbManager.addStepKeyword( keywordData['keyword'], keywordData['operationType'], keywordData['description'] ) if keywordId: self.tableModel.loadData() self.statusLabel.setText(f"成功添加关键词: {keywordData['keyword']}") else: QMessageBox.warning(self, "添加失败", "关键词已存在或添加失败") def editKeyword(self): """编辑关键词""" currentRow = self.tableView.currentIndex().row() if currentRow < 0: QMessageBox.information(self, "提示", "请先选择要编辑的关键词") return keywordInfo = self.tableModel.getKeywordInfo(currentRow) if not keywordInfo: return dialog = KeywordEditDialog(self, keywordInfo) if dialog.exec_() == QDialog.Accepted: keywordData = dialog.getKeywordData() if not keywordData['keyword']: QMessageBox.warning(self, "输入错误", "关键词不能为空") return success = self.dbManager.updateStepKeyword( keywordInfo['id'], keywordData['keyword'], keywordData['operationType'], keywordData['description'] ) if success: self.tableModel.loadData() self.statusLabel.setText(f"成功更新关键词: {keywordData['keyword']}") else: QMessageBox.warning(self, "更新失败", "关键词已存在或更新失败") def deleteKeyword(self): """删除关键词""" currentRow = self.tableView.currentIndex().row() if currentRow < 0: QMessageBox.information(self, "提示", "请先选择要删除的关键词") return keywordInfo = self.tableModel.getKeywordInfo(currentRow) if not keywordInfo: return reply = QMessageBox.question( self, "确认删除", f"确定要删除关键词 '{keywordInfo['keyword']}' 吗?", QMessageBox.Yes | QMessageBox.No ) if reply == QMessageBox.Yes: success = self.dbManager.deleteStepKeyword(keywordInfo['id']) if success: self.tableModel.loadData() self.statusLabel.setText(f"成功删除关键词: {keywordInfo['keyword']}") else: QMessageBox.warning(self, "删除失败", "删除关键词失败") def refreshData(self): """刷新数据""" self.tableModel.loadData() self.statusLabel.setText("数据已刷新") def getKeywordByText(self, text): """根据文本获取关键词""" return self.dbManager.getKeywordByText(text) def getOperationTypes(self): """获取所有操作类型""" return self.dbManager.getOperationTypes()