#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;
|
}
|
}
|
|
// ±¾µØ±àÂëתΪ 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(int nCount /*=10000*/) {
|
if (nullptr != m_pDB) {
|
static const char* STATUS_STR[] = {
|
"Unknown", "Ready", "Running", "Picking", "Placing",
|
"Restoring", "Error", "Abort", "Completed"
|
};
|
|
auto formatTime = [](const std::tm& time) {
|
char szTime[64];
|
strftime(szTime, sizeof(szTime), "%Y-%m-%d %H:%M:%S", &time);
|
return std::string(szTime);
|
};
|
|
std::time_t startTime = std::time(nullptr);
|
for (int i = 0; i < nCount; ++i) {
|
TransferData data;
|
data.strClassID = "T-" + std::to_string(1000 + i);
|
data.strStatus = STATUS_STR[i % 9];
|
|
std::time_t baseTime = startTime + i * 60;
|
std::time_t pickTime = baseTime + 60;
|
std::time_t placeTime = pickTime + 60;
|
std::time_t endTime = placeTime + 60;
|
|
std::tm tmCreate = {}, tmPick = {}, tmPlace = {}, tmEnd = {};
|
localtime_s(&tmCreate, &baseTime);
|
localtime_s(&tmPick, &pickTime);
|
localtime_s(&tmPlace, &placeTime);
|
localtime_s(&tmEnd, &endTime);
|
|
data.strCreateTime = formatTime(tmCreate);
|
data.strPickTime = formatTime(tmPick);
|
data.strPlaceTime = formatTime(tmPlace);
|
data.strEndTime = formatTime(tmEnd);
|
data.strDescription = "Mock transfer task " + std::to_string(i);
|
|
int nRecordId = 0;
|
if (!addTransferRecord(data, nRecordId)) {
|
std::cerr << "[Error] ²åÈëµÚ " << i << " Ìõ¼Ç¼ʧ°Ü" << std::endl;
|
}
|
}
|
|
std::cout << "[Mock] ³É¹¦²åÈë " << nCount << " Ìõ²âÊÔ°áÔ˼Ǽ¡£" << 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 = utf8ToAnsi(row[1]);
|
data.strStatus = utf8ToAnsi(row[2]);
|
data.strCreateTime = row[3];
|
data.strPickTime = row[4];
|
data.strPlaceTime = row[5];
|
data.strEndTime = row[6];
|
data.strDescription = utf8ToAnsi(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 = utf8ToAnsi(results[0][1]);
|
data.strStatus = utf8ToAnsi(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 = utf8ToAnsi(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 = utf8ToAnsi(row[1]);
|
data.strStatus = utf8ToAnsi(row[2]);
|
data.strCreateTime = row[3];
|
data.strPickTime = row[4];
|
data.strPlaceTime = row[5];
|
data.strEndTime = row[6];
|
data.strDescription = utf8ToAnsi(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 = '" << ansiToUtf8(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 = utf8ToAnsi(row[1]);
|
data.strStatus = utf8ToAnsi(row[2]);
|
data.strCreateTime = row[3];
|
data.strPickTime = row[4];
|
data.strPlaceTime = row[5];
|
data.strEndTime = row[6];
|
data.strDescription = utf8ToAnsi(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::getTotalTransferCountAll() {
|
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::getFilteredTransferCount(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 = '" << ansiToUtf8(filter.strStatus) << "'";
|
}
|
|
// ÃèÊö¹Ø¼ü×ÖÄ£ºýÆ¥Åä
|
if (!filter.strDescription.empty()) {
|
oss << " AND description LIKE '%" << ansiToUtf8(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 = '" << ansiToUtf8(filter.strStatus) << "'";
|
}
|
if (!filter.strDescription.empty()) {
|
oss << " AND description LIKE '%" << ansiToUtf8(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 = utf8ToAnsi(row[1]);
|
data.strStatus = utf8ToAnsi(row[2]);
|
data.strCreateTime = row[3];
|
data.strPickTime = row[4];
|
data.strPlaceTime = row[5];
|
data.strEndTime = row[6];
|
data.strDescription = utf8ToAnsi(row[7]);
|
|
records.push_back(data);
|
}
|
|
return records;
|
}
|
|
// ÇåÀíÔçÓÚijһʱ¼äµÄ°áÔ˼Ǽ
|
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;
|
}
|