submit 0421
parent
97dee8326b
commit
596f1b9673
|
|
@ -4,7 +4,9 @@
|
||||||
"Bash(python3 -c ' *)",
|
"Bash(python3 -c ' *)",
|
||||||
"Bash(sqlite3 data.db \"PRAGMA table_info\\(task_instruction\\);\")",
|
"Bash(sqlite3 data.db \"PRAGMA table_info\\(task_instruction\\);\")",
|
||||||
"Bash(venv/Scripts/python.exe -c ' *)",
|
"Bash(venv/Scripts/python.exe -c ' *)",
|
||||||
"Bash(venv/Scripts/python.exe -c \"import py_compile; py_compile.compile\\('taskForm.py', doraise=True\\)\")"
|
"Bash(venv/Scripts/python.exe -c \"import py_compile; py_compile.compile\\('taskForm.py', doraise=True\\)\")",
|
||||||
|
"Bash(venv/Scripts/pip list *)",
|
||||||
|
"Bash(venv/Scripts/pip install *)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
25
common.py
25
common.py
|
|
@ -432,11 +432,12 @@ class Common(QObject):
|
||||||
self.scanfResult = msg
|
self.scanfResult = msg
|
||||||
|
|
||||||
@pyqtSlot(str,str,str,str, result=bool)
|
@pyqtSlot(str,str,str,str, result=bool)
|
||||||
|
@pyqtSlot(str, str, str, str, result=bool)
|
||||||
def initAppScript(self, appId, instancName, scriptFile, plusFile="plus"):
|
def initAppScript(self, appId, instancName, scriptFile, plusFile="plus"):
|
||||||
try:
|
try:
|
||||||
if dog.isDogAlive() == 1 or suDog.isDogAlive() == 1:
|
if dog.isDogAlive() == 1 or suDog.isDogAlive() == 1:
|
||||||
scriptPath = os.path.join(self.appPath,"qml",plusFile,appId,"script", scriptFile)
|
scriptPath = os.path.join(self.appPath,"qml",plusFile,appId,"script", scriptFile)
|
||||||
with open(scriptPath, "r") as f:
|
with open(scriptPath, "r") as f:
|
||||||
script = f.read()
|
script = f.read()
|
||||||
exec(script, self.qscript)
|
exec(script, self.qscript)
|
||||||
if self.qscript != {}:
|
if self.qscript != {}:
|
||||||
|
|
@ -447,6 +448,10 @@ class Common(QObject):
|
||||||
print(e)
|
print(e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@pyqtSlot(str, result=QVariant)
|
||||||
|
def getScript(self, name):
|
||||||
|
return self.qscript.get(name, None)
|
||||||
|
|
||||||
@pyqtSlot(str,str,str,str,str, result=bool)
|
@pyqtSlot(str,str,str,str,str, result=bool)
|
||||||
def registAppQml(self, appId, instancName, className, scriptFile, plusFile="plus"):
|
def registAppQml(self, appId, instancName, className, scriptFile, plusFile="plus"):
|
||||||
try:
|
try:
|
||||||
|
|
@ -915,6 +920,24 @@ class Common(QObject):
|
||||||
# export_table_structure_and_data('data.db', 'task_group')
|
# export_table_structure_and_data('data.db', 'task_group')
|
||||||
# export_table_structure_and_data('data.db', 'task_instruction')
|
# export_table_structure_and_data('data.db', 'task_instruction')
|
||||||
# 导入表结构和数据
|
# 导入表结构和数据
|
||||||
|
@pyqtSlot(str, result=str)
|
||||||
|
def readLogFile(self, file_path):
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||||||
|
return f.read()
|
||||||
|
except Exception as e:
|
||||||
|
return f"Error reading file {file_path}: {e}"
|
||||||
|
|
||||||
|
@pyqtSlot(str, result=list)
|
||||||
|
def getTxtFiles(self, directory):
|
||||||
|
try:
|
||||||
|
path = directory.replace("file:///", "")
|
||||||
|
if not os.path.exists(path):
|
||||||
|
return []
|
||||||
|
return [os.path.join(path, f) for f in sorted(os.listdir(path)) if os.path.isfile(os.path.join(path, f))]
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
|
||||||
def migrate_sql_to_database(self, db_path, table_name):
|
def migrate_sql_to_database(self, db_path, table_name):
|
||||||
import stat
|
import stat
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ class SessionSerial(SessionAbstract):
|
||||||
self.thread = QThread()
|
self.thread = QThread()
|
||||||
self.worker.moveToThread(self.thread)
|
self.worker.moveToThread(self.thread)
|
||||||
self.thread.started.connect(self.worker.start)
|
self.thread.started.connect(self.worker.start)
|
||||||
self.worker.newDataArrive.connect(self.onNewDataArrive)
|
self.worker.newDataArrive.connect(self.onNewDataArrive, type=Qt.ConnectionType.DirectConnection)
|
||||||
self.worker.connectSuccess.connect(self.onConnectSuccess)
|
self.worker.connectSuccess.connect(self.onConnectSuccess)
|
||||||
self.worker.connectClosed.connect(self.onConnectClosed)
|
self.worker.connectClosed.connect(self.onConnectClosed)
|
||||||
self.worker.connectFailed.connect(self.onConnectFailed)
|
self.worker.connectFailed.connect(self.onConnectFailed)
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ class SessionTbus(SessionAbstract):
|
||||||
self.thread = QThread()
|
self.thread = QThread()
|
||||||
self.worker.moveToThread(self.thread)
|
self.worker.moveToThread(self.thread)
|
||||||
self.thread.started.connect(self.worker.start)
|
self.thread.started.connect(self.worker.start)
|
||||||
self.worker.newDataArrive.connect(self.onNewDataArrive)
|
self.worker.newDataArrive.connect(self.onNewDataArrive, type=Qt.ConnectionType.DirectConnection)
|
||||||
self.worker.connectSuccess.connect(self.onConnectSuccess)
|
self.worker.connectSuccess.connect(self.onConnectSuccess)
|
||||||
self.worker.connectClosed.connect(self.onConnectClosed)
|
self.worker.connectClosed.connect(self.onConnectClosed)
|
||||||
self.worker.connectFailed.connect(self.onConnectFailed)
|
self.worker.connectFailed.connect(self.onConnectFailed)
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ class SessionTbusNs(SessionAbstract):
|
||||||
self.thread = QThread()
|
self.thread = QThread()
|
||||||
self.worker.moveToThread(self.thread)
|
self.worker.moveToThread(self.thread)
|
||||||
self.thread.started.connect(self.worker.start)
|
self.thread.started.connect(self.worker.start)
|
||||||
self.worker.newDataArrive.connect(self.onNewDataArrive)
|
self.worker.newDataArrive.connect(self.onNewDataArrive, type=Qt.ConnectionType.DirectConnection)
|
||||||
self.worker.connectSuccess.connect(self.onConnectSuccess)
|
self.worker.connectSuccess.connect(self.onConnectSuccess)
|
||||||
self.worker.connectClosed.connect(self.onConnectClosed)
|
self.worker.connectClosed.connect(self.onConnectClosed)
|
||||||
self.worker.connectFailed.connect(self.onConnectFailed)
|
self.worker.connectFailed.connect(self.onConnectFailed)
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ class MainWindow(QMainWindow):
|
||||||
self.ui = Ui_MainWindow()
|
self.ui = Ui_MainWindow()
|
||||||
self.ui.setupUi(self)
|
self.ui.setupUi(self)
|
||||||
self.ui.tbDefault.setVisible(False)
|
self.ui.tbDefault.setVisible(False)
|
||||||
self.isDebugQML = False #DEBUG
|
self.isDebugQML = True #DEBUG
|
||||||
self.setWindowTitle("TG-TestingPlatform "+app_version.data["version"])
|
self.setWindowTitle("TG-TestingPlatform "+app_version.data["version"])
|
||||||
self.ui.lbtitle.setText("TG-TestingPlatform "+app_version.data["version"])
|
self.ui.lbtitle.setText("TG-TestingPlatform "+app_version.data["version"])
|
||||||
self.ui.logWidget.setVisible(True)
|
self.ui.logWidget.setVisible(True)
|
||||||
|
|
@ -234,7 +234,6 @@ class MainWindow(QMainWindow):
|
||||||
self.ui.quickTaskbar.setSource(QUrl(common.firstPath()+"/TaskBar.qml"))
|
self.ui.quickTaskbar.setSource(QUrl(common.firstPath()+"/TaskBar.qml"))
|
||||||
self.ui.quickStackView.setSource(QUrl(common.firstPath()+"/main.qml"))
|
self.ui.quickStackView.setSource(QUrl(common.firstPath()+"/main.qml"))
|
||||||
self.ui.quickSetting.setSource(QUrl(common.firstPath()+"/SettingView.qml"))
|
self.ui.quickSetting.setSource(QUrl(common.firstPath()+"/SettingView.qml"))
|
||||||
|
|
||||||
if self.isDebugQML:
|
if self.isDebugQML:
|
||||||
self.setDebugQML()
|
self.setDebugQML()
|
||||||
|
|
||||||
|
|
@ -249,7 +248,7 @@ class MainWindow(QMainWindow):
|
||||||
self.ui.quickDebug.rootContext().setContextProperty("taskManager", taskManager)
|
self.ui.quickDebug.rootContext().setContextProperty("taskManager", taskManager)
|
||||||
self.ui.quickDebug.rootContext().setContextProperty("interfaceManager", interfaceManager)
|
self.ui.quickDebug.rootContext().setContextProperty("interfaceManager", interfaceManager)
|
||||||
self.ui.quickDebug.rootContext().setContextProperty("common", common)
|
self.ui.quickDebug.rootContext().setContextProperty("common", common)
|
||||||
self.ui.quickDebug.setSource(QUrl(common.firstPath()+"/debug/gviewer/main.qml"))
|
self.ui.quickDebug.setSource(QUrl(common.firstPath()+"/debug/calibrate/main.qml"))
|
||||||
|
|
||||||
def clearContextProperties(self):
|
def clearContextProperties(self):
|
||||||
# 清除QML引擎缓存
|
# 清除QML引擎缓存
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ Rectangle
|
||||||
property var g_sn: "8441"
|
property var g_sn: "8441"
|
||||||
property var appPath: "/"+plusFile+"/"+appId+"/"
|
property var appPath: "/"+plusFile+"/"+appId+"/"
|
||||||
property var firstPath: ""
|
property var firstPath: ""
|
||||||
|
property var calibrate: null
|
||||||
property var startDate: new Date()
|
property var startDate: new Date()
|
||||||
property var startTime: startDate.getTime()
|
property var startTime: startDate.getTime()
|
||||||
property var endTime: startDate.getTime()
|
property var endTime: startDate.getTime()
|
||||||
|
|
@ -54,6 +55,7 @@ Rectangle
|
||||||
firstPath = common.firstPath()
|
firstPath = common.firstPath()
|
||||||
g_user = common.getCurrentUser()
|
g_user = common.getCurrentUser()
|
||||||
common.initAppScript(appId, "calibrate", "calibrate.py", plusFile)
|
common.initAppScript(appId, "calibrate", "calibrate.py", plusFile)
|
||||||
|
calibrate = common.getScript("calibrate")
|
||||||
setConfigInfo()
|
setConfigInfo()
|
||||||
calibrate.startShima(firstPath + appPath)
|
calibrate.startShima(firstPath + appPath)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,6 @@ import QtQuick.Dialogs
|
||||||
// import QtQuick.Controls.
|
// import QtQuick.Controls.
|
||||||
import "./app.js" as App
|
import "./app.js" as App
|
||||||
import "./common"
|
import "./common"
|
||||||
import Qt.labs.folderlistmodel
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
radius: 9
|
radius: 9
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import QtQuick.Dialogs
|
||||||
// import QtQuick.Controls.
|
// import QtQuick.Controls.
|
||||||
import "./app.js" as App
|
import "./app.js" as App
|
||||||
import "./common"
|
import "./common"
|
||||||
import Qt.labs.folderlistmodel
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
@ -55,6 +54,24 @@ Rectangle {
|
||||||
GradientStop { position: 1.0; color: "#b7d6fb" }
|
GradientStop { position: 1.0; color: "#b7d6fb" }
|
||||||
orientation: Gradient.Horizontal
|
orientation: Gradient.Horizontal
|
||||||
}
|
}
|
||||||
|
ListModel { id: fileListModel }
|
||||||
|
|
||||||
|
function refreshFileList() {
|
||||||
|
fileListModel.clear()
|
||||||
|
if (logDirectory) {
|
||||||
|
var files = common.getTxtFiles(logDirectory)
|
||||||
|
for (var i = 0; i < files.length; i++) {
|
||||||
|
var fp = files[i].toString()
|
||||||
|
fileListModel.append({
|
||||||
|
"fileName": fp.substring(fp.lastIndexOf('/') + 1).replace(/\\/g, '/').split('/').pop(),
|
||||||
|
"filePath": fp
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onLogDirectoryChanged: { refreshFileList() }
|
||||||
|
|
||||||
ListModel{
|
ListModel{
|
||||||
id: logModel
|
id: logModel
|
||||||
}
|
}
|
||||||
|
|
@ -138,24 +155,16 @@ Rectangle {
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
ScrollBar.vertical: ScrollBar{}
|
ScrollBar.vertical: ScrollBar{}
|
||||||
anchors.margins: 5
|
anchors.margins: 5
|
||||||
model: FolderListModel {
|
model: fileListModel
|
||||||
id: folderModel
|
|
||||||
rootFolder: logDirectory
|
|
||||||
showDirsFirst: true
|
|
||||||
showFiles: true
|
|
||||||
folder: logDirectory // 显式设置初始路径
|
|
||||||
}
|
|
||||||
delegate: ItemDelegate {
|
delegate: ItemDelegate {
|
||||||
text: model.fileName
|
text: model.fileName
|
||||||
icon.source: "resource/file.svg"
|
icon.source: "resource/file.svg"
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: fileSystemView.currentIndex == index ? "#D9D9D9" : "white"
|
color: fileSystemView.currentIndex == index ? "#D9D9D9" : "white"
|
||||||
// 代理项的其他内容...
|
|
||||||
}
|
}
|
||||||
onClicked: {
|
onClicked: {
|
||||||
console.info("Clicked on: " + model.fileName)
|
|
||||||
currentLogfilePath = model.filePath
|
currentLogfilePath = model.filePath
|
||||||
currentLogResult = log_processor.read_file(currentLogfilePath)
|
currentLogResult = common.readLogFile(currentLogfilePath)
|
||||||
updateLogDisplay()
|
updateLogDisplay()
|
||||||
fileSystemView.currentIndex = index
|
fileSystemView.currentIndex = index
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -565,8 +565,8 @@ class TaskForm(QWidget):
|
||||||
row_id_index = self.taskGroupModel.index(row, 0, QModelIndex())
|
row_id_index = self.taskGroupModel.index(row, 0, QModelIndex())
|
||||||
group_id = self.taskGroupModel.data(row_id_index, Qt.ItemDataRole.DisplayRole)
|
group_id = self.taskGroupModel.data(row_id_index, Qt.ItemDataRole.DisplayRole)
|
||||||
self.current_groupId = group_id
|
self.current_groupId = group_id
|
||||||
self.loadTask()
|
|
||||||
self.clearChildrenModel()
|
self.clearChildrenModel()
|
||||||
|
QTimer.singleShot(0, self.loadTask)
|
||||||
|
|
||||||
#任务列表选中
|
#任务列表选中
|
||||||
def handleTaskSelection(self, index):
|
def handleTaskSelection(self, index):
|
||||||
|
|
@ -955,6 +955,9 @@ class TaskForm(QWidget):
|
||||||
if str(taskId) == str(obj.get('task_instruction_id')):
|
if str(taskId) == str(obj.get('task_instruction_id')):
|
||||||
self.taskModelBlockSignals = True
|
self.taskModelBlockSignals = True
|
||||||
item.setData({'value': value, 'maximum': maxValue, 'task_instruction_id': obj.get('task_instruction_id'), 'name': obj.get('name')}, Qt.ItemDataRole.UserRole)
|
item.setData({'value': value, 'maximum': maxValue, 'task_instruction_id': obj.get('task_instruction_id'), 'name': obj.get('name')}, Qt.ItemDataRole.UserRole)
|
||||||
|
self.taskModelBlockSignals = False
|
||||||
|
self.ui.tableViewTask.viewport().update()
|
||||||
|
return
|
||||||
def _onTaskStop(self, taskId):
|
def _onTaskStop(self, taskId):
|
||||||
"""任务停止时清理缓存和进度显示"""
|
"""任务停止时清理缓存和进度显示"""
|
||||||
taskId = str(taskId)
|
taskId = str(taskId)
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ class TaskActuator(QThread):
|
||||||
loop = int(self.taskInfo.get("loop", 1))
|
loop = int(self.taskInfo.get("loop", 1))
|
||||||
delay = float(int(self.taskInfo.get("delay",0))/1000)
|
delay = float(int(self.taskInfo.get("delay",0))/1000)
|
||||||
taskIndex = 0
|
taskIndex = 0
|
||||||
total = instructionListLength * loop
|
total = instructionListLength * loop if loop > 0 else instructionListLength
|
||||||
self.updateProgress.emit(self.id, 0, total)
|
self.updateProgress.emit(self.id, 0, total)
|
||||||
self.updateDetails.emit(self.id, 0, total)
|
self.updateDetails.emit(self.id, 0, total)
|
||||||
self.updateDetails.emit(self.parentId, 0, total)
|
self.updateDetails.emit(self.parentId, 0, total)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,30 @@ from taskInstructionModel.taskInstructionManager import taskInstructionManager
|
||||||
from taskModel.taskManager import taskManager
|
from taskModel.taskManager import taskManager
|
||||||
from common import common
|
from common import common
|
||||||
|
|
||||||
|
class _KillThread(QThread):
|
||||||
|
done = pyqtSignal(object) # 传 actuator 回主线程处理
|
||||||
|
|
||||||
|
def __init__(self, actuator):
|
||||||
|
super().__init__()
|
||||||
|
self.actuator = actuator
|
||||||
|
self.finished.connect(self.deleteLater)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
a = self.actuator
|
||||||
|
if not a.wait(500):
|
||||||
|
for item in a.instructionList:
|
||||||
|
try:
|
||||||
|
iface = item.get("interface")
|
||||||
|
if iface:
|
||||||
|
from interfaceSession.interfaceManager import interfaceManager
|
||||||
|
interfaceManager.getSession(iface).unlock()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
a.terminate()
|
||||||
|
a.wait(200)
|
||||||
|
self.done.emit(a)
|
||||||
|
|
||||||
|
|
||||||
class TaskActuatorManager(QObject):
|
class TaskActuatorManager(QObject):
|
||||||
logMsg = pyqtSignal(dict)
|
logMsg = pyqtSignal(dict)
|
||||||
taskStart = pyqtSignal(str)
|
taskStart = pyqtSignal(str)
|
||||||
|
|
@ -100,7 +124,6 @@ class TaskActuatorManager(QObject):
|
||||||
a for tid, a in list(self.taskActuatorDict.items())
|
a for tid, a in list(self.taskActuatorDict.items())
|
||||||
if a.isRunning() and not (excludeTaskId and str(tid) == str(excludeTaskId))
|
if a.isRunning() and not (excludeTaskId and str(tid) == str(excludeTaskId))
|
||||||
]
|
]
|
||||||
# 先全部设置停止标志
|
|
||||||
for a in actuators:
|
for a in actuators:
|
||||||
a.running_lock.lock()
|
a.running_lock.lock()
|
||||||
a.running = False
|
a.running = False
|
||||||
|
|
@ -111,25 +134,20 @@ class TaskActuatorManager(QObject):
|
||||||
a.subTaskActuator.running_lock.lock()
|
a.subTaskActuator.running_lock.lock()
|
||||||
a.subTaskActuator.running = False
|
a.subTaskActuator.running = False
|
||||||
a.subTaskActuator.running_lock.unlock()
|
a.subTaskActuator.running_lock.unlock()
|
||||||
# 再统一等待/强杀
|
|
||||||
for a in actuators:
|
|
||||||
a.quit()
|
a.quit()
|
||||||
if not a.wait(500):
|
kt = _KillThread(a)
|
||||||
for item in a.instructionList:
|
kt.done.connect(self._onKillDone)
|
||||||
try:
|
self._killThreads = getattr(self, '_killThreads', [])
|
||||||
iface = item.get("interface")
|
self._killThreads.append(kt)
|
||||||
if iface:
|
kt.start()
|
||||||
from interfaceSession.interfaceManager import interfaceManager
|
|
||||||
interfaceManager.getSession(iface).unlock()
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
a.terminate()
|
|
||||||
a.wait(200)
|
|
||||||
a.updateDetails.emit(a.id, -1, -1)
|
|
||||||
a.taskStop.emit(a.id)
|
|
||||||
log.info(f"任务 {a.id} 已停止")
|
|
||||||
return len(actuators)
|
return len(actuators)
|
||||||
|
|
||||||
|
def _onKillDone(self, a):
|
||||||
|
a.updateDetails.emit(a.id, -1, -1)
|
||||||
|
a.taskStop.emit(a.id)
|
||||||
|
log.info(f"任务 {a.id} 已停止")
|
||||||
|
self._killThreads = [t for t in getattr(self, '_killThreads', []) if t.isRunning()]
|
||||||
|
|
||||||
def requestStopAll(self, requesterTaskId=None):
|
def requestStopAll(self, requesterTaskId=None):
|
||||||
"""请求停止所有任务(由主程序处理)"""
|
"""请求停止所有任务(由主程序处理)"""
|
||||||
print(f"[DEBUG] requestStopAll 被调用,请求者: {requesterTaskId}")
|
print(f"[DEBUG] requestStopAll 被调用,请求者: {requesterTaskId}")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue