| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #include "stdafx.h" |
| | | #include "TransferManager.h" |
| | | #include <iostream> |
| | | #include <sstream> |
| | | #include <fstream> |
| | | #include <iomanip> |
| | | #include <ctime> |
| | | #include <stdexcept> |
| | | |
| | | // éæäºæ¥éåå§å |
| | | std::mutex TransferManager::m_mutex; |
| | | |
| | | // è·å TransferManager åä¾ |
| | | TransferManager& TransferManager::getInstance() { |
| | | static TransferManager instance; |
| | | return instance; |
| | | } |
| | | |
| | | // æé 彿° |
| | | TransferManager::TransferManager() { |
| | | m_pDB = new BL::SQLiteDatabase(); |
| | | } |
| | | |
| | | // ææå½æ° |
| | | TransferManager::~TransferManager() { |
| | | if (m_pDB) { |
| | | delete m_pDB; |
| | | m_pDB = nullptr; |
| | | } |
| | | } |
| | | |
| | | // ä»»å¡ç¶æè½¬æ¢æ int ç±»å |
| | | int TransferManager::statusToInt(TransferStatus status) { |
| | | return static_cast<int>(status); |
| | | } |
| | | |
| | | // int ç±»åè½¬æ¢æä»»å¡ç¶æ |
| | | TransferStatus TransferManager::intToStatus(int value) { |
| | | switch (value) { |
| | | case 0: return TransferStatus::Ready; |
| | | case 1: return TransferStatus::Running; |
| | | case 2: return TransferStatus::Error; |
| | | case 3: return TransferStatus::Abort; |
| | | case 4: return TransferStatus::Completed; |
| | | default: return TransferStatus::Error; |
| | | } |
| | | } |
| | | |
| | | // ä»»å¡ç¶æè½¬æ¢æå符串 |
| | | std::string TransferManager::statusToString(TransferStatus status) { |
| | | switch (status) { |
| | | case TransferStatus::Ready: return "Ready"; |
| | | case TransferStatus::Running: return "Running"; |
| | | case TransferStatus::Error: return "Error"; |
| | | case TransferStatus::Abort: return "Abort"; |
| | | case TransferStatus::Completed: return "Completed"; |
| | | default: return "Unknown"; |
| | | } |
| | | } |
| | | |
| | | // åç¬¦ä¸²è½¬æ¢æä»»å¡ç¶æ |
| | | TransferStatus TransferManager::stringToStatus(const std::string& str) { |
| | | if (str == "Ready") return TransferStatus::Ready; |
| | | if (str == "Running") return TransferStatus::Running; |
| | | if (str == "Error") return TransferStatus::Error; |
| | | if (str == "Abort") return TransferStatus::Abort; |
| | | if (str == "Completed") return TransferStatus::Completed; |
| | | return TransferStatus::Error; |
| | | } |
| | | |
| | | // æ¬å°ç¼ç 转为 UTF-8 |
| | | std::string TransferManager::ansiToUtf8(const std::string& ansiStr) { |
| | | // 1. ANSI â UTF-16 |
| | | int wideLen = MultiByteToWideChar(CP_ACP, 0, ansiStr.c_str(), -1, nullptr, 0); |
| | | std::wstring wideStr(wideLen, 0); |
| | | MultiByteToWideChar(CP_ACP, 0, ansiStr.c_str(), -1, &wideStr[0], wideLen); |
| | | |
| | | // 2. UTF-16 â UTF-8 |
| | | int utf8Len = WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), -1, nullptr, 0, nullptr, nullptr); |
| | | std::string utf8Str(utf8Len, 0); |
| | | WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), -1, &utf8Str[0], utf8Len, nullptr, nullptr); |
| | | |
| | | utf8Str.pop_back(); // 廿æåç '\0' |
| | | return utf8Str; |
| | | } |
| | | |
| | | // UTF-8 转为æ¬å°ç¼ç |
| | | std::string TransferManager::utf8ToAnsi(const std::string& utf8Str) { |
| | | // 1. UTF-8 â UTF-16 |
| | | int wideLen = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, NULL, 0); |
| | | std::wstring wideStr(wideLen, 0); |
| | | MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, &wideStr[0], wideLen); |
| | | |
| | | // 2. UTF-16 â ANSI |
| | | int ansiLen = WideCharToMultiByte(CP_ACP, 0, wideStr.c_str(), -1, NULL, 0, NULL, NULL); |
| | | std::string ansiStr(ansiLen, 0); |
| | | WideCharToMultiByte(CP_ACP, 0, wideStr.c_str(), -1, &ansiStr[0], ansiLen, NULL, NULL); |
| | | |
| | | ansiStr.pop_back(); // 廿æåç '\0' |
| | | return ansiStr; |
| | | } |
| | | |
| | | // åå§åæ¬è¿è®°å½è¡¨ |
| | | bool TransferManager::initTransferTable() { |
| | | char szPath[MAX_PATH]; |
| | | GetModuleFileName(NULL, szPath, MAX_PATH); |
| | | std::string exePath(szPath); |
| | | std::string dbDir = exePath.substr(0, exePath.find_last_of("\\/")) + "\\DB"; |
| | | |
| | | if (!CreateDirectory(dbDir.c_str(), NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { |
| | | throw std::runtime_error("åå»ºæ°æ®åºç®å½å¤±è´¥"); |
| | | } |
| | | |
| | | std::string dbPath = dbDir + "\\TransferManager.db"; |
| | | |
| | | if (!m_pDB->connect(dbPath, true)) { |
| | | throw std::runtime_error("è¿æ¥æ°æ®åºå¤±è´¥"); |
| | | } |
| | | |
| | | const std::string createTableSQL = R"( |
| | | CREATE TABLE IF NOT EXISTS transfers ( |
| | | record_id INTEGER PRIMARY KEY AUTOINCREMENT, |
| | | class_id TEXT NOT NULL, |
| | | status TEXT NOT NULL, |
| | | create_time TEXT, |
| | | pick_time TEXT, |
| | | place_time TEXT, |
| | | end_time TEXT, |
| | | description TEXT |
| | | ); |
| | | )"; |
| | | |
| | | return m_pDB->executeQuery(createTableSQL); |
| | | } |
| | | |
| | | // æå
¥æµè¯æ¬è¿è®°å½ |
| | | void TransferManager::insertTestTransferRecord() { |
| | | TransferData data; |
| | | data.strClassID = "Task-20240529-001"; |
| | | data.strStatus = "Running"; |
| | | data.strCreateTime = "2024-05-29 10:30:00"; |
| | | data.strPickTime = "2024-05-29 10:31:00"; |
| | | data.strPlaceTime = "2024-05-29 10:32:00"; |
| | | data.strEndTime = "2024-05-29 10:33:00"; |
| | | data.strDescription = "æ¬è¿å¨ä½ï¼ä» Port1 åç â Port2 æ¾ç"; |
| | | |
| | | int nRecordId = -1; |
| | | if (TransferManager::getInstance().addTransferRecord(data, nRecordId)) { |
| | | std::cout << "æå
¥æåï¼è®°å½ ID = " << nRecordId << std::endl; |
| | | } |
| | | else { |
| | | std::cerr << "æå
¥å¤±è´¥ï¼" << std::endl; |
| | | } |
| | | } |
| | | |
| | | // æå¼æ°æ®åºè¿æ¥ |
| | | void TransferManager::termTransferTable() { |
| | | if (m_pDB) { |
| | | m_pDB->disconnect(); |
| | | } |
| | | } |
| | | |
| | | // å 餿¬è¿è®°å½è¡¨ |
| | | bool TransferManager::destroyTransferTable() { |
| | | if (!m_pDB) return false; |
| | | |
| | | const std::string dropTableSQL = "DROP TABLE IF EXISTS transfers;"; |
| | | return m_pDB->executeQuery(dropTableSQL); |
| | | } |
| | | |
| | | // æå
¥æ¬è¿è®°å½ |
| | | bool TransferManager::addTransferRecord(const TransferData& data, int& outRecordId) { |
| | | if (!m_pDB) { |
| | | return false; |
| | | } |
| | | |
| | | std::ostringstream oss; |
| | | oss << "INSERT INTO transfers (class_id, status, create_time, pick_time, place_time, end_time, description) " |
| | | << "VALUES ('" |
| | | << ansiToUtf8(data.strClassID) << "', '" |
| | | << ansiToUtf8(data.strStatus) << "', '" |
| | | << data.strCreateTime << "', '" |
| | | << data.strPickTime << "', '" |
| | | << data.strPlaceTime << "', '" |
| | | << data.strEndTime << "', '" |
| | | << ansiToUtf8(data.strDescription) << "') RETURNING record_id;"; |
| | | |
| | | std::lock_guard<std::mutex> lock(m_mutex); |
| | | |
| | | auto results = m_pDB->fetchResults(oss.str()); |
| | | if (!results.empty() && !results[0].empty()) { |
| | | try { |
| | | outRecordId = std::stoi(results[0][0]); |
| | | return true; |
| | | } |
| | | catch (const std::exception& e) { |
| | | std::cerr << "è§£æ record_id åºé: " << e.what() << std::endl; |
| | | } |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | // æ¥è¯¢æææ¬è¿è®°å½ |
| | | std::vector<TransferData> TransferManager::getAllTransfers() { |
| | | std::vector<TransferData> records; |
| | | |
| | | if (!m_pDB) { |
| | | return records; |
| | | } |
| | | |
| | | const std::string query = R"( |
| | | SELECT record_id, class_id, status, create_time, pick_time, place_time, end_time, description |
| | | FROM transfers |
| | | ORDER BY record_id DESC |
| | | )"; |
| | | |
| | | auto results = m_pDB->fetchResults(query); |
| | | for (const auto& row : results) { |
| | | if (row.size() != 8) continue; |
| | | |
| | | TransferData data; |
| | | data.nRecordId = std::stoi(row[0]); |
| | | data.strClassID = row[1]; |
| | | data.strStatus = row[2]; |
| | | data.strCreateTime = row[3]; |
| | | data.strPickTime = row[4]; |
| | | data.strPlaceTime = row[5]; |
| | | data.strEndTime = row[6]; |
| | | data.strDescription = row[7]; |
| | | |
| | | records.push_back(data); |
| | | } |
| | | |
| | | return records; |
| | | } |
| | | |
| | | // æ ¹æ® ID æ¥è¯¢æ¬è¿è®°å½ |
| | | TransferData TransferManager::getTransferById(int id) { |
| | | TransferData data; |
| | | if (!m_pDB) { |
| | | return data; |
| | | } |
| | | std::ostringstream oss; |
| | | oss << "SELECT record_id, class_id, status, create_time, pick_time, place_time, end_time, description " |
| | | << "FROM transfers WHERE record_id = " << id; |
| | | auto results = m_pDB->fetchResults(oss.str()); |
| | | if (!results.empty() && results[0].size() == 8) { |
| | | data.nRecordId = std::stoi(results[0][0]); |
| | | data.strClassID = results[0][1]; |
| | | data.strStatus = results[0][2]; |
| | | data.strCreateTime = results[0][3]; |
| | | data.strPickTime = results[0][4]; |
| | | data.strPlaceTime = results[0][5]; |
| | | data.strEndTime = results[0][6]; |
| | | data.strDescription = results[0][7]; |
| | | } |
| | | return data; |
| | | } |
| | | |
| | | // æ ¹æ®æ¶é´èå´æ¥è¯¢æ¬è¿è®°å½ |
| | | std::vector<TransferData> TransferManager::getTransfersByTimeRange(const std::string& startTime, const std::string& endTime) { |
| | | std::vector<TransferData> records; |
| | | if (!m_pDB) { |
| | | return records; |
| | | } |
| | | std::ostringstream oss; |
| | | oss << "SELECT record_id, class_id, status, create_time, pick_time, place_time, end_time, description " |
| | | << "FROM transfers WHERE 1=1"; |
| | | if (!startTime.empty()) { |
| | | oss << " AND create_time >= '" << startTime << "'"; |
| | | } |
| | | if (!endTime.empty()) { |
| | | oss << " AND end_time <= '" << endTime << "'"; |
| | | } |
| | | auto results = m_pDB->fetchResults(oss.str()); |
| | | for (const auto& row : results) { |
| | | if (row.size() != 8) continue; |
| | | TransferData data; |
| | | data.nRecordId = std::stoi(row[0]); |
| | | data.strClassID = row[1]; |
| | | data.strStatus = row[2]; |
| | | data.strCreateTime = row[3]; |
| | | data.strPickTime = row[4]; |
| | | data.strPlaceTime = row[5]; |
| | | data.strEndTime = row[6]; |
| | | data.strDescription = row[7]; |
| | | records.push_back(data); |
| | | } |
| | | return records; |
| | | } |
| | | |
| | | // æ¥è¯¢æå®ç¶æçæ¬è¿è®°å½ |
| | | std::vector<TransferData> TransferManager::getTransfersByStatus(const std::string& status) { |
| | | std::vector<TransferData> records; |
| | | if (!m_pDB) { |
| | | return records; |
| | | } |
| | | |
| | | std::ostringstream oss; |
| | | oss << "SELECT record_id, class_id, status, create_time, pick_time, place_time, end_time, description " |
| | | << "FROM transfers WHERE status = '" << status << "' " |
| | | << "ORDER BY create_time DESC"; |
| | | |
| | | auto results = m_pDB->fetchResults(oss.str()); |
| | | for (const auto& row : results) { |
| | | if (row.size() != 8) continue; |
| | | |
| | | TransferData data; |
| | | data.nRecordId = std::stoi(row[0]); |
| | | data.strClassID = row[1]; |
| | | data.strStatus = row[2]; |
| | | data.strCreateTime = row[3]; |
| | | data.strPickTime = row[4]; |
| | | data.strPlaceTime = row[5]; |
| | | data.strEndTime = row[6]; |
| | | data.strDescription = row[7]; |
| | | |
| | | records.push_back(data); |
| | | } |
| | | |
| | | return records; |
| | | } |
| | | |
| | | // å页è·åæ¬è¿è®°å½ |
| | | //std::vector<TransferData> TransferManager::getTransfers(int startPosition, int count) { |
| | | // std::vector<TransferData> records; |
| | | // if (!m_pDB) { |
| | | // return records; |
| | | // } |
| | | // std::ostringstream oss; |
| | | // oss << "SELECT record_id, class_id, status, create_time, pick_time, place_time, end_time, description " |
| | | // << "FROM transfers ORDER BY create_time DESC LIMIT " << count << " OFFSET " << startPosition; |
| | | // auto results = m_pDB->fetchResults(oss.str()); |
| | | // for (const auto& row : results) { |
| | | // if (row.size() != 8) continue; |
| | | // TransferData data; |
| | | // data.nRecordId = std::stoi(row[0]); |
| | | // data.strClassID = row[1]; |
| | | // data.strStatus = row[2]; |
| | | // data.strCreateTime = row[3]; |
| | | // data.strPickTime = row[4]; |
| | | // data.strPlaceTime = row[5]; |
| | | // data.strEndTime = row[6]; |
| | | // data.strDescription = row[7]; |
| | | // records.push_back(data); |
| | | // } |
| | | // return records; |
| | | //} |
| | | |
| | | // è·åç¬¦åæ¡ä»¶çè®°å½æ»æ° |
| | | int TransferManager::getTotalTransferCount() { |
| | | if (!m_pDB) { |
| | | return 0; |
| | | } |
| | | |
| | | const std::string query = "SELECT COUNT(*) FROM transfers;"; |
| | | auto results = m_pDB->fetchResults(query); |
| | | |
| | | if (!results.empty() && !results[0].empty()) { |
| | | try { |
| | | return std::stoi(results[0][0]); |
| | | } |
| | | catch (const std::exception& e) { |
| | | std::cerr << "Error parsing total count: " << e.what() << std::endl; |
| | | } |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | // è·åç¬¦åæ¡ä»¶çè®°å½æ»æ° |
| | | int TransferManager::getTotalTransferCount(const TransferData& filter) { |
| | | if (!m_pDB) { |
| | | return 0; |
| | | } |
| | | |
| | | std::ostringstream oss; |
| | | oss << "SELECT COUNT(*) FROM transfers WHERE 1=1"; |
| | | |
| | | // ç¶æçéï¼å®å
¨å¹é
ï¼ |
| | | if (!filter.strStatus.empty()) { |
| | | oss << " AND status = '" << filter.strStatus << "'"; |
| | | } |
| | | |
| | | // æè¿°å
³é®å模ç³å¹é
|
| | | if (!filter.strDescription.empty()) { |
| | | oss << " AND description LIKE '%" << filter.strDescription << "%'"; |
| | | } |
| | | |
| | | // æ¶é´èå´çé |
| | | if (!filter.strCreateTime.empty()) { |
| | | oss << " AND create_time >= '" << filter.strCreateTime << "'"; |
| | | } |
| | | if (!filter.strEndTime.empty()) { |
| | | oss << " AND end_time <= '" << filter.strEndTime << "'"; |
| | | } |
| | | |
| | | auto results = m_pDB->fetchResults(oss.str()); |
| | | if (!results.empty() && !results[0].empty()) { |
| | | try { |
| | | return std::stoi(results[0][0]); |
| | | } |
| | | catch (const std::exception& e) { |
| | | std::cerr << "Error parsing total count: " << e.what() << std::endl; |
| | | } |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | std::vector<TransferData> TransferManager::getTransfers(const TransferData& filter, int pageNum, int pageSize) { |
| | | std::vector<TransferData> records; |
| | | |
| | | if (!m_pDB) { |
| | | return records; |
| | | } |
| | | |
| | | std::ostringstream oss; |
| | | oss << "SELECT record_id, class_id, status, create_time, pick_time, place_time, end_time, description " |
| | | << "FROM transfers WHERE 1=1"; |
| | | |
| | | // æ¡ä»¶æ¼æ¥ï¼ä¸ getTotalTransferCount ä¿æä¸è´ï¼ |
| | | if (!filter.strStatus.empty()) { |
| | | oss << " AND status = '" << filter.strStatus << "'"; |
| | | } |
| | | if (!filter.strDescription.empty()) { |
| | | oss << " AND description LIKE '%" << filter.strDescription << "%'"; |
| | | } |
| | | if (!filter.strCreateTime.empty()) { |
| | | oss << " AND create_time >= '" << filter.strCreateTime << "'"; |
| | | } |
| | | if (!filter.strEndTime.empty()) { |
| | | oss << " AND end_time <= '" << filter.strEndTime << "'"; |
| | | } |
| | | |
| | | // å页æ§å¶ |
| | | int offset = (pageNum - 1) * pageSize; |
| | | oss << " ORDER BY create_time DESC"; |
| | | oss << " LIMIT " << pageSize << " OFFSET " << offset; |
| | | |
| | | // æ¥è¯¢ |
| | | auto results = m_pDB->fetchResults(oss.str()); |
| | | for (const auto& row : results) { |
| | | if (row.size() != 8) continue; |
| | | |
| | | TransferData data; |
| | | data.nRecordId = std::stoi(row[0]); |
| | | data.strClassID = row[1]; |
| | | data.strStatus = row[2]; |
| | | data.strCreateTime = row[3]; |
| | | data.strPickTime = row[4]; |
| | | data.strPlaceTime = row[5]; |
| | | data.strEndTime = row[6]; |
| | | data.strDescription = row[7]; |
| | | |
| | | records.push_back(data); |
| | | } |
| | | |
| | | return records; |
| | | } |
| | | |
| | | // æ¸
çæ©äºæä¸æ¶é´çæ¬è¿è®°å½ |
| | | void TransferManager::cleanOldTransfers(int daysToKeep) { |
| | | if (!m_pDB) { |
| | | return; |
| | | } |
| | | std::ostringstream oss; |
| | | oss << "DELETE FROM transfers WHERE create_time < datetime('now', '-" << daysToKeep << " days')"; |
| | | |
| | | m_pDB->executeQuery(oss.str()); |
| | | } |
| | | |
| | | // è¯»åæ¬è¿è®°å½ CSV æä»¶ |
| | | bool TransferManager::readTransferFile(const std::string& filename) { |
| | | std::ifstream file(filename); |
| | | if (!file.is_open()) { |
| | | std::cerr << "æ æ³æå¼æä»¶: " << filename << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::string line; |
| | | bool firstLine = true; |
| | | int insertedCount = 0; |
| | | |
| | | while (std::getline(file, line)) { |
| | | if (firstLine) { |
| | | firstLine = false; |
| | | continue; |
| | | } |
| | | |
| | | std::stringstream ss(line); |
| | | std::string cell; |
| | | TransferData data; |
| | | |
| | | try { |
| | | std::getline(ss, cell, ','); |
| | | data.nRecordId = std::stoi(cell); |
| | | |
| | | std::getline(ss, data.strClassID, ','); |
| | | std::getline(ss, data.strStatus, ','); |
| | | std::getline(ss, data.strCreateTime, ','); |
| | | std::getline(ss, data.strPickTime, ','); |
| | | std::getline(ss, data.strPlaceTime, ','); |
| | | std::getline(ss, data.strEndTime, ','); |
| | | std::getline(ss, data.strDescription, ','); |
| | | |
| | | int newId = -1; |
| | | if (addTransferRecord(data, newId)) { |
| | | ++insertedCount; |
| | | } |
| | | } |
| | | catch (const std::exception& e) { |
| | | std::cerr << "读åé误è¡: " << line << "ï¼é误: " << e.what() << std::endl; |
| | | continue; |
| | | } |
| | | } |
| | | |
| | | file.close(); |
| | | std::cout << "æå导å
¥è®°å½æ°: " << insertedCount << std::endl; |
| | | return true; |
| | | } |
| | | |
| | | // ä¿åæ¬è¿è®°å½å° CSV æä»¶ |
| | | bool TransferManager::saveTransferFile(const std::string& filename) { |
| | | std::ofstream file(filename); |
| | | if (!file.is_open()) { |
| | | std::cerr << "æ æ³åå
¥æä»¶: " << filename << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | // åå
¥æ é¢ |
| | | file << "RecordID,ClassID,Status,CreateTime,PickTime,PlaceTime,EndTime,Description\n"; |
| | | |
| | | auto records = getAllTransfers(); |
| | | for (const auto& data : records) { |
| | | file << data.nRecordId << "," |
| | | << data.strClassID << "," |
| | | << data.strStatus << "," |
| | | << data.strCreateTime << "," |
| | | << data.strPickTime << "," |
| | | << data.strPlaceTime << "," |
| | | << data.strEndTime << "," |
| | | << data.strDescription << "\n"; |
| | | } |
| | | |
| | | file.close(); |
| | | std::cout << "å·²å¯¼åº " << records.size() << " æ¡è®°å½å°: " << filename << std::endl; |
| | | return true; |
| | | } |