#include "procedureengine.h" #include "procedureparser.h" #include #include #include #include // ============================================================================= // 單例實現 // ============================================================================= ProcedureEngine *ProcedureEngine::s_instance = nullptr; ProcedureEngine *ProcedureEngine::instance() { if (!s_instance) { s_instance = new ProcedureEngine(); } return s_instance; } ProcedureEngine::ProcedureEngine(QObject *parent) : QObject(parent), m_parser(new ProcedureParser(this)), m_status(ProcedureStatus::Idle), m_executionTimer(new QTimer(this)) { connect(m_executionTimer, &QTimer::timeout, this, &ProcedureEngine::onExecutionTimeout); } ProcedureEngine::~ProcedureEngine() { } // ============================================================================= // 配置載入 // ============================================================================= bool ProcedureEngine::loadProcedure(const QString &configPath) { if (m_status == ProcedureStatus::Running || m_status == ProcedureStatus::Paused) { qWarning() << "程序正在執行中,無法載入新配置"; return false; } // 檢查文件是否存在 if (!QFile::exists(configPath)) { emit errorOccurred(QString("配置文件不存在: %1").arg(configPath)); return false; } // 解析配置 if (!m_parser->loadConfig(configPath)) { emit errorOccurred(QString("配置文件解析失敗: %1").arg(configPath)); return false; } m_config = m_parser->parseProcedureConfig(); // 驗證配置 if (!m_parser->validateConfig()) { QStringList errors = m_parser->getValidationErrors(); emit errorOccurred(QString("配置驗證失敗:\n%1").arg(errors.join("\n"))); return false; } // 初始化執行上下文 resetExecutionContext(); m_configPath = configPath; setStatus(ProcedureStatus::Loaded); emit procedureLoaded(m_config.procedureName); qDebug() << "程序載入成功:" << m_config.procedureName; qDebug() << " - 任務組數量:" << m_config.testTaskGroups.size(); qDebug() << " - 活動序列數量:" << m_config.activitySequence.size(); return true; } void ProcedureEngine::resetExecutionContext() { m_context = ExecutionContext(); m_context.currentActivityIndex = -1; m_context.currentStageIndex = -1; m_context.currentActionIndex = -1; m_context.loopIteration = 0; m_context.startTime = QDateTime(); } // ============================================================================= // 程序控制 // ============================================================================= void ProcedureEngine::startProcedure() { if (m_status != ProcedureStatus::Loaded && m_status != ProcedureStatus::Completed) { qWarning() << "程序狀態不正確,無法啟動"; return; } resetExecutionContext(); m_context.startTime = QDateTime::currentDateTime(); setStatus(ProcedureStatus::Running); emit procedureStarted(); // 移動到第一個活動 moveToFirstActivity(); } void ProcedureEngine::pauseProcedure() { if (m_status != ProcedureStatus::Running) { return; } m_executionTimer->stop(); setStatus(ProcedureStatus::Paused); emit procedurePaused(); } void ProcedureEngine::resumeProcedure() { if (m_status != ProcedureStatus::Paused) { return; } setStatus(ProcedureStatus::Running); emit procedureResumed(); // 繼續執行當前動作 executeCurrentAction(); } void ProcedureEngine::stopProcedure() { if (m_status == ProcedureStatus::Idle || m_status == ProcedureStatus::Loaded) { return; } m_executionTimer->stop(); setStatus(ProcedureStatus::Stopped); emit procedureStopped(); } void ProcedureEngine::resetProcedure() { stopProcedure(); resetExecutionContext(); setStatus(ProcedureStatus::Loaded); // 清除所有表格數據 m_tableData.clear(); } // ============================================================================= // 活動導航 // ============================================================================= void ProcedureEngine::moveToFirstActivity() { if (m_config.activitySequence.isEmpty()) { completeProcedure(); return; } m_context.currentActivityIndex = 0; m_context.currentStageIndex = -1; m_context.currentActionIndex = -1; enterCurrentActivity(); } bool ProcedureEngine::moveToNextActivity() { if (m_status != ProcedureStatus::Running) { return false; } int nextIndex = m_context.currentActivityIndex + 1; if (nextIndex >= m_config.activitySequence.size()) { // 沒有更多活動 completeProcedure(); return false; } m_context.currentActivityIndex = nextIndex; m_context.currentStageIndex = -1; m_context.currentActionIndex = -1; enterCurrentActivity(); return true; } bool ProcedureEngine::moveToPreviousActivity() { if (m_status != ProcedureStatus::Running && m_status != ProcedureStatus::Paused) { return false; } int prevIndex = m_context.currentActivityIndex - 1; if (prevIndex < 0) { return false; } m_context.currentActivityIndex = prevIndex; m_context.currentStageIndex = -1; m_context.currentActionIndex = -1; enterCurrentActivity(); return true; } bool ProcedureEngine::jumpToActivity(int index) { if (index < 0 || index >= m_config.activitySequence.size()) { return false; } m_context.currentActivityIndex = index; m_context.currentStageIndex = -1; m_context.currentActionIndex = -1; enterCurrentActivity(); return true; } void ProcedureEngine::enterCurrentActivity() { if (m_context.currentActivityIndex < 0 || m_context.currentActivityIndex >= m_config.activitySequence.size()) { return; } const ActivityStep &step = m_config.activitySequence[m_context.currentActivityIndex]; qDebug() << "進入活動:" << step.name << "(" << step.ref << ")"; emit activityStarted(m_context.currentActivityIndex, step); if (step.type == ActivityType::TEST_TASK_GROUP) { // 開始執行任務組 startTaskGroupExecution(step.ref); } else if (step.type == ActivityType::RESULT_DISPLAY) { // 顯示結果 displayResult(step.ref); } } // ============================================================================= // 任務組執行 // ============================================================================= void ProcedureEngine::startTaskGroupExecution(const QString &taskGroupRef) { if (!m_config.testTaskGroups.contains(taskGroupRef)) { emit errorOccurred(QString("找不到任務組: %1").arg(taskGroupRef)); return; } const TestTaskGroup &taskGroup = m_config.testTaskGroups[taskGroupRef]; qDebug() << "開始執行任務組:" << taskGroup.name; qDebug() << " - 階段數量:" << taskGroup.stages.size(); emit taskGroupStarted(taskGroupRef, taskGroup.name); // 初始化表格 for (const QString &tableRef : taskGroup.tableRefs) { initializeTable(tableRef); } // 移動到第一個階段 if (!taskGroup.stages.isEmpty()) { m_context.currentStageIndex = 0; m_context.currentActionIndex = -1; enterCurrentStage(taskGroupRef); } else { // 沒有階段,完成任務組 completeTaskGroup(taskGroupRef); } } void ProcedureEngine::enterCurrentStage(const QString &taskGroupRef) { if (!m_config.testTaskGroups.contains(taskGroupRef)) { return; } const TestTaskGroup &taskGroup = m_config.testTaskGroups[taskGroupRef]; if (m_context.currentStageIndex < 0 || m_context.currentStageIndex >= taskGroup.stages.size()) { completeTaskGroup(taskGroupRef); return; } const TestActivityGroup &stage = taskGroup.stages[m_context.currentStageIndex]; qDebug() << "進入階段:" << stage.name; emit stageStarted(m_context.currentStageIndex, stage.name); // 檢查跳過條件 if (!stage.skipCondition.isEmpty() && evaluateCondition(stage.skipCondition)) { qDebug() << "階段被跳過:" << stage.name; moveToNextStage(taskGroupRef); return; } // 移動到第一個動作 if (!stage.actions.isEmpty()) { m_context.currentActionIndex = 0; executeCurrentAction(); } else { // 沒有動作,移動到下一個階段 moveToNextStage(taskGroupRef); } } void ProcedureEngine::moveToNextStage(const QString &taskGroupRef) { if (!m_config.testTaskGroups.contains(taskGroupRef)) { return; } const TestTaskGroup &taskGroup = m_config.testTaskGroups[taskGroupRef]; int nextStageIndex = m_context.currentStageIndex + 1; if (nextStageIndex >= taskGroup.stages.size()) { // 檢查循環 m_context.loopIteration++; if (m_context.loopIteration < taskGroup.loopCount) { // 繼續下一輪 m_context.currentStageIndex = 0; m_context.currentActionIndex = -1; enterCurrentStage(taskGroupRef); } else { // 完成任務組 completeTaskGroup(taskGroupRef); } return; } m_context.currentStageIndex = nextStageIndex; m_context.currentActionIndex = -1; enterCurrentStage(taskGroupRef); } void ProcedureEngine::completeTaskGroup(const QString &taskGroupRef) { qDebug() << "任務組完成:" << taskGroupRef; m_context.loopIteration = 0; emit taskGroupCompleted(taskGroupRef); // 自動移動到下一個活動(如果處於運行狀態) if (m_status == ProcedureStatus::Running) { // 使用延遲以允許UI更新 QTimer::singleShot(100, this, [this]() { moveToNextActivity(); }); } } // ============================================================================= // 動作執行 // ============================================================================= void ProcedureEngine::executeCurrentAction() { if (m_status != ProcedureStatus::Running) { return; } const ActivityStep &step = m_config.activitySequence[m_context.currentActivityIndex]; if (step.type != ActivityType::TEST_TASK_GROUP) { return; } if (!m_config.testTaskGroups.contains(step.ref)) { return; } const TestTaskGroup &taskGroup = m_config.testTaskGroups[step.ref]; if (m_context.currentStageIndex < 0 || m_context.currentStageIndex >= taskGroup.stages.size()) { return; } const TestActivityGroup &stage = taskGroup.stages[m_context.currentStageIndex]; if (m_context.currentActionIndex < 0 || m_context.currentActionIndex >= stage.actions.size()) { // 階段動作執行完畢,移動到下一個階段 emit stageCompleted(m_context.currentStageIndex); moveToNextStage(step.ref); return; } const TestAction &action = stage.actions[m_context.currentActionIndex]; qDebug() << "執行動作:" << action.actionId << "-" << action.functionName; emit actionStarted(m_context.currentActionIndex, action.actionId); // 設置超時 if (action.timeout > 0) { m_executionTimer->start(action.timeout); } // 請求執行動作(通過信號通知外部執行) emit executeActionRequested(action); } void ProcedureEngine::onActionCompleted(const QString &actionId, const QVariantMap &results) { m_executionTimer->stop(); qDebug() << "動作完成:" << actionId; emit actionCompleted(m_context.currentActionIndex, actionId, results); // 處理結果(寫入表格等) processActionResults(actionId, results); // 移動到下一個動作 moveToNextAction(); } void ProcedureEngine::onActionFailed(const QString &actionId, const QString &error) { m_executionTimer->stop(); qWarning() << "動作執行失敗:" << actionId << "-" << error; emit actionFailed(m_context.currentActionIndex, actionId, error); // 根據配置決定是否繼續 // TODO: 可配置的錯誤處理策略 moveToNextAction(); } void ProcedureEngine::moveToNextAction() { if (m_status != ProcedureStatus::Running) { return; } m_context.currentActionIndex++; executeCurrentAction(); } void ProcedureEngine::onExecutionTimeout() { qWarning() << "動作執行超時"; const ActivityStep &step = m_config.activitySequence[m_context.currentActivityIndex]; if (step.type == ActivityType::TEST_TASK_GROUP && m_config.testTaskGroups.contains(step.ref)) { const TestTaskGroup &taskGroup = m_config.testTaskGroups[step.ref]; if (m_context.currentStageIndex >= 0 && m_context.currentStageIndex < taskGroup.stages.size()) { const TestActivityGroup &stage = taskGroup.stages[m_context.currentStageIndex]; if (m_context.currentActionIndex >= 0 && m_context.currentActionIndex < stage.actions.size()) { const TestAction &action = stage.actions[m_context.currentActionIndex]; onActionFailed(action.actionId, "執行超時"); return; } } } // 如果無法確定當前動作,直接移動到下一個 moveToNextAction(); } // ============================================================================= // 結果處理 // ============================================================================= void ProcedureEngine::processActionResults(const QString &actionId, const QVariantMap &results) { // 獲取當前動作定義 const ActivityStep &step = m_config.activitySequence[m_context.currentActivityIndex]; if (step.type != ActivityType::TEST_TASK_GROUP) { return; } if (!m_config.testTaskGroups.contains(step.ref)) { return; } const TestTaskGroup &taskGroup = m_config.testTaskGroups[step.ref]; if (m_context.currentStageIndex < 0 || m_context.currentStageIndex >= taskGroup.stages.size()) { return; } const TestActivityGroup &stage = taskGroup.stages[m_context.currentStageIndex]; if (m_context.currentActionIndex < 0 || m_context.currentActionIndex >= stage.actions.size()) { return; } const TestAction &action = stage.actions[m_context.currentActionIndex]; // 根據輸出映射寫入表格 for (auto it = action.outputs.begin(); it != action.outputs.end(); ++it) { const QString &outputKey = it.key(); const FieldSelector &selector = it.value(); if (results.contains(outputKey)) { QVariant value = results[outputKey]; setTableCellValue(selector.tableRef, selector.row, selector.column, value); } } } void ProcedureEngine::displayResult(const QString &displayRef) { if (!m_config.resultDisplays.contains(displayRef)) { emit errorOccurred(QString("找不到結果顯示: %1").arg(displayRef)); return; } const ResultDisplay &display = m_config.resultDisplays[displayRef]; qDebug() << "顯示結果:" << display.name; emit resultDisplayRequested(displayRef, display); } void ProcedureEngine::completeProcedure() { qDebug() << "程序執行完成"; setStatus(ProcedureStatus::Completed); emit procedureCompleted(); } // ============================================================================= // 表格數據管理 // ============================================================================= void ProcedureEngine::initializeTable(const QString &tableRef) { if (!m_config.tables.contains(tableRef)) { qWarning() << "找不到表格定義:" << tableRef; return; } const TableDefinition &tableDef = m_config.tables[tableRef]; // 初始化表格數據 QVector> data; int rowCount = tableDef.rowCount > 0 ? tableDef.rowCount : 10; int colCount = tableDef.fields.size() > 0 ? tableDef.fields.size() : tableDef.columnCount; for (int row = 0; row < rowCount; row++) { QVector rowData; for (int col = 0; col < colCount; col++) { if (col < tableDef.fields.size()) { rowData.append(tableDef.fields[col].defaultValue); } else { rowData.append(QVariant()); } } data.append(rowData); } // 應用靜態單元格 for (const StaticCell &cell : tableDef.staticCells) { if (cell.row < data.size() && cell.column < data[cell.row].size()) { data[cell.row][cell.column] = cell.value; } } m_tableData[tableRef] = data; emit tableInitialized(tableRef, tableDef); } QVariant ProcedureEngine::getTableCellValue(const QString &tableRef, int row, int column) const { if (!m_tableData.contains(tableRef)) { return QVariant(); } const auto &data = m_tableData[tableRef]; if (row < 0 || row >= data.size()) { return QVariant(); } if (column < 0 || column >= data[row].size()) { return QVariant(); } return data[row][column]; } void ProcedureEngine::setTableCellValue(const QString &tableRef, int row, int column, const QVariant &value) { if (!m_tableData.contains(tableRef)) { return; } auto &data = m_tableData[tableRef]; if (row < 0 || row >= data.size()) { return; } // 自動擴展列 while (column >= data[row].size()) { data[row].append(QVariant()); } data[row][column] = value; emit tableDataChanged(tableRef, row, column, value); } QVector> ProcedureEngine::getTableData(const QString &tableRef) const { if (m_tableData.contains(tableRef)) { return m_tableData[tableRef]; } return QVector>(); } // ============================================================================= // 條件評估 // ============================================================================= bool ProcedureEngine::evaluateCondition(const QString &condition) { // 簡單的條件評估 // TODO: 實現完整的表達式解析器 if (condition.isEmpty() || condition == "true") { return true; } if (condition == "false") { return false; } // 支持簡單的表格引用條件 // 格式: table[row][col] == value static QRegularExpression tableRefRe(R"((\w+)\[(\d+)\]\[(\d+)\]\s*(==|!=|>|<|>=|<=)\s*(.+))"); QRegularExpressionMatch match = tableRefRe.match(condition); if (match.hasMatch()) { QString tableRef = match.captured(1); int row = match.captured(2).toInt(); int col = match.captured(3).toInt(); QString op = match.captured(4); QString valueStr = match.captured(5).trimmed(); QVariant cellValue = getTableCellValue(tableRef, row, col); QVariant compareValue = valueStr; // 簡單比較 if (op == "==") { return cellValue == compareValue; } else if (op == "!=") { return cellValue != compareValue; } else if (op == ">") { return cellValue.toDouble() > compareValue.toDouble(); } else if (op == "<") { return cellValue.toDouble() < compareValue.toDouble(); } else if (op == ">=") { return cellValue.toDouble() >= compareValue.toDouble(); } else if (op == "<=") { return cellValue.toDouble() <= compareValue.toDouble(); } } qWarning() << "無法評估條件:" << condition; return false; } // ============================================================================= // 狀態查詢 // ============================================================================= void ProcedureEngine::setStatus(ProcedureStatus status) { if (m_status != status) { m_status = status; emit statusChanged(status); } } ProcedureStatus ProcedureEngine::status() const { return m_status; } ProcedureConfig ProcedureEngine::config() const { return m_config; } ExecutionContext ProcedureEngine::executionContext() const { return m_context; } ActivityStep ProcedureEngine::getCurrentActivity() const { if (m_context.currentActivityIndex >= 0 && m_context.currentActivityIndex < m_config.activitySequence.size()) { return m_config.activitySequence[m_context.currentActivityIndex]; } return ActivityStep(); } TestTaskGroup ProcedureEngine::getCurrentTaskGroup() const { ActivityStep step = getCurrentActivity(); if (step.type == ActivityType::TEST_TASK_GROUP && m_config.testTaskGroups.contains(step.ref)) { return m_config.testTaskGroups[step.ref]; } return TestTaskGroup(); } TestActivityGroup ProcedureEngine::getCurrentStage() const { TestTaskGroup taskGroup = getCurrentTaskGroup(); if (m_context.currentStageIndex >= 0 && m_context.currentStageIndex < taskGroup.stages.size()) { return taskGroup.stages[m_context.currentStageIndex]; } return TestActivityGroup(); } TestAction ProcedureEngine::getCurrentAction() const { TestActivityGroup stage = getCurrentStage(); if (m_context.currentActionIndex >= 0 && m_context.currentActionIndex < stage.actions.size()) { return stage.actions[m_context.currentActionIndex]; } return TestAction(); } int ProcedureEngine::getActivityCount() const { return m_config.activitySequence.size(); } int ProcedureEngine::getCurrentActivityIndex() const { return m_context.currentActivityIndex; } double ProcedureEngine::getProgress() const { if (m_config.activitySequence.isEmpty()) { return 0.0; } // 基於活動數量計算簡單進度 double activityProgress = static_cast(m_context.currentActivityIndex) / m_config.activitySequence.size(); // 可以進一步細化到階段和動作級別 // TODO: 更精確的進度計算 return qBound(0.0, activityProgress * 100.0, 100.0); }