#include "stdafx.h" #include "ProductionLogManager.h" #include #include #include #include #include const std::string PRODUCTION_DB_FILE = R"(ProductionLog.db)"; std::mutex ProductionLogManager::m_mutex; ProductionLogManager& ProductionLogManager::getInstance() { static ProductionLogManager instance; return instance; } ProductionLogManager::ProductionLogManager() { m_pDB = new BL::SQLiteDatabase(); } ProductionLogManager::~ProductionLogManager() { if (m_pDB) { delete m_pDB; m_pDB = nullptr; } } bool ProductionLogManager::initProductionTable() { char path[MAX_PATH]; GetModuleFileName(NULL, path, MAX_PATH); std::string exePath(path); std::string dbFileDir = exePath.substr(0, exePath.find_last_of("\\/")) + "\\DB"; if (!CreateDirectory(dbFileDir.c_str(), NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { throw std::runtime_error("Failed to create DB directory."); } std::string dbFilePath = dbFileDir + "\\" + PRODUCTION_DB_FILE; if (!m_pDB->connect(dbFilePath, true)) { throw std::runtime_error("Failed to connect to production database."); } const std::string createTableQuery = R"( CREATE TABLE IF NOT EXISTS production_log ( step_id INTEGER PRIMARY KEY AUTOINCREMENT, product_id TEXT NOT NULL, batch_no TEXT NOT NULL, device_id INTEGER NOT NULL, prev_device_id INTEGER, next_device_id INTEGER, operator_name TEXT, start_time DATETIME, end_time DATETIME, yield INTEGER, good_count INTEGER, bad_count INTEGER, status TEXT, note TEXT ) )"; return m_pDB->executeQuery(createTableQuery); } void ProductionLogManager::termProductionTable() { if (m_pDB) { m_pDB->disconnect(); } } bool ProductionLogManager::destroyProductionTable() { if (!m_pDB) return false; const std::string query = "DROP TABLE IF EXISTS production_log"; return m_pDB->executeQuery(query); } void ProductionLogManager::insertMockData() { // TODO: ʵÏÖÄ£ÄâÊý¾Ý²åÈëÂß¼­£¨Ê¹Óà std::ostringstream£© ProductionStep step; step.strProductId = "P888"; step.strBatchNo = "B999"; step.nDeviceId = 3; step.nPrevDeviceId = 2; step.nNextDeviceId = 4; step.strOperator = "MockUser"; step.strStartTime = "2025-04-02 10:00:00"; step.strEndTime = "2025-04-02 10:20:00"; step.nYield = 100; step.nGoodCount = 98; step.nBadCount = 2; step.strStatus = "²âÊÔ"; step.strNote = "ÕâÊÇÄ£ÄâÂÄÀú"; int id = 0; addProductionStep(id, step); } bool ProductionLogManager::addProductionStep(int stepId, const ProductionStep& stepData) { std::ostringstream query; query << "INSERT INTO production_log (product_id, batch_no, device_id, prev_device_id, next_device_id, operator_name, start_time, end_time, yield, good_count, bad_count, status, note) " << "VALUES ('" << stepData.strProductId << "', '" << stepData.strBatchNo << "', " << stepData.nDeviceId << ", " << stepData.nPrevDeviceId << ", " << stepData.nNextDeviceId << ", '" << stepData.strOperator << "', '" << stepData.strStartTime << "', '" << stepData.strEndTime << "', " << stepData.nYield << ", " << stepData.nGoodCount << ", " << stepData.nBadCount << ", '" << stepData.strStatus << "', '" << stepData.strNote << "') RETURNING step_id;"; std::lock_guard lock(m_mutex); auto results = m_pDB->fetchResults(query.str()); if (!results.empty() && !results[0].empty()) { try { stepId = std::stoi(results[0][0]); m_mapStepCache[stepId] = stepData; return true; } catch (...) { return false; } } return false; } std::vector ProductionLogManager::getAllSteps() { const std::string query = R"( SELECT step_id, product_id, batch_no, device_id, prev_device_id, next_device_id, operator_name, start_time, end_time, yield, good_count, bad_count, status, note FROM production_log )"; auto results = m_pDB->fetchResults(query); std::vector steps; for (const auto& row : results) { ProductionStep step; step.nStepId = std::stoi(row[0]); step.strProductId = row[1]; step.strBatchNo = row[2]; step.nDeviceId = std::stoi(row[3]); step.nPrevDeviceId = std::stoi(row[4]); step.nNextDeviceId = std::stoi(row[5]); step.strOperator = row[6]; step.strStartTime = row[7]; step.strEndTime = row[8]; step.nYield = std::stoi(row[9]); step.nGoodCount = std::stoi(row[10]); step.nBadCount = std::stoi(row[11]); step.strStatus = row[12]; step.strNote = row[13]; steps.push_back(step); } return steps; } std::vector ProductionLogManager::getStepsByProductId(const std::string& productId) { std::ostringstream query; query << "SELECT * FROM production_log WHERE product_id = '" << productId << "'"; auto results = m_pDB->fetchResults(query.str()); std::vector steps; for (const auto& row : results) { ProductionStep step; step.nStepId = std::stoi(row[0]); step.strProductId = row[1]; step.strBatchNo = row[2]; step.nDeviceId = std::stoi(row[3]); step.nPrevDeviceId = std::stoi(row[4]); step.nNextDeviceId = std::stoi(row[5]); step.strOperator = row[6]; step.strStartTime = row[7]; step.strEndTime = row[8]; step.nYield = std::stoi(row[9]); step.nGoodCount = std::stoi(row[10]); step.nBadCount = std::stoi(row[11]); step.strStatus = row[12]; step.strNote = row[13]; steps.push_back(step); } return steps; } std::vector ProductionLogManager::getStepsByBatchNo(const std::string& batchNo) { std::ostringstream query; query << "SELECT * FROM production_log WHERE batch_no = '" << batchNo << "'"; auto results = m_pDB->fetchResults(query.str()); std::vector steps; for (const auto& row : results) { ProductionStep step; step.nStepId = std::stoi(row[0]); step.strProductId = row[1]; step.strBatchNo = row[2]; step.nDeviceId = std::stoi(row[3]); step.nPrevDeviceId = std::stoi(row[4]); step.nNextDeviceId = std::stoi(row[5]); step.strOperator = row[6]; step.strStartTime = row[7]; step.strEndTime = row[8]; step.nYield = std::stoi(row[9]); step.nGoodCount = std::stoi(row[10]); step.nBadCount = std::stoi(row[11]); step.strStatus = row[12]; step.strNote = row[13]; steps.push_back(step); } return steps; } std::vector ProductionLogManager::getStepsByDeviceId(int nDeviceId) { std::ostringstream query; query << "SELECT * FROM production_log WHERE device_id = " << nDeviceId; auto results = m_pDB->fetchResults(query.str()); std::vector steps; for (const auto& row : results) { ProductionStep step; step.nStepId = std::stoi(row[0]); step.strProductId = row[1]; step.strBatchNo = row[2]; step.nDeviceId = std::stoi(row[3]); step.nPrevDeviceId = std::stoi(row[4]); step.nNextDeviceId = std::stoi(row[5]); step.strOperator = row[6]; step.strStartTime = row[7]; step.strEndTime = row[8]; step.nYield = std::stoi(row[9]); step.nGoodCount = std::stoi(row[10]); step.nBadCount = std::stoi(row[11]); step.strStatus = row[12]; step.strNote = row[13]; steps.push_back(step); } return steps; } std::vector ProductionLogManager::getStepsByTimeRange(const std::string& startTime, const std::string& endTime) { std::ostringstream query; query << "SELECT * FROM production_log WHERE start_time >= '" << startTime << "' AND end_time <= '" << endTime << "'"; auto results = m_pDB->fetchResults(query.str()); std::vector steps; for (const auto& row : results) { ProductionStep step; step.nStepId = std::stoi(row[0]); step.strProductId = row[1]; step.strBatchNo = row[2]; step.nDeviceId = std::stoi(row[3]); step.nPrevDeviceId = std::stoi(row[4]); step.nNextDeviceId = std::stoi(row[5]); step.strOperator = row[6]; step.strStartTime = row[7]; step.strEndTime = row[8]; step.nYield = std::stoi(row[9]); step.nGoodCount = std::stoi(row[10]); step.nBadCount = std::stoi(row[11]); step.strStatus = row[12]; step.strNote = row[13]; steps.push_back(step); } return steps; } std::vector ProductionLogManager::getFilteredSteps( const std::string& productId, const std::string& batchNo, const std::string& deviceId, const std::string& operatorName, const std::string& status, const std::string& startTime, const std::string& endTime, int pageNumber, int pageSize) { std::ostringstream query; query << "SELECT * FROM production_log WHERE 1=1"; if (!productId.empty()) { query << " AND product_id LIKE '%" << productId << "%'"; } if (!batchNo.empty()) { query << " AND batch_no LIKE '%" << batchNo << "%'"; } if (!deviceId.empty()) { query << " AND device_id = " << deviceId; } if (!operatorName.empty()) { query << " AND operator_name LIKE '%" << operatorName << "%'"; } if (!status.empty()) { query << " AND status LIKE '%" << status << "%'"; } if (!startTime.empty()) { query << " AND start_time >= '" << startTime << "'"; } if (!endTime.empty()) { query << " AND end_time <= '" << endTime << "'"; } int offset = (pageNumber - 1) * pageSize; query << " ORDER BY start_time DESC LIMIT " << pageSize << " OFFSET " << offset; auto results = m_pDB->fetchResults(query.str()); std::vector steps; for (const auto& row : results) { ProductionStep step; step.nStepId = std::stoi(row[0]); step.strProductId = row[1]; step.strBatchNo = row[2]; step.nDeviceId = std::stoi(row[3]); step.nPrevDeviceId = std::stoi(row[4]); step.nNextDeviceId = std::stoi(row[5]); step.strOperator = row[6]; step.strStartTime = row[7]; step.strEndTime = row[8]; step.nYield = std::stoi(row[9]); step.nGoodCount = std::stoi(row[10]); step.nBadCount = std::stoi(row[11]); step.strStatus = row[12]; step.strNote = row[13]; steps.push_back(step); } return steps; } int ProductionLogManager::getTotalStepCount( const std::string& productId, const std::string& batchNo, const std::string& deviceId, const std::string& operatorName, const std::string& status, const std::string& startTime, const std::string& endTime) { std::ostringstream query; query << "SELECT COUNT(*) FROM production_log WHERE 1=1"; if (!productId.empty()) { query << " AND product_id LIKE '%" << productId << "%'"; } if (!batchNo.empty()) { query << " AND batch_no LIKE '%" << batchNo << "%'"; } if (!deviceId.empty()) { query << " AND device_id = " << deviceId; } if (!operatorName.empty()) { query << " AND operator_name LIKE '%" << operatorName << "%'"; } if (!status.empty()) { query << " AND status LIKE '%" << status << "%'"; } if (!startTime.empty()) { query << " AND start_time >= '" << startTime << "'"; } if (!endTime.empty()) { query << " AND end_time <= '" << endTime << "'"; } auto results = m_pDB->fetchResults(query.str()); if (!results.empty() && !results[0].empty()) { return std::stoi(results[0][0]); } return 0; } bool ProductionLogManager::updateStepEndTime(int nStepId, const std::string& newEndTime) { std::ostringstream query; query << "UPDATE production_log SET end_time = '" << newEndTime << "' WHERE step_id = " << nStepId; return m_pDB->executeQuery(query.str()); } bool ProductionLogManager::saveProductionFile(const std::string& filename) { std::ofstream file(filename); if (!file.is_open()) return false; file << "StepID,ProductID,BatchNo,DeviceID,PrevDeviceID,NextDeviceID,Operator,StartTime,EndTime,Yield,Good,Bad,Status,Note\n"; for (auto it = m_mapStepCache.begin(); it != m_mapStepCache.end(); ++it) { const int id = it->first; const ProductionStep& step = it->second; file << id << "," << step.strProductId << "," << step.strBatchNo << "," << step.nDeviceId << "," << step.nPrevDeviceId << "," << step.nNextDeviceId << "," << step.strOperator << "," << step.strStartTime << "," << step.strEndTime << "," << step.nYield << "," << step.nGoodCount << "," << step.nBadCount << "," << step.strStatus << "," << step.strNote << "\n"; } file.close(); return true; } bool ProductionLogManager::readProductionFile(const std::string& filename) { std::ifstream file(filename); if (!file.is_open()) return false; std::string line; bool first = true; while (std::getline(file, line)) { if (first) { first = false; continue; } std::stringstream ss(line); std::string cell; ProductionStep step; std::getline(ss, cell, ','); step.nStepId = std::stoi(cell); std::getline(ss, step.strProductId, ','); std::getline(ss, step.strBatchNo, ','); std::getline(ss, cell, ','); step.nDeviceId = std::stoi(cell); std::getline(ss, cell, ','); step.nPrevDeviceId = std::stoi(cell); std::getline(ss, cell, ','); step.nNextDeviceId = std::stoi(cell); std::getline(ss, step.strOperator, ','); std::getline(ss, step.strStartTime, ','); std::getline(ss, step.strEndTime, ','); std::getline(ss, cell, ','); step.nYield = std::stoi(cell); std::getline(ss, cell, ','); step.nGoodCount = std::stoi(cell); std::getline(ss, cell, ','); step.nBadCount = std::stoi(cell); std::getline(ss, step.strStatus, ','); std::getline(ss, step.strNote); m_mapStepCache[step.nStepId] = step; } return true; }