| | |
| | | #include "stdafx.h" |
| | | #include "stdafx.h" |
| | | #include "RecipeManager.h" |
| | | #include <sstream> |
| | | #include <iomanip> |
| | |
| | | return false; |
| | | } |
| | | |
| | | // 启用 SQLite 的外键约束支持 |
| | | // 启用 SQLite 的外键约束支持 |
| | | if (!m_pDB->executeQuery("PRAGMA foreign_keys = ON;")) { |
| | | std::cerr << "Failed to enable foreign keys." << std::endl; |
| | | return false; |
| | |
| | | |
| | | const std::string createRecipeTable = R"( |
| | | CREATE TABLE IF NOT EXISTS recipes ( |
| | | ppid TEXT PRIMARY KEY NOT NULL, |
| | | id INTEGER PRIMARY KEY AUTOINCREMENT, |
| | | ppid TEXT NOT NULL UNIQUE, |
| | | description TEXT, |
| | | create_time TEXT DEFAULT (datetime('now', 'localtime')) |
| | | ); |
| | |
| | | device_id INTEGER NOT NULL, |
| | | device_name TEXT NOT NULL, |
| | | recipe_id INTEGER NOT NULL, |
| | | recipe_name TEXT NOT NULL, |
| | | FOREIGN KEY(ppid) REFERENCES recipes(ppid) ON DELETE CASCADE ON UPDATE CASCADE, |
| | | UNIQUE (ppid, device_id), |
| | | UNIQUE (ppid, device_name) |
| | |
| | | |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | |
| | | // 开始事务 |
| | | // 开始事务 |
| | | m_pDB->executeQuery("BEGIN TRANSACTION;"); |
| | | |
| | | std::ostringstream oss; |
| | |
| | | |
| | | for (const auto& device : recipe.vecDeviceList) { |
| | | std::ostringstream devSql; |
| | | devSql << "INSERT OR REPLACE INTO recipe_devices (ppid, device_id, device_name, recipe_id) VALUES ('" |
| | | devSql << "INSERT OR REPLACE INTO recipe_devices (ppid, device_id, device_name, recipe_id, recipe_name) VALUES ('" |
| | | << recipe.strPPID << "', " |
| | | << device.nDeviceID << ", '" |
| | | << device.strDeviceName << "', " |
| | | << device.nRecipeID << ");"; |
| | | << device.nRecipeID << ", '" |
| | | << device.strRecipeName << "');"; |
| | | |
| | | |
| | | if (!m_pDB->executeQuery(devSql.str())) { |
| | | std::cerr << "[AddRecipe] Failed to insert device mapping: " << device.nDeviceID << std::endl; |
| | |
| | | } |
| | | } |
| | | |
| | | // 提交事务 |
| | | // 提交事务 |
| | | m_pDB->executeQuery("COMMIT;"); |
| | | return true; |
| | | } |
| | |
| | | return false; |
| | | } |
| | | |
| | | // 检查 ppid 是否存在 |
| | | // 检查 ppid 是否存在 |
| | | if (!ppidExists(ppid)) { |
| | | std::cerr << "[addRecipeDevice] PPID does not exist: " << ppid << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | // 插入设备记录 |
| | | // 插入设备记录 |
| | | std::ostringstream oss; |
| | | oss << "INSERT OR REPLACE INTO recipe_devices (ppid, device_id, device_name, recipe_id) VALUES ('" |
| | | oss << "INSERT OR REPLACE INTO recipe_devices (ppid, device_id, device_name, recipe_id, recipe_name) VALUES ('" |
| | | << ppid << "', " |
| | | << device.nDeviceID << ", '" |
| | | << device.strDeviceName << "', " |
| | | << device.nRecipeID << ");"; |
| | | << device.nRecipeID << ", '" |
| | | << device.strRecipeName << "');"; |
| | | |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | return m_pDB->executeQuery(oss.str()); |
| | |
| | | info.strCreateTime = row[2]; |
| | | |
| | | std::ostringstream devQuery; |
| | | devQuery << "SELECT device_id, device_name, recipe_id FROM recipe_devices WHERE ppid = '" << info.strPPID << "';"; |
| | | devQuery << "SELECT device_id, device_name, recipe_id, recipe_name FROM recipe_devices WHERE ppid = '" << info.strPPID << "'ORDER BY id ASC;"; |
| | | auto devs = m_pDB->fetchResults(devQuery.str()); |
| | | |
| | | for (const auto& dev : devs) { |
| | |
| | | dr.nDeviceID = std::stoi(dev[0]); |
| | | dr.strDeviceName = dev[1]; |
| | | dr.nRecipeID = std::stoi(dev[2]); |
| | | dr.strRecipeName = dev[3]; |
| | | } |
| | | catch (...) { |
| | | std::cerr << "Invalid data in recipe_devices for PPID: " << info.strPPID << std::endl; |
| | |
| | | return vecPPID; |
| | | } |
| | | |
| | | std::string RecipeManager::getPPIDById(int nId) { |
| | | if (!m_pDB) { |
| | | return {}; |
| | | } |
| | | |
| | | std::ostringstream query; |
| | | query << "SELECT ppid FROM recipes WHERE id = " << nId << ";"; |
| | | |
| | | auto rows = m_pDB->fetchResults(query.str()); |
| | | if (rows.empty() || rows[0].empty()) { |
| | | return {}; |
| | | } |
| | | |
| | | return rows[0][0]; |
| | | } |
| | | |
| | | int RecipeManager::getIdByPPID(const std::string& ppid) { |
| | | if (!m_pDB) { |
| | | return -1; |
| | | } |
| | | |
| | | std::ostringstream query; |
| | | query << "SELECT id FROM recipes WHERE ppid = '" << ppid << "';"; |
| | | |
| | | auto rows = m_pDB->fetchResults(query.str()); |
| | | if (rows.empty() || rows[0].empty()) { |
| | | return -1; |
| | | } |
| | | |
| | | try { |
| | | return std::stoi(rows[0][0]); |
| | | } |
| | | catch (...) { |
| | | std::cerr << "Invalid id value for PPID: " << ppid << std::endl; |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | RecipeInfo RecipeManager::getRecipeByPPID(const std::string& ppid) { |
| | | RecipeInfo info; |
| | | auto rows = m_pDB->fetchResults("SELECT ppid, description, create_time FROM recipes WHERE ppid = '" + ppid + "';"); |
| | |
| | | info.strDescription = rows[0][1]; |
| | | info.strCreateTime = rows[0][2]; |
| | | |
| | | auto devs = m_pDB->fetchResults("SELECT device_id, device_name, recipe_id FROM recipe_devices WHERE ppid = '" + ppid + "';"); |
| | | auto devs = m_pDB->fetchResults("SELECT device_id, device_name, recipe_id, recipe_name FROM recipe_devices WHERE ppid = '" + ppid + "';"); |
| | | for (const auto& dev : devs) { |
| | | DeviceRecipe dr; |
| | | try { |
| | | dr.nDeviceID = std::stoi(dev[0]); |
| | | dr.strDeviceName = dev[1]; |
| | | dr.nRecipeID = std::stoi(dev[2]); |
| | | dr.strRecipeName = dev[3]; |
| | | } |
| | | catch (...) { |
| | | std::cerr << "Invalid data in recipe_devices for PPID: " << ppid << std::endl; |
| | |
| | | |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | |
| | | // 检查是否已经存在相同的 newPPID |
| | | // 检查是否已经存在相同的 newPPID |
| | | auto check = m_pDB->fetchResults("SELECT COUNT(*) FROM recipes WHERE ppid = '" + newPPID + "';"); |
| | | if (!check.empty() && !check[0].empty() && check[0][0] != "0") { |
| | | std::cerr << "[updatePPID] New PPID already exists: " << newPPID << std::endl; |
| | |
| | | return m_pDB->executeQuery(query.str()); |
| | | } |
| | | |
| | | bool RecipeManager::addDeviceRecipe(const std::string& strDeviceName, int nID, const std::string& strName, const std::string& strPara) { |
| | | if (!m_pDB || strDeviceName.empty() || nID <= 0 || strName.empty() || strPara.empty()) { |
| | | return false; |
| | | } |
| | | |
| | | std::ostringstream sql; |
| | | sql << "CREATE TABLE IF NOT EXISTS " << strDeviceName << "_Recipes (" |
| | | << "recipe_id INTEGER PRIMARY KEY," |
| | | << "recipe_name TEXT NOT NULL," |
| | | << "recipe_para TEXT NOT NULL" |
| | | << ");"; |
| | | m_pDB->executeQuery(sql.str()); |
| | | |
| | | std::ostringstream ins; |
| | | ins << "INSERT OR REPLACE INTO " << strDeviceName |
| | | << "_Recipes (recipe_id, recipe_name, recipe_para) VALUES (" |
| | | << nID << ", '" << strName << "', '" << strPara << "');"; |
| | | |
| | | std::lock_guard<std::recursive_mutex> lk(m_mutex); |
| | | return m_pDB->executeQuery(ins.str()); |
| | | } |
| | | |
| | | bool RecipeManager::updateDeviceRecipeName(const std::string& strDeviceName, int nID, const std::string& strNewName) { |
| | | if (!m_pDB || strDeviceName.empty() || nID <= 0 || strNewName.empty()) { |
| | | return false; |
| | | } |
| | | |
| | | std::ostringstream sql; |
| | | sql << "UPDATE " << strDeviceName << "_Recipes SET recipe_name='" << strNewName |
| | | << "' WHERE recipe_id=" << nID << ";"; |
| | | |
| | | std::lock_guard<std::recursive_mutex> lk(m_mutex); |
| | | return m_pDB->executeQuery(sql.str()); |
| | | } |
| | | |
| | | bool RecipeManager::updateDeviceRecipePara(const std::string& strDeviceName, int nID, const std::string& strNewPara) { |
| | | if (!m_pDB || strDeviceName.empty() || nID <= 0) { |
| | | return false; |
| | | } |
| | | |
| | | std::ostringstream sql; |
| | | sql << "UPDATE " << strDeviceName << "_Recipes SET recipe_para='" << strNewPara |
| | | << "' WHERE recipe_id=" << nID << ";"; |
| | | |
| | | std::lock_guard<std::recursive_mutex> lk(m_mutex); |
| | | return m_pDB->executeQuery(sql.str()); |
| | | } |
| | | |
| | | std::string RecipeManager::getDeviceRecipeName(const std::string& strDeviceName, int nID) { |
| | | if (!m_pDB || strDeviceName.empty() || nID <= 0) { |
| | | return ""; |
| | | } |
| | | |
| | | std::ostringstream sql; |
| | | sql << "SELECT recipe_name FROM " << strDeviceName << "_Recipes " |
| | | << "WHERE recipe_id=" << nID << " LIMIT 1;"; |
| | | |
| | | auto rows = m_pDB->fetchResults(sql.str()); |
| | | if (!rows.empty() && !rows[0].empty()) { |
| | | return rows[0][0]; |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | std::string RecipeManager::getDeviceRecipePara(const std::string& strDeviceName, int nID) { |
| | | if (!m_pDB || strDeviceName.empty() || nID <= 0) { |
| | | return ""; |
| | | } |
| | | |
| | | std::ostringstream sql; |
| | | sql << "SELECT recipe_para FROM " << strDeviceName << "_Recipes " |
| | | << "WHERE recipe_id=" << nID << " LIMIT 1;"; |
| | | |
| | | auto rows = m_pDB->fetchResults(sql.str()); |
| | | if (!rows.empty() && !rows[0].empty()) { |
| | | return rows[0][0]; |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | bool RecipeManager::deleteDeviceRecipe(const std::string& strDeviceName, int nID) { |
| | | if (!m_pDB || strDeviceName.empty() || nID <= 0) { |
| | | return false; |
| | | } |
| | | |
| | | std::ostringstream sql; |
| | | sql << "DELETE FROM " << strDeviceName << "_Recipes WHERE recipe_id=" << nID << ";"; |
| | | |
| | | std::lock_guard<std::recursive_mutex> lk(m_mutex); |
| | | return m_pDB->executeQuery(sql.str()); |
| | | } |
| | | |
| | | std::vector<std::pair<int, std::string>> RecipeManager::getDeviceRecipes(const std::string& strDeviceName) { |
| | | std::vector<std::pair<int, std::string>> out; |
| | | if (!m_pDB || strDeviceName.empty()) { |
| | | return out; |
| | | } |
| | | |
| | | std::ostringstream sql; |
| | | sql << "SELECT recipe_id, recipe_name FROM " << strDeviceName << "_Recipes ORDER BY recipe_id;"; |
| | | |
| | | auto rows = m_pDB->fetchResults(sql.str()); |
| | | for (const auto& r : rows) { |
| | | if (r.size() < 2) continue; |
| | | try { |
| | | int id = std::stoi(r[0]); |
| | | out.emplace_back(id, r[1]); |
| | | } |
| | | catch (...) {} |
| | | } |
| | | return out; |
| | | } |
| | | |
| | | void RecipeManager::insertMockData() { |
| | | if (!m_pDB) { |
| | | return; |
| | |
| | | recipe.strDescription = "Main Board Burn-in"; |
| | | |
| | | recipe.vecDeviceList = { |
| | | {1, 101, "Burner A"}, |
| | | {2, 102, "Burner B"} |
| | | {9, 101, "VacuumBake", "VacuumBake"}, |
| | | {10, 102, "Bonder1", "Bonder1"}, |
| | | {11, 103, "Bonder2", "Bonder2"} |
| | | }; |
| | | |
| | | addRecipe(recipe); |
| | | |
| | | addDeviceRecipe("Bonder1", 101, "标准工艺", ""); |
| | | addDeviceRecipe("Bonder1", 102, "改良工艺", ""); |
| | | addDeviceRecipe("Bonder1", 103, "高速模式", ""); |
| | | |
| | | addDeviceRecipe("Bonder2", 101, "标准工艺", ""); |
| | | addDeviceRecipe("Bonder2", 102, "改良工艺", ""); |
| | | addDeviceRecipe("Bonder2", 103, "高速模式", ""); |
| | | } |
| | | |
| | | bool RecipeManager::readRecipeFile(const std::string& filename) { |
| | |
| | | std::getline(ss, cell, ','); |
| | | try { dev.nRecipeID = std::stoi(cell); } |
| | | catch (...) { continue; } |
| | | std::getline(ss, dev.strRecipeName, ','); |
| | | std::getline(ss, description, ','); |
| | | std::getline(ss, createTime, ','); |
| | | |
| | |
| | | return false; |
| | | } |
| | | |
| | | file << "PPID,DeviceID,DeviceName,RecipeID,Description,CreateTime\n"; |
| | | file << "PPID,DeviceID,DeviceName,RecipeID,RecipeName,Description,CreateTime\n"; |
| | | auto recipes = getAllRecipes(); |
| | | for (const auto& recipe : recipes) { |
| | | for (const auto& dev : recipe.vecDeviceList) { |
| | |
| | | << dev.nDeviceID << "," |
| | | << dev.strDeviceName << "," |
| | | << dev.nRecipeID << "," |
| | | << dev.strRecipeName << "," |
| | | << recipe.strDescription << "," |
| | | << recipe.strCreateTime << "\n"; |
| | | } |