import json import base64 import os import re import uuid from PyQt6 import * from PyQt6.QtCore import * from PyQt6.QtGui import * from PyQt6.QtWidgets import * from insertInstructionDlg import InsertInstructionDlg from insertTaskDlg import InsertTaskDlg from ui.Ui_taskForm import Ui_taskForm from createTaskDlg import CreateTaskDlg from chooseDeviceDlg import ChooseDeviceDlg from interfaceSession.interfaceManager import interfaceManager from instructionModel.instructionManager import instructionManager from taskModel.taskManager import taskManager from deviceModel.deviceManager import deviceManager from devmodelModel.devModelManager import devModelManager from taskGroupModel.taskGroupManager import taskGroupManager from taskInstructionModel.taskInstructionManager import taskInstructionManager from taskModel.taskActuatorManager import taskActuatorManager from devGroupModel.devGroupManager import devGroupManager from show_editor import CodeDialog from logs import log from common import NoWheelComboBox from common import TaskProgressBar from common import DragDropInfo from common import AlignNoDelegate from common import AlignDevDelegate from common import AlignTaskNoDelegate # from common import EventFilter from common import common class QxStandardItem(QStandardItem): def __init__(self, text='', parent=None): self.obj = parent super().__init__(text) def updateProgress(self, taskId, value, maxValue): obj = self.data(Qt.ItemDataRole.UserRole) if obj is not None and isinstance(obj, dict): if str(taskId) == str(obj.get('task_instruction_id')): self.obj.taskModelBlockSignals = True self.setData({'value': value, 'maximum': maxValue, 'task_instruction_id': obj.get('task_instruction_id'), 'name':obj.get('name')}, Qt.ItemDataRole.UserRole) self.obj.taskModelBlockSignals = False class ProgressBarDelegate(QStyledItemDelegate): def paint(self, painter, option, index): if index.column() == 6: # 仅对第七列添加进度条 data = index.data(Qt.ItemDataRole.UserRole) # 获取进度条数据 if data is not None and isinstance(data, dict): value = data.get('value', -9999) maximum = data.get('maximum', -9999) # 没有有效进度值时不绘制 if value < 0 or maximum < 1: return progress_rect = option.rect # 进度条的矩形边界 progress_width = int((value / maximum) * progress_rect.width()) # 计算进度条的宽度 progress_rect.adjust(2, 2, -2, -2) # 绘制进度条背景 painter.fillRect(progress_rect, QColor("#F8FAFF")) # 绘制实际数值文本 text = f"{value}/{maximum}" text_rect = QRect(option.rect) pen = painter.pen() pen.setColor(Qt.GlobalColor.black) painter.setPen(pen) # 绘制实际进度 progress_rect.setWidth(progress_width) painter.fillRect(progress_rect, QColor("#007EFF")) painter.drawText(text_rect, Qt.AlignmentFlag.AlignCenter, text) else: super().paint(painter, option, index) class TaskForm(QWidget): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_taskForm() self.ui.setupUi(self) self.defaultScriptBase64 = "aW1wb3J0IHRpbWUNCg0Kc3RhcnRUaW1lID0gdGltZS50aW1lKCkgDQpjdXJyZW50SW5kZXggPSAwDQpjdXJyZW50U3RhdGUgPSAwDQpkYXRlX2Zvcm1hdCA9ICIlWS0lbS0lZCAlSDolTTolUyINCg0KZGVmIHRvVGltZSh0YXJnZXRfdGltZV9zdHIpOg0KICAgIHRhcmdldF90aW1lID0gdGltZS5ta3RpbWUodGltZS5zdHJwdGltZSh0YXJnZXRfdGltZV9zdHIsIGRhdGVfZm9ybWF0KSkNCiAgICBjdXJyZW50X3RpbWUgPSB0aW1lLnRpbWUoKQ0KICAgICPmm7TmlrDml7bpl7Tov5vluqYNCiAgICB1cGRhdGVUaW1lKHN0YXJ0VGltZSwgY3VycmVudF90aW1lLCB0YXJnZXRfdGltZSkNCiAgICBpZiBjdXJyZW50X3RpbWUgPiB0YXJnZXRfdGltZToNCiAgICAgICAgcmV0dXJuIFRydWUNCiAgICByZXR1cm4gRmFsc2UNCg0KZGVmIHRvRGF5KGRheXMpOiAgDQogICAgdGFyZ2V0X3RpbWUgPSBzdGFydFRpbWUgKyBmbG9hdChkYXlzKSAqIDg2NDAwICAjIOWwhuWkqeaVsOi9rOaNouS4uuenkuW5tuWKoOWIsHN0YXJ0VGltZeS4iiAgDQogICAgY3VycmVudF90aW1lID0gdGltZS50aW1lKCkgIA0KICAgIHVwZGF0ZVRpbWUoc3RhcnRUaW1lLCBjdXJyZW50X3RpbWUsIHRhcmdldF90aW1lKSAgDQogICAgcmV0dXJuIGN1cnJlbnRfdGltZSA+IHRhcmdldF90aW1lICANCg0KZGVmIHRvSG91cihob3Vycyk6ICANCiAgICB0YXJnZXRfdGltZSA9IHN0YXJ0VGltZSArIGZsb2F0KGhvdXJzKSAqIDM2MDAgICMg5bCG5bCP5pe26L2s5o2i5Li656eS5bm25Yqg5Yiwc3RhcnRUaW1l5LiKICANCiAgICBjdXJyZW50X3RpbWUgPSB0aW1lLnRpbWUoKSAgDQogICAgdXBkYXRlVGltZShzdGFydFRpbWUsIGN1cnJlbnRfdGltZSwgdGFyZ2V0X3RpbWUpICANCiAgICByZXR1cm4gY3VycmVudF90aW1lID4gdGFyZ2V0X3RpbWUgIA0KICAgDQpkZWYgdG9NaW51dGUobWludXRlcyk6ICANCiAgICB0YXJnZXRfdGltZSA9IHN0YXJ0VGltZSArIGZsb2F0KG1pbnV0ZXMpICogNjAgICMg5bCG5YiG6ZKf6L2s5o2i5Li656eS5bm25Yqg5Yiwc3RhcnRUaW1l5LiKICANCiAgICBjdXJyZW50X3RpbWUgPSB0aW1lLnRpbWUoKSAgDQogICAgdXBkYXRlVGltZShzdGFydFRpbWUsIGN1cnJlbnRfdGltZSwgdGFyZ2V0X3RpbWUpICANCiAgICByZXR1cm4gY3VycmVudF90aW1lID4gdGFyZ2V0X3RpbWUgIA0KICANCmRlZiB0b1NlY29uZChzZWNvbmRzKTogIA0KICAgIHRhcmdldF90aW1lID0gc3RhcnRUaW1lICsgZmxvYXQoc2Vjb25kcykgICMg5bCG56eS55u05o6l5Yqg5Yiwc3RhcnRUaW1l5LiKICANCiAgICBjdXJyZW50X3RpbWUgPSB0aW1lLnRpbWUoKSAgDQogICAgdXBkYXRlVGltZShzdGFydFRpbWUsIGN1cnJlbnRfdGltZSwgdGFyZ2V0X3RpbWUpICANCiAgICByZXR1cm4gY3VycmVudF90aW1lID4gdGFyZ2V0X3RpbWUgIA0KICAgIA0KZGVmIGNhbGxCYWNrKGNvbXBsZXRlZF9zdGF0ZSk6DQogICAgZ2xvYmFsIGN1cnJlbnRJbmRleCwgY3VycmVudFN0YXRlDQogICAgY3VycmVudFN0YXRlID0gY29tcGxldGVkX3N0YXRlICMwOiDov5vlhaXku7vliqE7ICAx77ya5omn6KGM5Lu75YqhOyAgMu+8muaJp+ihjOaMh+S7pDsgIDPvvJrnrYnlvoXmjIfku6TplIHop6PpmaQ7ICA077yaIOaMh+S7pOW+queOrw0KICAgICNsb2coZiJjb21wbGV0ZWRfc3RhdGUgPXtjb21wbGV0ZWRfc3RhdGV9ICwgY3VycmVudEluZGV4ID0ge2N1cnJlbnRJbmRleH0sIHRhc2tQcm9jZXNzRmxhZyA9IHt0YXNrUHJvY2Vzc0ZsYWd9IikNCiAgICBpZiBsb29wID09IDA6DQogICAgICAgIGlmIGN1cnJlbnRJbmRleCA9PSAwOiAgICAgICAgICAgI+mmluasoei/m+WFpemYn+WIlw0KICAgICAgICAgICAgbG9nKGYiSW5pdGlhbGl6aW5nIGhlcmUuIikNCiAgICAgICAgICAgIGN1cnJlbnRJbmRleCArPSAxDQogICAgICAgICAgICB0aW1lLnNsZWVwKDEpDQogICAgICAgICAgICANCiAgICAgICAgbG9nKGYiY29tcGxldGVkX3N0YXRlID17Y29tcGxldGVkX3N0YXRlfSIpDQogICAgICAgICMg5Lu75Yqh5b6q546v5qyh5pWwPTAg5pe25Y+v55SoDQogICAgICAgICNpZiB0b1RpbWUoIjIwMjQtMDEtMDUgMjA6MDA6MDAiKToNCiAgICAgICAgIyAgICBmaW5pc2goKQ0KICAgICAgICAjaWYgdG9EYXkoMSk6DQogICAgICAgICMgICAgZmluaXNoKCkgICAgDQogICAgICAgICNpZiB0b0hvdXIoMSk6DQogICAgICAgICMgICAgZmluaXNoKCkNCiAgICAgICAgaWYgdG9NaW51dGUoMSk6DQogICAgICAgICAgICBmaW5pc2goKQ0KICAgICAgICAjaWYgdG9TZWNvbmQoMzApOg0KICAgICAgICAjICAgIGZpbmlzaCgpDQogICAgZWxzZTogDQogICAgICAgIG1hdGNoIGNvbXBsZXRlZF9zdGF0ZToNCiAgICAgICAgICAgIGNhc2UgMDogICAgICAgICAgICAgICAgICAgICAgICAgICAgICPov5vlhaXpmJ/liJcNCiAgICAgICAgICAgICAgICBpZiBjdXJyZW50SW5kZXggPT0gMDogICAgICAgICAgICPpppbmrKHov5vlhaXpmJ/liJcNCiAgICAgICAgICAgICAgICAgICAgbG9nKGYiSW5pdGlhbGl6aW5nIGhlcmUuIikNCiAgICAgICAgICAgICAgICAgICAgdGltZS5zbGVlcCg1KQ0KICAgICAgICAgICAgICAgIGxvZyhmImNvbXBsZXRlZF9zdGF0ZSA9e2NvbXBsZXRlZF9zdGF0ZX0iKQ0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgY2FzZSAxOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI+aJp+ihjOmYn+WIlw0KICAgICAgICAgICAgICAgIGxvZyhmImNvbXBsZXRlZF9zdGF0ZSA9e2NvbXBsZXRlZF9zdGF0ZX0iKQ0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgY2FzZSAyOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI+aJp+ihjOaMh+S7pA0KICAgICAgICAgICAgICAgIGxvZyhmImNvbXBsZXRlZF9zdGF0ZSA9e2NvbXBsZXRlZF9zdGF0ZX0iKQ0KDQpkZWYgbmV4dCgpOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAj6Zif5YiX5Y2V5qyh5omn6KGM5a6M5q+V5ZCO6LCD55SoDQogICAgZ2xvYmFsIGN1cnJlbnRJbmRleCwgY3VycmVudFN0YXRlDQogICAgY3VycmVudEluZGV4ID0gY3VycmVudEluZGV4ICsgMQ0KICAgIGlmIGN1cnJlbnRJbmRleCA+PSBsb29wOiAgICAgICAgICAgICAgICAgICAgI+atpOaXtuS7u+WKoeaJp+ihjOWujOavlQ0KICAgICAgICBsb2coJ0NsZWFuaW5nIHVwIGhlcmUuJykNCiAgICAgICAgZmluaXNoKCk=" self.taskModelBlockSignals = False self.taskDetailModelBlockSignals = False self.taskGroupModelSignalsBlock = False self.confInterfaces = interfaceManager.getInfo() self.supportedTypes = instructionManager.getSupportedType() self.codeDialog = CodeDialog("脚本编辑") # 全局进度缓存:key=task_instruction_id, value={'value': x, 'maximum': y} self.taskProgressCache = {} self.chooseDeviceDlg = ChooseDeviceDlg() self.createTaskDlg = CreateTaskDlg() self.insertInstructionDlg = InsertInstructionDlg() self.insertTaskDlg = InsertTaskDlg() self.current_groupId = None self.topWidget = None self.taskModel = QStandardItemModel() self.taskGroupModel = QStandardItemModel() self.taskDetailModel = QStandardItemModel() self.taskDetailDescriptionModel = QStandardItemModel() self.rootItem = self.taskDetailDescriptionModel.invisibleRootItem() self.ui.treeViewDescription.setModel(self.taskDetailDescriptionModel) self.ui.treeViewDescription.setColumnWidth(0, 400) self.ui.treeViewDescription.setHeaderHidden(True) self.insertInstructionDlg.accepted.connect(self.refreshTaskDetail) self.insertTaskDlg.accepted.connect(self.refreshTaskDetail) self.createTaskDlg.createFinished.connect(self.createTaskFinished) self.createTaskDlg.editFinished.connect(self.editTaskFinished) self.chooseDeviceDlg.chooseFinished.connect(self.chooseDeviceFinished) self.ui.pbInsertInstruction.clicked.connect(self.insertInstruction) self.ui.pbInsertTask.clicked.connect(self.insertTask) self.taskModel.itemChanged.connect(self.updateTask) self.taskGroupModel.itemChanged.connect(self.updateTaskGroup) self.taskDetailModel.itemChanged.connect(self.updateTaskInstruction) self.ui.tableViewTask.setModel(self.taskModel) self.ui.tableViewTaskGroup.setModel(self.taskGroupModel) self.ui.tableViewTaskGroup.dropEvent = self.dropEvent self.ui.pbEditTaskScript.clicked.connect(self.editTaskScript) self.ui.pbCopyTask.clicked.connect(self.copyTask) self.ui.pbExportTask.clicked.connect(self.exportTask) self.ui.tableViewTaskDetail.setModel(self.taskDetailModel) self.ui.tableViewTaskDetail.doubleClicked.connect(self.editTaskDetail) self.ui.tableViewTaskDetail.selectionModel().selectionChanged.connect(self.handleTaskDetailSelection) self.ui.pbCreateGroup.clicked.connect(self.createGroup) self.ui.pbDeleteGroup.clicked.connect(self.deleteGroup) self.ui.pbCreateTask.clicked.connect(self.createTask) self.ui.pbEditTask.clicked.connect(self.editTask) self.ui.pbDeleteTask.clicked.connect(self.deleteTask) self.ui.pbUp.clicked.connect(self.handleUpClick) self.ui.pbDown.clicked.connect(self.handleDownClick) self.ui.pbDeleteTaskDetail.clicked.connect(self.deleteTaskDetail) self.ui.pbSort.clicked.connect(self.showSortBtn) self.ui.pbStartTask.clicked.connect(self.startTask) self.ui.pbStopTask.clicked.connect(self.stopTask) self.ui.pbSaveSort.clicked.connect(self.saveSort) self.ui.pbEditScript.clicked.connect(self.editScript) self.subTasks = {} self.hideSortBtn() self.ui.tableViewTaskGroup.selectionModel().selectionChanged.connect(self.handleGroupSelection) self.ui.tableViewTask.selectionModel().selectionChanged.connect(self.handleTaskSelection) self.setSplitterStretchFactor() self.batchSetItemDelegate() taskActuatorManager.updateProgress.connect(self._onUpdateProgress) taskActuatorManager.taskStop.connect(self._onTaskStop) taskActuatorManager.taskStart.connect(self._onTaskStart) def batchSetItemDelegate(self): self.ui.tableViewTask.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter) self.ui.tableViewTaskGroup.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter) self.ui.tableViewTaskDetail.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter) self.ui.tableViewTask.setItemDelegate(AlignTaskNoDelegate(self.ui.tableViewTask)) self.ui.tableViewTaskGroup.setItemDelegate(AlignNoDelegate(self.ui.tableViewTaskGroup)) self.ui.tableViewTaskDetail.setItemDelegate(AlignDevDelegate(self.ui.tableViewTaskDetail,2)) def dropEvent(self, event: QDropEvent): if event.source() != self: mime_data = event.mimeData() source_index = mime_data.data('application/x-qabstractitemmodeldatalist') target_pos = event.position() target_index = self.ui.tableViewTaskGroup.indexAt(QPoint(int(target_pos.x()), int(target_pos.y()))) drag_drop_info = DragDropInfo(source_index, target_index) self.handleDrop(drag_drop_info) event.accept() else: event.ignore() # 双击编辑任务功能 def editTaskDetail(self, index): rows = self.ui.tableViewTaskDetail.selectionModel().selectedRows() if len(rows) == 1: row = rows[0].row() if index.column() == 3: row_id_index = self.taskDetailModel.index(row, 0, QModelIndex()) row_target_id_index = self.taskDetailModel.index(row, 11, QModelIndex()) id = self.taskDetailModel.data(row_id_index, Qt.ItemDataRole.DisplayRole) target_id = self.taskDetailModel.data(row_target_id_index, Qt.ItemDataRole.DisplayRole) self.chooseDeviceDlg.showChooseDeviceDlg(id, target_id) def handleDrop(self, drag_drop_info): target_row = drag_drop_info.target_index.row() if target_row > -1: row_id_index = self.taskGroupModel.index(target_row, 0, QModelIndex()) groupId = self.taskGroupModel.data(row_id_index, Qt.ItemDataRole.DisplayRole) rows = self.ui.tableViewTask.selectionModel().selectedRows() for row in rows: row_id_index = self.taskModel.index(row.row(), 0, QModelIndex()) taskId = self.taskModel.data(row_id_index, Qt.ItemDataRole.DisplayRole) taskParam = { "group_id": groupId } result = taskManager.update(taskId, taskParam) self.refreshSelect() def editScript(self): indexs = self.ui.tableViewTask.selectionModel().selectedRows() if len(indexs) == 1: if len(self.ui.tableViewTaskDetail.selectionModel().selectedRows())== 1: row = self.ui.tableViewTaskDetail.selectionModel().selectedRows()[0].row() row_target_id_index = self.taskDetailModel.index(row, 11, QModelIndex()) row_devicename_index = self.taskDetailModel.index(row, 3, QModelIndex()) devicename = self.taskDetailModel.data(row_devicename_index, Qt.ItemDataRole.DisplayRole) target_id = self.taskDetailModel.data(row_target_id_index, Qt.ItemDataRole.DisplayRole) if devicename == "任务": task = taskManager.getInfo(target_id) if task: scriptStr = task["script"] and str(base64.b64decode(task["script"] ), 'utf-8') or str(base64.b64decode(self.defaultScriptBase64).decode('utf-8')) scriptStr = self.codeDialog.showEditDlg(scriptStr,"task") if scriptStr == "": return script = base64.b64encode(scriptStr.encode("utf-8")) param = { "script": script } result = taskManager.update(target_id, param) else: instruction = instructionManager.getInfo(target_id) if instruction != None: dataAttr = instruction.get('attr') if dataAttr != None: if dataAttr.get('script') != None: base64_encoded_str = dataAttr.get('script') result = self.codeDialog.showEditDlg(str(base64.b64decode(base64_encoded_str).decode('utf-8'))) if result == "": return script = base64.b64encode(result.encode("utf-8")).decode('utf-8') dataAttr['script'] = script instructionManager.update(target_id, {"attr": dataAttr}) script = base64.b64encode(result.encode("utf-8")).decode('utf-8') dataAttr['script'] = script instructionManager.update(target_id, {"attr": dataAttr}) def editTaskScript(self): if len(self.ui.tableViewTask.selectionModel().selectedRows()) == 1: row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row() row_index = self.taskModel.index(row, 0, QModelIndex()) task_id = self.taskModel.data(row_index, Qt.ItemDataRole.DisplayRole) task = taskManager.getInfo(task_id) if task: scriptStr = task["script"] and str(base64.b64decode(task["script"] ), 'utf-8') or str(base64.b64decode(self.defaultScriptBase64).decode('utf-8')) scriptStr = self.codeDialog.showEditDlg(scriptStr,"task") if scriptStr == "": return script = base64.b64encode(scriptStr.encode("utf-8")) param = { "script": script } result = taskManager.update(task_id, param) def startTask(self): if len(self.ui.tableViewTask.selectionModel().selectedRows()) == 1: row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row() row_index = self.taskModel.index(row, 0, QModelIndex()) taskid = self.taskModel.data(row_index, Qt.ItemDataRole.DisplayRole) taskActuatorManager.start(taskid) def stopTask(self): if len(self.ui.tableViewTask.selectionModel().selectedRows()) == 1: row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row() row_index = self.taskModel.index(row, 0, QModelIndex()) taskid = self.taskModel.data(row_index, Qt.ItemDataRole.DisplayRole) taskActuatorManager.stop(taskid) def copyTask(self): if len(self.ui.tableViewTask.selectionModel().selectedRows()) == 1: row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row() row_index = self.taskModel.index(row, 0, QModelIndex()) taskid = self.taskModel.data(row_index, Qt.ItemDataRole.DisplayRole) taskManager.createCopy(taskid) self.refreshSelect() # 覆盖方式导入设备模型 def overWriteTask(self): file_dialog = QFileDialog(self) file_dialog.setWindowTitle("选择JSON") file_dialog.setNameFilter("Supported file formats (*.json)") file_dialog.setFileMode(QFileDialog.FileMode.ExistingFile) if file_dialog.exec(): file_path = file_dialog.selectedFiles()[0] with open(file_path, "r", encoding="utf-8") as f: # 指定以utf-8编码打开文件 taskInfo = json.load(f) tasks = taskInfo.get("tasks",[]) instructions = taskInfo.get("task_instructions",[]) for task in tasks: groupId = task['group_id'] group_name = task['group_name'] if groupId != None: if taskGroupManager.getInfo( groupId ) == None: groupId = taskGroupManager.create({"id": groupId, "name": group_name}) task['group_id'] = groupId task_id = task['id'] if taskManager.getInfo(task_id) != None: taskManager.update(task_id, task) else: task_id = taskManager.create_from_json(task) for instruction in instructions: instructionId = instruction['id'] if instruction["task_id"] == task_id: if taskInstructionManager.getInstructionInfo(instructionId) != None: taskInstructionManager.update(instructionId, instruction) else: taskInstructionManager.create_from_json(instruction) self.refreshSelect() def exportSingleTask(self, task_id): tInfo = taskManager.getInfo(task_id) #判断taskInfo 中的Id 长度是否小于10,如果是则改为uuid new_task_id = str(uuid.uuid4()) if len(str(task_id)) < 10: tInfo["id"] = new_task_id common.writeJson(os.path.join(os.path.dirname(__file__),"export"),"task", tInfo) groupInfo = taskGroupManager.getInfo(tInfo["group_id"]) common.writeJson(os.path.join(os.path.dirname(__file__),"export"),"task_group", groupInfo) task_instructionInfos = taskInstructionManager.getTaskInstructions(task_id) for task_instructionInfo in task_instructionInfos: if len(str(task_instructionInfo["id"])) < 10: task_instructionInfo["id"] = str(uuid.uuid4()) if len(task_id) < 10: task_instructionInfo["task_id"] = new_task_id target_type = task_instructionInfo["target_type"] if target_type == "instruction": deviceInfo = deviceManager.getOriginalInfo(task_instructionInfo["device_id"]) groupInfo = devGroupManager.getInfo(deviceInfo["group_id"]) if deviceInfo!= None: common.writeJson(os.path.join(os.path.dirname(__file__),"export"),"device", deviceInfo) if groupInfo!= None: common.writeJson(os.path.join(os.path.dirname(__file__),"export"),"device_group", groupInfo) elif target_type == "task": self.exportSingleTask(task_instructionInfo["target_id"]) common.writeJson(os.path.join(os.path.dirname(__file__),"export"),"task_instruction", task_instructionInfo) def exportTask(self): try: filename = "data.zip" packeagePath = filename fname = QFileDialog.getSaveFileName(self, '保存文件', packeagePath, 'JSON files (*.zip)') if fname[0]: packeagePath = fname[0] exportPath = os.path.join(os.path.dirname(__file__),"export") #清空exportPath目录 common.clearDir(exportPath) #创建exportPath目录 common.createDir(exportPath) indexs = self.ui.tableViewTask.selectionModel().selectedRows() for index in indexs: row = index.row() row_index = self.taskModel.index(row, 0, QModelIndex()) task_id = self.taskModel.data(row_index, Qt.ItemDataRole.DisplayRole) self.exportSingleTask(task_id) common.writeZip(packeagePath, exportPath) except Exception as e: if self.topWidget == None: self.topWidget = self.findTopLevelParent(self) if self.topWidget != None: self.topWidget.alertDialog(e,"导出文件异常") def chooseDeviceFinished(self): self.refreshTaskDetail() def saveSort(self): for row in range(self.taskDetailModel.rowCount()): row_id_index = self.taskDetailModel.index(row, 0, QModelIndex()) row_level_index = self.taskDetailModel.index(row, 10, QModelIndex()) taskInstanceId = self.taskDetailModel.data(row_id_index, Qt.ItemDataRole.DisplayRole) level = self.taskDetailModel.data(row_level_index, Qt.ItemDataRole.DisplayRole) if not str(row) == level: param = { "level": row } if not taskInstructionManager.update(taskInstanceId, param): print("update error") self.refreshTaskDetail() self.hideSortBtn() def createGroup(self): index = self.taskGroupModel.rowCount() self.taskGroupModel.appendRow([ QStandardItem(),QStandardItem(str(index+1)), QStandardItem()]) self.ui.tableViewTaskGroup.setCurrentIndex(self.taskGroupModel.index(index, 0) ) self.ui.tableViewTaskGroup.edit(self.taskGroupModel.index(index, 2)) def deleteGroup(self): if len(self.ui.tableViewTaskGroup.selectionModel().selectedRows())== 1: row = self.ui.tableViewTaskGroup.selectionModel().selectedRows()[0].row() row_id_index = self.taskGroupModel.index(row, 0, QModelIndex()) groupId = self.taskGroupModel.data(row_id_index, Qt.ItemDataRole.DisplayRole) if groupId == common.defaultGroupId: return row_groupName_index = self.taskGroupModel.index(row, 2, QModelIndex()) groupName = self.taskGroupModel.data(row_groupName_index, Qt.ItemDataRole.DisplayRole) if self.topWidget == None: self.topWidget = self.findTopLevelParent(self) if self.topWidget != None: if self.taskModel.rowCount() > 0: self.topWidget.alertDialog("分组下存在任务,不能删除分组", "警告") return if self.topWidget.removeDialog(groupName,"删除分组"): result = taskGroupManager.delete(groupId) if result == True: self.clearChildrenModel() self.taskGroupModel.removeRow(row) def updateTaskGroup(self): if self.taskGroupModelSignalsBlock == False: if len(self.ui.tableViewTaskGroup.selectionModel().selectedRows())== 1: row = self.ui.tableViewTaskGroup.selectionModel().selectedRows()[0].row() row_id_index = self.taskGroupModel.index(row, 0, QModelIndex()) groupId = self.taskGroupModel.data(row_id_index, Qt.ItemDataRole.DisplayRole) row_nane_index = self.taskGroupModel.index(row, 2, QModelIndex()) groupName = self.taskGroupModel.data(row_nane_index, Qt.ItemDataRole.DisplayRole) if groupId == None: groupId = taskGroupManager.create({"name":groupName}) self.taskGroupModel.setData(row_id_index, groupId) else: taskGroupManager.update(groupId, {"name":groupName}) def showSortBtn(self): self.ui.pbUp.setVisible(True) self.ui.pbDown.setVisible(True) self.ui.pbSaveSort.setVisible(True) self.ui.pbDeleteTaskDetail.setVisible(False) self.ui.pbDeleteTask.setEnabled(False) self.ui.pbSort.setVisible(False) self.ui.pbInsertInstruction.setVisible(False) self.ui.pbInsertTask.setVisible(False) self.ui.pbEditScript.setVisible(False) self.ui.tableViewTaskDetail.setColumnHidden(9, True) self.ui.tableViewTaskDetail.setColumnHidden(8, True) self.ui.tableViewTaskDetail.setColumnHidden(7, True) self.ui.tableViewTaskDetail.setColumnHidden(6, True) self.setAllColumnWidth() def hideSortBtn(self): self.ui.pbUp.setVisible(False) self.ui.pbDown.setVisible(False) self.ui.pbSaveSort.setVisible(False) self.ui.pbSort.setVisible(True) self.ui.pbDeleteTaskDetail.setVisible(True) self.ui.pbDeleteTask.setEnabled(True) self.ui.pbInsertInstruction.setVisible(True) self.ui.pbInsertTask.setVisible(True) self.ui.pbEditScript.setVisible(True) self.ui.tableViewTaskDetail.setColumnHidden(9, False) self.ui.tableViewTaskDetail.setColumnHidden(8, False) self.ui.tableViewTaskDetail.setColumnHidden(7, False) self.ui.tableViewTaskDetail.setColumnHidden(6, False) self.setAllColumnWidth() def insertTask(self): if len(self.ui.tableViewTask.selectionModel().selectedRows())== 1: row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row() taskId=self.taskModel.item(row, 0).text() position = self.taskDetailModel.rowCount() self.insertTaskDlg.showDlg(taskId, position) def insertInstruction(self): if len(self.ui.tableViewTask.selectionModel().selectedRows())== 1: row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row() taskId=self.taskModel.item(row, 0).text() position = self.taskDetailModel.rowCount() self.insertInstructionDlg.showDlg(taskId, position) def createTaskFinished(self): self.loadTask() if self.taskModel.rowCount() > 0: self.ui.tableViewTask.selectRow(self.taskModel.rowCount()-1) def editTaskFinished(self): if len(self.ui.tableViewTask.selectionModel().selectedRows())== 1: row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row() self.loadTask() if self.taskModel.rowCount() > 0: self.ui.tableViewTask.selectRow(row) def createTask(self): if self.current_groupId != None: self.createTaskDlg.showCreateDlg(self.current_groupId) def editTask(self): if len(self.ui.tableViewTask.selectionModel().selectedRows())== 1: row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row() row_taskId_index = self.taskModel.index(row, 0, QModelIndex()) task_id = self.taskModel.data(row_taskId_index, Qt.ItemDataRole.DisplayRole) task = taskManager.getInfo(task_id) if task: self.createTaskDlg.showEditDlg(task) def findTopLevelParent(self, widget): parent = widget.parent() while parent and not isinstance(parent, QMainWindow): # 顶层窗口是 QMainWindow widget = parent parent = widget.parent() return parent def deleteTask(self): indexs = self.ui.tableViewTask.selectionModel().selectedRows() if len(indexs) == 1: row = indexs[0].row() row_id_index = self.taskModel.index(row, 0, QModelIndex()) row_name_index = self.taskModel.index(row, 2, QModelIndex()) taskName = self.taskModel.data(row_name_index, Qt.ItemDataRole.DisplayRole) if self.topWidget == None: self.topWidget = self.findTopLevelParent(self) if self.topWidget != None: if self.topWidget.removeDialog(taskName,"删除任务"): row_taskModel_index = self.taskModel.index(row, 0, QModelIndex()) result = taskManager.delete(self.taskModel.data(row_taskModel_index, Qt.ItemDataRole.DisplayRole)) if result == True: self.refreshSelect() elif len(indexs) > 1: if self.topWidget == None: self.topWidget = self.findTopLevelParent(self) if self.topWidget != None: #必须这样写,不能写else if self.topWidget.removeDialog(f"{len(indexs)}个任务"): for index in indexs: row = index.row() row_id_index = self.taskModel.index(row, 0, QModelIndex()) taskId = self.taskModel.data(row_id_index, Qt.ItemDataRole.DisplayRole) taskManager.delete(taskId) self.refreshSelect() def clearChildrenModel(self): self.taskDetailModel.clear() self.ui.textEditDescription.clear() self.clearTreeModel() def clearTaskChildrenModel(self): self.taskModel.clear() self.ui.textEditDescription.clear() self.clearTreeModel() def handleUpClick(self): selectRows = self.ui.tableViewTaskDetail.selectionModel().selectedRows() if len(selectRows) == 1: row = selectRows[0].row() if row > 0: item = self.taskDetailModel.takeRow(row) self.taskDetailModel.insertRow(row - 1, item) self.ui.tableViewTaskDetail.selectRow(row - 1) def handleDownClick(self): selectRows = self.ui.tableViewTaskDetail.selectionModel().selectedRows() if len(selectRows) == 1: row = selectRows[0].row() if row < self.taskDetailModel.rowCount() - 1: item = self.taskDetailModel.takeRow(row) self.taskDetailModel.insertRow(row + 1, item) self.ui.tableViewTaskDetail.selectRow(row + 1) def refreshSelect(self): selectedRows = self.ui.tableViewTaskGroup.selectionModel().selectedRows() self.loadTaskGroup() if len(selectedRows) < 1: self.ui.tableViewTaskGroup.selectRow(0) if len(selectedRows) == 1: row = selectedRows[0].row() self.ui.tableViewTaskGroup.selectRow(row) def refreshTaskDetail(self): if len(self.ui.tableViewTask.selectionModel().selectedRows()) == 1: row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row() row_index = self.taskModel.index(row, 0, QModelIndex()) taskid = self.taskModel.data(row_index, Qt.ItemDataRole.DisplayRole) self.loadTaskDetail(taskid) # 任务分组选中 def handleGroupSelection(self, index): if len(self.ui.tableViewTaskGroup.selectionModel().selectedRows()) == 1: row = self.ui.tableViewTaskGroup.selectionModel().selectedRows()[0].row() row_id_index = self.taskGroupModel.index(row, 0, QModelIndex()) group_id = self.taskGroupModel.data(row_id_index, Qt.ItemDataRole.DisplayRole) self.current_groupId = group_id self.loadTask() self.clearChildrenModel() #任务列表选中 def handleTaskSelection(self, index): self.refreshTaskDetail() def handleTaskDetailSelection(self, index): if len(self.ui.tableViewTaskDetail.selectionModel().selectedRows()) == 1: row = self.ui.tableViewTaskDetail.selectionModel().selectedRows()[0].row() row_target_id_index = self.taskDetailModel.index(row, 11, QModelIndex()) targetId = self.taskDetailModel.data(row_target_id_index, Qt.ItemDataRole.DisplayRole) row_target_type_name_index = self.taskDetailModel.index(row, 3, QModelIndex()) targetTypeName = self.taskDetailModel.data(row_target_type_name_index, Qt.ItemDataRole.DisplayRole) if targetTypeName == "任务": self.clearTreeModel() self.appendTaskItem(targetId) self.ui.stackedWidgetDescription.setCurrentIndex(1) else: info = instructionManager.getInfo(targetId) attr = info.get('attr') if attr == None: self.ui.textEditDescription.clear() else: description = attr.get('description') if description == None: self.ui.textEditDescription.clear() else: self.ui.textEditDescription.setText(description) self.ui.stackedWidgetDescription.setCurrentIndex(0) def appendTaskItem(self, taskId): try: task = taskManager.getInfo(str(taskId)) if task: name = task["name"] item = QStandardItem(str(name)) self.appendChildTask(item, str(taskId)) self.rootItem.appendRow([item]) self.ui.treeViewDescription.expandAll() except Exception as e: print(e) def appendChildTask(self, parent, taskId): try: taskInstructions = taskInstructionManager.getInfo(taskId) if taskInstructions: for taskInstruction in taskInstructions: target_type = taskInstruction["target_type"] task_instruction_id = str(taskInstruction["id"]) level = taskInstruction["level"] if target_type == "task": task = taskManager.getInfo(str(taskInstruction["target_id"])) if task: name = task["name"] childItem = QStandardItem(str(name)) parent.appendRow([childItem]) except Exception as e: print(e) def deleteTaskDetail(self): if len(self.ui.tableViewTaskDetail.selectionModel().selectedRows())== 1: row = self.ui.tableViewTaskDetail.selectionModel().selectedRows()[0].row() row_name_index = self.taskDetailModel.index(row, 4, QModelIndex()) targetName = self.taskDetailModel.data(row_name_index, Qt.ItemDataRole.DisplayRole) if self.topWidget == None: self.topWidget = self.findTopLevelParent(self) if self.topWidget != None: if self.topWidget.removeDialog(targetName,"删除功能"): row_taskDetail_index = self.taskDetailModel.index(row, 0, QModelIndex()) taskInstructionId = self.taskDetailModel.data(row_taskDetail_index, Qt.ItemDataRole.DisplayRole) if taskInstructionManager.delete(taskInstructionId): self.taskDetailModel.removeRow(row) def updateTask(self): if self.taskModelBlockSignals == True: return if len(self.ui.tableViewTask.selectionModel().selectedRows()) == 1: row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row() row_id_index = self.taskModel.index(row, 0, QModelIndex()) row_name_index = self.taskModel.index(row, 2, QModelIndex()) row_loop_index = self.taskModel.index(row, 3, QModelIndex()) row_delay_index = self.taskModel.index(row, 4, QModelIndex()) row_remark_index = self.taskModel.index(row, 5, QModelIndex()) name = self.taskModel.data(row_name_index, Qt.ItemDataRole.DisplayRole) delay = self.taskModel.data(row_delay_index, Qt.ItemDataRole.DisplayRole) loop = self.taskModel.data(row_loop_index, Qt.ItemDataRole.DisplayRole) remark = self.taskModel.data(row_remark_index, Qt.ItemDataRole.DisplayRole) taskId = self.taskModel.data(row_id_index, Qt.ItemDataRole.DisplayRole) taskParam = { "name": name, "delay": delay, "loop": loop, "remark": remark } result = taskManager.update(taskId, taskParam) def updateTaskInstruction(self): if self.taskDetailModelBlockSignals == True: return if len(self.ui.tableViewTaskDetail.selectionModel().selectedRows()) == 1: row = self.ui.tableViewTaskDetail.selectionModel().selectedRows()[0].row() row_id_index = self.taskDetailModel.index(row, 0, QModelIndex()) row_delay_index = self.taskDetailModel.index(row, 6, QModelIndex()) row_loop_index = self.taskDetailModel.index(row, 7, QModelIndex()) row_param_index = self.taskDetailModel.index(row, 8, QModelIndex()) row_interfacenum_index = self.taskDetailModel.index(row, 9, QModelIndex()) delay = self.taskDetailModel.data(row_delay_index, Qt.ItemDataRole.DisplayRole) loop = self.taskDetailModel.data(row_loop_index, Qt.ItemDataRole.DisplayRole) param = self.taskDetailModel.data(row_param_index, Qt.ItemDataRole.DisplayRole) interfaceIndex = self.taskDetailModel.data(row_interfacenum_index, Qt.ItemDataRole.DisplayRole) taskInstanceId = self.taskDetailModel.data(row_id_index, Qt.ItemDataRole.DisplayRole) taskInstanceParam = { "delay": delay, "loop": loop, "target_param": param, "interface_index": interfaceIndex } result = taskInstructionManager.update(taskInstanceId, taskInstanceParam) def setItemsEnable(self, enable): self.ui.pbInsertTask.setEnabled(enable) self.ui.pbDeleteTask.setEnabled(enable) self.ui.pbInsertInstruction.setEnabled(enable) if not enable: self.ui.tableViewTask.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) else: self.ui.tableViewTask.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) def clearTreeModel(self): try: for i in range(self.taskDetailDescriptionModel.rowCount()): self.taskDetailDescriptionModel.removeRow(0) except Exception as e: print(e) #加载任务详情 def loadTaskDetail(self, taskId): self.setItemsEnable(False) self.taskDetailModelBlockSignals = True self.taskDetailModel.clear() self.ui.textEditDescription.clear() self.clearTreeModel() self.loadPageTaskDetail(taskId, 0, 50) self.taskDetailModelBlockSignals = False self.setItemsEnable(True) self.batchOperation() def loadPageTaskDetail(self, taskId, row, limit): QCoreApplication.processEvents() if taskId: taskInstructions = taskInstructionManager.getPageInfo(taskId,row, limit) if len(taskInstructions) > 0: for taskInstruction in taskInstructions: index = self.taskDetailModel.rowCount() self.taskDetailModel.setItem(index, 0, QStandardItem(str(taskInstruction["id"]))) self.taskDetailModel.setItem(index, 1, QStandardItem(str(taskInstruction["task_id"]))) name = "" type = "" devicename = "" dev_model_id = "" devinterface = [] if taskInstruction["target_type"] == "instruction": instruction = instructionManager.getInfo(str(taskInstruction["target_id"])) if instruction: name = instruction["name"] type = instruction["type"] if instruction["type"] is not None and instruction["type"] in self.supportedTypes: type = self.supportedTypes[instruction["type"]]["name"] device_id = taskInstruction["device_id"] device = deviceManager.getInfo(device_id) if device != None: devicename = device["name"] dev_model_id = device["dev_model_id"] devinterface = device["interface"] elif taskInstruction["target_type"] == "task": task = taskManager.getInfo(taskInstruction["target_id"]) if task != None: devicename = "任务" name = task["name"] self.taskDetailModel.setItem(index, 2, QStandardItem(str(index+1))) self.taskDetailModel.setItem(index, 3, QStandardItem(devicename)) self.taskDetailModel.setItem(index, 4, QStandardItem(name)) self.taskDetailModel.setItem(index, 5, QStandardItem(type)) self.taskDetailModel.setItem(index, 6, QStandardItem(str(taskInstruction["delay"]))) self.taskDetailModel.setItem(index, 7, QStandardItem(str(taskInstruction["loop"]))) self.taskDetailModel.setItem(index, 8, QStandardItem(taskInstruction["target_param"])) self.taskDetailModel.setItem(index, 9, QStandardItem("")) self.taskDetailModel.setItem(index, 10, QStandardItem(str(taskInstruction["level"]))) self.taskDetailModel.setItem(index, 11, QStandardItem(str(taskInstruction["target_id"]))) self.setUnEditableStyle(self.taskDetailModel.item(index, 2)) self.setDeviceStyle(self.taskDetailModel.item(index, 2), devicename) self.setUnEditableStyle(self.taskDetailModel.item(index, 3)) self.setUnEditableStyle(self.taskDetailModel.item(index, 4)) self.setUnEditableStyle(self.taskDetailModel.item(index, 5)) devModel = devModelManager.getInfo(dev_model_id) if devModel != None: attr_json_dict = devModel["attr"] devmodelInterfacetypes = {} if "interfaceType" in attr_json_dict: devmodelInterfacetypes = attr_json_dict["interfaceType"] if len(devmodelInterfacetypes) > 0: cmb = NoWheelComboBox() cmb.currentIndexChanged.connect(self.changeInterface) for devmodelInterfacetype in devmodelInterfacetypes: cmb.addItem(devmodelInterfacetype) interface_index = "interface_index" in taskInstruction and taskInstruction["interface_index"] or 0 interface_index = interface_index != "" and interface_index or 0 if interface_index < len(devmodelInterfacetypes): cmb.setCurrentIndex(interface_index) self.taskDetailModel.setItem(index, 9, QStandardItem(str(interface_index))) else: if len(devmodelInterfacetypes) > 0: cmb.setCurrentIndex(0) taskInstructionManager.update(str(taskInstruction["id"]), {"interface_index":0}) # 更新 self.taskDetailModel.setItem(index, 9, QStandardItem("0")) self.ui.tableViewTaskDetail.setIndexWidget(self.taskDetailModel.index(index, 9), cmb) self.batchOperation() self.loadPageTaskDetail(taskId, row + limit,limit) else: return # 切换接口 def changeInterface(self,index): if len(self.ui.tableViewTaskDetail.selectionModel().selectedRows())== 1: row = self.ui.tableViewTaskDetail.selectionModel().selectedRows()[0].row() self.taskDetailModel.setItem(row, 9 , QStandardItem(str(index))) def setTaskStyle(self,item,type): if type == "parent": item.setForeground(QColor(255, 255, 255)) item.setBackground(QColor(240, 35, 35)) elif type == "child": item.setForeground(QColor(0, 0, 0)) item.setBackground(QColor(238, 191, 63)) def setDeviceStyle(self,item,device_name): if device_name == "": item.setBackground(QColor(229, 214, 223)) else: item.setForeground(QColor(0, 0, 0)) #设置不可编辑样式 def setUnEditableStyle(self, item): item.setEditable(False) def setSplitterStretchFactor(self): self.ui.splitter.setStretchFactor(0, 15) self.ui.splitter.setStretchFactor(1, 35) self.ui.splitter.setStretchFactor(2, 50) # 批量操作 def batchOperation(self): self.setAllHorizontalHeaderLabels() self.hideAllColumn() self.setAllColumnWidth() # 批量设置标题 def setAllHorizontalHeaderLabels(self): self.taskGroupModel.setHorizontalHeaderLabels(["ID","","名称"]) self.taskModel.setHorizontalHeaderLabels(["ID","","名称", "循环次数", "间隔时间(ms)", "备注", "进度","组ID"]) self.taskDetailModel.setHorizontalHeaderLabels(["ID","任务ID","","设备","名称", "类型", "间隔时间(ms)", "循环次数", "参数", "端口", "序号"]) # 隐藏指定列 def hideAllColumn(self): self.ui.tableViewTask.setColumnHidden(0, True) self.ui.tableViewTask.setColumnHidden(1, True) self.ui.tableViewTask.setColumnHidden(7, True) self.ui.tableViewTask.setColumnHidden(8, True) self.ui.tableViewTaskGroup.setColumnHidden(0, True) self.ui.tableViewTaskGroup.setColumnHidden(1, True) self.ui.tableViewTaskDetail.setColumnHidden(0, True) self.ui.tableViewTaskDetail.setColumnHidden(1, True) self.ui.tableViewTaskDetail.setColumnHidden(10, True) self.ui.tableViewTaskDetail.setColumnHidden(11, True) # 批量设置列宽 def setAllColumnWidth(self): if self.taskGroupModel.rowCount() > 0: self.ui.tableViewTaskGroup.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.ResizeToContents) self.ui.tableViewTaskGroup.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch) if self.taskModel.rowCount() > 0: self.ui.tableViewTask.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents) self.ui.tableViewTask.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeMode.Stretch) self.ui.tableViewTask.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeMode.Stretch) self.ui.tableViewTask.horizontalHeader().setSectionResizeMode(5, QHeaderView.ResizeMode.Stretch) self.ui.tableViewTask.horizontalHeader().setSectionResizeMode(6, QHeaderView.ResizeMode.Interactive) if self.taskDetailModel.rowCount() > 0: self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents) self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeMode.Interactive) self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeMode.ResizeToContents) self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(5, QHeaderView.ResizeMode.Stretch) self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(6, QHeaderView.ResizeMode.Stretch) self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(7, QHeaderView.ResizeMode.Stretch) self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(8, QHeaderView.ResizeMode.Stretch) self.ui.tableViewTaskDetail.horizontalHeader().setSectionResizeMode(9, QHeaderView.ResizeMode.Interactive) #加载全部被包含的子任务 def loadAllSubTasks(self): self.subTasks = {} self.parentTasks = {} includingsubtasks = taskInstructionManager.getIncludingsubtasks() if len(includingsubtasks) > 0: for task in includingsubtasks: taskInfo = taskManager.getInfo(str(task["task_id"])) if taskInfo: taskName = taskInfo["name"] self.parentTasks[str(task["task_id"])] = True if str(task["target_id"]) in self.subTasks: if taskName not in self.subTasks[str(task["target_id"])]: self.subTasks[str(task["target_id"])].append(taskName) else: self.subTasks[str(task["target_id"])] = [] self.subTasks[str(task["target_id"])].append(taskName) # 加载队列组 def loadTaskGroup(self): self.taskGroupModel.clear() self.ui.textEditDescription.clear() self.clearTreeModel() groups = taskGroupManager.getInfo() self.taskGroupModelBlockSignals = True if len(groups) > 0: for group in groups: index = self.taskGroupModel.rowCount() self.taskGroupModel.setItem(index, 0, QStandardItem(str(group["id"]))) self.taskGroupModel.setItem(index, 1, QStandardItem(str(index+1))) self.taskGroupModel.setItem(index, 2, QStandardItem(group["name"])) self.setUnEditableStyle(self.taskGroupModel.item(index, 1)) self.taskGroupModelBlockSignals = False self.batchOperation() # 加载队列 def loadTask(self): self.loadAllSubTasks() self.taskModel.clear() self.ui.textEditDescription.clear() self.clearTreeModel() tasks = taskManager.getGroupTask(self.current_groupId) self.taskModelBlockSignals = True if len(tasks) > 0: for task in tasks: index = self.taskModel.rowCount() progressItem = QxStandardItem('',self) # 从全局缓存恢复进度值(如果有) task_id = str(task["id"]) if task_id in self.taskProgressCache: cache = self.taskProgressCache[task_id] progressItem.setData({'task_instruction_id': task["id"], 'name': task["name"], 'value': cache['value'], 'maximum': cache['maximum']}, Qt.ItemDataRole.UserRole) else: progressItem.setData({'task_instruction_id': task["id"], 'name': task["name"]}, Qt.ItemDataRole.UserRole) self.taskModel.setItem(index, 0, QStandardItem(str(task["id"]))) self.taskModel.setItem(index, 1, QStandardItem(str(index+1))) self.taskModel.setItem(index, 2, QStandardItem(task["name"])) self.taskModel.setItem(index, 3, QStandardItem(str(task["loop"]))) self.taskModel.setItem(index, 4, QStandardItem(str(task["delay"]))) self.taskModel.setItem(index, 5, QStandardItem(task["remark"])) self.taskModel.setItem(index, 6, progressItem) self.taskModel.setItem(index, 7, QStandardItem(str(task["group_id"]))) self.taskModel.setItem(index, 8, QStandardItem("normal")) self.setUnEditableStyle(self.taskModel.item(index, 1)) delegate = ProgressBarDelegate() self.ui.tableViewTask.setItemDelegateForColumn(6, delegate) if task_id in self.parentTasks: self.taskModel.setItem(index, 8, QStandardItem("parent")) if task_id in self.subTasks: self.taskModel.setItem(index, 8, QStandardItem("child")) self.taskModelBlockSignals = False self.batchOperation() def _onUpdateProgress(self, taskId, value, maxValue): # 更新全局缓存 self.taskProgressCache[str(taskId)] = {'value': value, 'maximum': maxValue} # 任务完成时清理缓存 if value >= maxValue and maxValue > 0: self.taskProgressCache.pop(str(taskId), None) # 更新当前显示的模型 for row in range(self.taskModel.rowCount()): item = self.taskModel.item(row, 6) if item is not None: obj = item.data(Qt.ItemDataRole.UserRole) if obj is not None and isinstance(obj, dict): if str(taskId) == str(obj.get('task_instruction_id')): self.taskModelBlockSignals = True item.setData({'value': value, 'maximum': maxValue, 'task_instruction_id': obj.get('task_instruction_id'), 'name': obj.get('name')}, Qt.ItemDataRole.UserRole) def _onTaskStop(self, taskId): """任务停止时清理缓存和进度显示""" taskId = str(taskId) # 清理缓存 self.taskProgressCache.pop(taskId, None) # 刷新进度显示(重置为0/0或清空) for row in range(self.taskModel.rowCount()): item = self.taskModel.item(row, 6) if item is not None: obj = item.data(Qt.ItemDataRole.UserRole) if obj is not None and isinstance(obj, dict): if taskId == str(obj.get('task_instruction_id')): self.taskModelBlockSignals = True # 重置进度为0/0(隐藏进度条) item.setData({'value': -1, 'maximum': -1, 'task_instruction_id': obj.get('task_instruction_id'), 'name': obj.get('name')}, Qt.ItemDataRole.UserRole) self.taskModelBlockSignals = False # 强制刷新UI self.ui.tableViewTask.viewport().update() return def _onTaskStart(self, taskId): """任务启动时初始化进度显示""" taskId = str(taskId) # 初始化缓存为 0/total(会在第一次 updateProgress 时更新) self.taskProgressCache[taskId] = {'value': 0, 'maximum': 1} # 刷新显示 for row in range(self.taskModel.rowCount()): item = self.taskModel.item(row, 6) if item is not None: obj = item.data(Qt.ItemDataRole.UserRole) if obj is not None and isinstance(obj, dict): if taskId == str(obj.get('task_instruction_id')): self.taskModelBlockSignals = True item.setData({'value': 0, 'maximum': 1, 'task_instruction_id': obj.get('task_instruction_id'), 'name': obj.get('name')}, Qt.ItemDataRole.UserRole) self.taskModelBlockSignals = False self.ui.tableViewTask.viewport().update() return