mrDarker
2025-05-29 958cfa6b2e1c1eec0e20edc50816ef18f10cbf09
1. 修改本地模式Port设置界面
2. 添加Transfer数据库管理类
已添加2个文件
已修改6个文件
791 ■■■■■ 文件已修改
SourceCode/Bond/Servo/PortConfigurationDlg.cpp 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.cpp 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.rc 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj.filters 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/TransferManager.cpp 550 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/TransferManager.h 171 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/resource.h 补丁 | 查看 | 原始文档 | blame | 历史
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);
        }
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();
}
SourceCode/Bond/Servo/Servo.rc
Binary files differ
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>
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" />
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;
}
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
SourceCode/Bond/Servo/resource.h
Binary files differ