From 958cfa6b2e1c1eec0e20edc50816ef18f10cbf09 Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期四, 29 五月 2025 15:50:34 +0800
Subject: [PATCH] 1. 修改本地模式Port设置界面 2. 添加Transfer数据库管理类
---
SourceCode/Bond/Servo/Servo.vcxproj | 2
SourceCode/Bond/Servo/PortConfigurationDlg.cpp | 28 +-
SourceCode/Bond/Servo/Servo.vcxproj.filters | 2
SourceCode/Bond/Servo/resource.h | 0
SourceCode/Bond/Servo/TransferManager.h | 171 ++++++++++++
SourceCode/Bond/Servo/Servo.cpp | 38 +-
SourceCode/Bond/Servo/Servo.rc | 0
SourceCode/Bond/Servo/TransferManager.cpp | 550 +++++++++++++++++++++++++++++++++++++++
8 files changed, 757 insertions(+), 34 deletions(-)
diff --git a/SourceCode/Bond/Servo/PortConfigurationDlg.cpp b/SourceCode/Bond/Servo/PortConfigurationDlg.cpp
index b19be21..79a1e11 100644
--- a/SourceCode/Bond/Servo/PortConfigurationDlg.cpp
+++ b/SourceCode/Bond/Servo/PortConfigurationDlg.cpp
@@ -30,7 +30,7 @@
return;
}
- const int nCols = 4;
+ const int nCols = 3;
const int nFixRows = 1;
const int nRows = 9;
@@ -87,10 +87,10 @@
void CPortConfigurationDlg::FillGrid()
{
- CStringArray recipeOptions;
- recipeOptions.Add(_T("Recipe A"));
- recipeOptions.Add(_T("Recipe B"));
- recipeOptions.Add(_T("Recipe C"));
+ //CStringArray recipeOptions;
+ //recipeOptions.Add(_T("Recipe A"));
+ //recipeOptions.Add(_T("Recipe B"));
+ //recipeOptions.Add(_T("Recipe C"));
for (int i = 1; i < 9; ++i) {
CString strIndex;
@@ -99,19 +99,19 @@
m_wndGrid.SetItemState(i, 0, GVIS_READONLY);
// EQ Recipe - ComboBox
- if (m_wndGrid.SetCellType(i, 1, RUNTIME_CLASS(CGridCellCombo))) {
- CGridCellCombo* pCell = static_cast<CGridCellCombo*>(m_wndGrid.GetCell(i, 1));
- pCell->SetOptions(recipeOptions);
- pCell->SetStyle(CBS_DROPDOWNLIST);
- }
- m_wndGrid.SetItemText(i, 1, recipeOptions[0]);
+ //if (m_wndGrid.SetCellType(i, 1, RUNTIME_CLASS(CGridCellCombo))) {
+ // CGridCellCombo* pCell = static_cast<CGridCellCombo*>(m_wndGrid.GetCell(i, 1));
+ // pCell->SetOptions(recipeOptions);
+ // pCell->SetStyle(CBS_DROPDOWNLIST);
+ //}
+ //m_wndGrid.SetItemText(i, 1, recipeOptions[0]);
// Panel ID - 鍙紪杈�
- m_wndGrid.SetItemText(i, 2, _T(""));
+ m_wndGrid.SetItemText(i, 1, _T(""));
// Checkbox
- m_wndGrid.SetCellType(i, 3, RUNTIME_CLASS(CGridCellCheck));
- CGridCellCheck* pCheck = static_cast<CGridCellCheck*>(m_wndGrid.GetCell(i, 3));
+ m_wndGrid.SetCellType(i, 2, RUNTIME_CLASS(CGridCellCheck));
+ CGridCellCheck* pCheck = static_cast<CGridCellCheck*>(m_wndGrid.GetCell(i, 2));
if (pCheck) {
pCheck->SetCheck(FALSE);
}
diff --git a/SourceCode/Bond/Servo/Servo.cpp b/SourceCode/Bond/Servo/Servo.cpp
index 3b5e1c5..18a95a1 100644
--- a/SourceCode/Bond/Servo/Servo.cpp
+++ b/SourceCode/Bond/Servo/Servo.cpp
@@ -8,7 +8,7 @@
#include "ServoGraph.h"
#include "AlarmManager.h"
#include "SECSRuntimeManager.h"
-#include "ProductionLogManager.h"
+#include "TransferManager.h"
#include "VerticalLine.h"
#include "EqsGraphWnd.h"
#include "MapPosWnd.h"
@@ -132,22 +132,6 @@
}
AlarmManager::getInstance().insertMockData();
-
- // 初始化生产履历管理器
- //try {
- // if (!ProductionLogManager::getInstance().initProductionTable()) {
- // AfxMessageBox("初始化生产履历管理器失败!");
- // return FALSE;
- // }
- //}
- //catch (const std::exception& ex) {
- // CString errorMsg;
- // errorMsg.Format(_T("初始化生产履历管理器失败:%s"), CString(ex.what()));
- // AfxMessageBox(errorMsg, MB_ICONERROR);
- // return FALSE;
- //}
-
-
// 初始化SECS运行设置管理库
try {
if (!SECSRuntimeManager::getInstance().initRuntimeSetting()) {
@@ -158,6 +142,20 @@
catch (const std::exception& ex) {
CString errorMsg;
errorMsg.Format(_T("初始化SECS运行设置失败:%s"), CString(ex.what()));
+ AfxMessageBox(errorMsg, MB_ICONERROR);
+ return FALSE;
+ }
+
+ // 初始化搬运记录管理库
+ try {
+ if (!TransferManager::getInstance().initTransferTable()) {
+ AfxMessageBox("初始化搬运记录管理库设置失败!");
+ return FALSE;
+ }
+ }
+ catch (const std::exception& ex) {
+ CString errorMsg;
+ errorMsg.Format(_T("初始化搬运记录管理库设置失败:%s"), CString(ex.what()));
AfxMessageBox(errorMsg, MB_ICONERROR);
return FALSE;
}
@@ -205,12 +203,12 @@
// 销毁报警表
AlarmManager::getInstance().termAlarmTable();
- // 销毁生产表
- ProductionLogManager::getInstance().termProductionTable();
-
// 销毁SECS运行设置管理库
SECSRuntimeManager::getInstance().termRuntimeSetting();
+ // 销毁搬运记录管理库
+ TransferManager::getInstance().termTransferTable();
+
return CWinApp::ExitInstance();
}
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index d392894..140d51f 100644
--- a/SourceCode/Bond/Servo/Servo.rc
+++ b/SourceCode/Bond/Servo/Servo.rc
Binary files differ
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index 21de14d..11eb375 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -317,6 +317,7 @@
<ClInclude Include="targetver.h" />
<ClInclude Include="TerminalDisplayDlg.h" />
<ClInclude Include="ToolUnits.h" />
+ <ClInclude Include="TransferManager.h" />
<ClInclude Include="VerticalLine.h" />
</ItemGroup>
<ItemGroup>
@@ -438,6 +439,7 @@
</ClCompile>
<ClCompile Include="TerminalDisplayDlg.cpp" />
<ClCompile Include="ToolUnits.cpp" />
+ <ClCompile Include="TransferManager.cpp" />
<ClCompile Include="VerticalLine.cpp" />
</ItemGroup>
<ItemGroup>
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index b2ae64c..1a8bb3f 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -149,6 +149,7 @@
<Filter>GridControl\NewCellTypes</Filter>
</ClCompile>
<ClCompile Include="PortConfigurationDlg.cpp" />
+ <ClCompile Include="TransferManager.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AlarmManager.h" />
@@ -303,6 +304,7 @@
<Filter>GridControl\NewCellTypes</Filter>
</ClInclude>
<ClInclude Include="PortConfigurationDlg.h" />
+ <ClInclude Include="TransferManager.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Servo.rc" />
diff --git a/SourceCode/Bond/Servo/TransferManager.cpp b/SourceCode/Bond/Servo/TransferManager.cpp
new file mode 100644
index 0000000..bfcf457
--- /dev/null
+++ b/SourceCode/Bond/Servo/TransferManager.cpp
@@ -0,0 +1,550 @@
+#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;
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/TransferManager.h b/SourceCode/Bond/Servo/TransferManager.h
new file mode 100644
index 0000000..ed1bbf6
--- /dev/null
+++ b/SourceCode/Bond/Servo/TransferManager.h
@@ -0,0 +1,171 @@
+#ifndef TRANSFER_MANAGER_H
+#define TRANSFER_MANAGER_H
+
+#include <string>
+#include <vector>
+#include <mutex>
+#include <unordered_map>
+#include "Database.h"
+
+/**
+ * 任务状态枚举类型
+ */
+enum class TransferStatus {
+ Ready = 0,
+ Running,
+ Error,
+ Abort,
+ Completed
+};
+
+/**
+ * 搬运记录结构体
+ */
+struct TransferData {
+ int nRecordId; // 主键
+ std::string strClassID; // 搬运任务 ClassID
+ std::string strStatus; // 任务状态(字符串:Ready、Running...)
+ std::string strCreateTime; // 创建时间
+ std::string strPickTime; // 取片时间
+ std::string strPlaceTime; // 放片时间
+ std::string strEndTime; // 结束时间
+ std::string strDescription; // 任务说明
+};
+
+using TransferDataMap = std::unordered_map<int, TransferData>;
+
+class TransferManager {
+public:
+ /**
+ * 获取 TransferManager 单例
+ * @return TransferManager 实例
+ */
+ static TransferManager& getInstance();
+
+ /**
+ * 初始化搬运记录表
+ * @return 成功返回 true,失败返回 false
+ */
+ bool initTransferTable();
+
+ /**
+ * 插入测试搬运记录
+ */
+ void insertTestTransferRecord();
+
+ /**
+ * 终止数据库连接
+ */
+ void termTransferTable();
+
+ /**
+ * 删除搬运记录表
+ * @return 成功返回 true,失败返回 false
+ */
+ bool destroyTransferTable();
+
+ /**
+ * 插入搬运记录
+ * @param data 搬运记录结构体
+ * @param outRecordId 插入后的记录主键 ID
+ * @return 成功返回 true,失败返回 false
+ */
+ bool addTransferRecord(const TransferData& data, int& outRecordId);
+
+ /**
+ * 查询所有搬运记录
+ * @return 所有记录数据
+ */
+ std::vector<TransferData> getAllTransfers();
+
+ /**
+ * 根据记录 ID 查询搬运记录
+ * @param id 记录主键 ID
+ * @return 搬运记录数据
+ */
+ TransferData getTransferById(int id);
+
+ /**
+ * 根据时间范围查询搬运记录
+ * @param startTime 起始时间
+ * @param endTime 结束时间
+ * @return 搬运记录数据
+ */
+ std::vector<TransferData> getTransfersByTimeRange(const std::string& startTime, const std::string& endTime);
+
+ /**
+ * 根据状态查询搬运记录
+ * @param status 任务状态
+ * @return 搬运记录数据
+ */
+ std::vector<TransferData> TransferManager::getTransfersByStatus(const std::string& status);
+
+ /**
+ * 分页获取搬运记录
+ * @param startPosition 起始记录位置
+ * @param count 获取的记录数量
+ * @return 搬运记录数据
+ */
+ //std::vector<TransferData> getTransfers(int startPosition, int count);
+
+ /**
+ * 获取符合条件的记录总数
+ */
+ int getTotalTransferCount();
+
+ /**
+ * 分页获取符合条件的搬运记录
+ * @param filter 过滤条件
+ * @param pageNum 页码
+ * @param pageSize 每页记录数
+ */
+ std::vector<TransferData> getTransfers(const TransferData& filter, int pageNum, int pageSize);
+
+ /**
+ * 获取符合条件的记录总数
+ * @param filter 过滤条件
+ * @return 符合条件的记录总数
+ */
+ int getTotalTransferCount(const TransferData& filter);;
+
+ /**
+ * 清理早于某一时间的搬运记录
+ * @param daysToKeep 保留的天数
+ */
+ void cleanOldTransfers(int daysToKeep = 30);
+
+ /**
+ * 读取搬运记录 CSV 文件
+ * @param filename 文件名
+ * @return 成功返回 true,失败返回 false
+ */
+ bool readTransferFile(const std::string& filename);
+
+ /**
+ * 保存搬运记录到 CSV 文件
+ * @param filename 文件名
+ * @return 成功返回 true,失败返回 false
+ */
+ bool saveTransferFile(const std::string& filename);
+
+private:
+ TransferManager();
+ ~TransferManager();
+
+ // 禁止拷贝和赋值
+ TransferManager(const TransferManager&) = delete;
+ TransferManager& operator=(const TransferManager&) = delete;
+
+ // 内联函数
+ inline int statusToInt(TransferStatus status);
+ inline TransferStatus intToStatus(int value);
+ inline std::string statusToString(TransferStatus status);
+ inline TransferStatus stringToStatus(const std::string& str);
+ inline std::string ansiToUtf8(const std::string& ansiStr);
+ inline std::string utf8ToAnsi(const std::string& utf8Str);
+
+ BL::Database* m_pDB;
+ static std::mutex m_mutex;
+};
+
+#endif // TRANSFER_MANAGER_H
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index a205193..f530d52 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/SourceCode/Bond/Servo/resource.h
Binary files differ
--
Gitblit v1.9.3