From 44360bc2cdeee16be72f9cc4bfb42e0ac26b5b44 Mon Sep 17 00:00:00 2001
From: chenluhua1980 <Chenluhua@qq.com>
Date: 星期一, 19 一月 2026 14:47:19 +0800
Subject: [PATCH] 1.修改优化

---
 SourceCode/Bond/Servo/CPageGlassList.cpp |  845 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 755 insertions(+), 90 deletions(-)

diff --git a/SourceCode/Bond/Servo/CPageGlassList.cpp b/SourceCode/Bond/Servo/CPageGlassList.cpp
index d85afe4..801a337 100644
--- a/SourceCode/Bond/Servo/CPageGlassList.cpp
+++ b/SourceCode/Bond/Servo/CPageGlassList.cpp
@@ -8,12 +8,13 @@
 #include "GlassJson.h"
 #include "CServoUtilsTool.h"
 #include "ToolUnits.h"
-
 #include <optional>
 #include <unordered_set>
 #include <unordered_map>
 #include <vector>
 #include <string>
+#include <algorithm>
+#include "CProcessDataListDlg.h"
 
 #define PAGE_SIZE                       50
 #define PAGE_BACKGROUND_COLOR           RGB(252, 252, 255)
@@ -99,6 +100,9 @@
 
 // ====== 寮�鍏筹細1=鍚敤鍋囨暟鎹紙鍙浛鎹� DB 鏌ヨ锛夛紱0=鐢ㄧ湡瀹� DB ======
 #define USE_FAKE_DB_DEMO 0
+
+// ====== 寮�鍏筹細1=鍚敤妯℃嫙浼犳劅鍣ㄦ暟鎹敓鎴愶紱0=浣跨敤鐪熷疄鏁版嵁 ======
+#define USE_MOCK_SENSOR_DATA 0
 
 #if USE_FAKE_DB_DEMO
 #include <ctime>
@@ -372,6 +376,55 @@
     return true;
 }
 
+// 杈呭姪鍑芥暟锛氬皢 ANSI CString 鍐欏叆鏂囦欢涓� UTF-8 缂栫爜
+bool CPageGlassList::WriteAnsiStringAsUtf8ToFile(const CString& ansiContent, const CString& filePath)
+{
+    CFile file;
+    if (!file.Open(filePath, CFile::modeCreate | CFile::modeWrite)) {
+        return false;
+    }
+
+    // 鍐欏叆 UTF-8 BOM
+    const unsigned char bom[] = { 0xEF, 0xBB, 0xBF };
+    file.Write(bom, 3);
+
+    // 灏� ANSI 杞崲涓� Unicode
+    int unicodeLength = MultiByteToWideChar(CP_ACP, 0,
+        ansiContent, ansiContent.GetLength(),
+        NULL, 0);
+
+    if (unicodeLength <= 0) {
+        file.Close();
+        return false;
+    }
+
+    wchar_t* unicodeBuffer = new wchar_t[unicodeLength + 1];
+    MultiByteToWideChar(CP_ACP, 0,
+        ansiContent, ansiContent.GetLength(),
+        unicodeBuffer, unicodeLength);
+    unicodeBuffer[unicodeLength] = 0;
+
+    // 灏� Unicode 杞崲涓� UTF-8
+    int utf8Length = WideCharToMultiByte(CP_UTF8, 0,
+        unicodeBuffer, unicodeLength,
+        NULL, 0, NULL, NULL);
+
+    bool success = false;
+    if (utf8Length > 0) {
+        char* utf8Buffer = new char[utf8Length];
+        WideCharToMultiByte(CP_UTF8, 0,
+            unicodeBuffer, unicodeLength,
+            utf8Buffer, utf8Length, NULL, NULL);
+
+        file.Write(utf8Buffer, utf8Length);
+        delete[] utf8Buffer;
+        success = true;
+    }
+
+    delete[] unicodeBuffer;
+    file.Close();
+    return success;
+}
 
 // CPageGlassList 瀵硅瘽妗�
 
@@ -426,6 +479,7 @@
     ON_BN_CLICKED(IDC_BUTTON_PREV_PAGE, &CPageGlassList::OnBnClickedButtonPrevPage)
     ON_BN_CLICKED(IDC_BUTTON_NEXT_PAGE, &CPageGlassList::OnBnClickedButtonNextPage)
     ON_NOTIFY(ELCN_SHOWFULLTEXT, IDC_LIST_ALARM, &CPageGlassList::OnShowFullText)
+    ON_BN_CLICKED(IDC_BUTTON_EXPORT_ROW, &CPageGlassList::OnBnClickedButtonExportRow)
 END_MESSAGE_MAP()
 
 // ===== 绉佹湁灏忓伐鍏� =====
@@ -436,7 +490,7 @@
 }
 
 // ===== CPageGlassList 娑堟伅澶勭悊绋嬪簭 =====
-void CPageGlassList::InitRxWindow()
+void CPageGlassList::InitRxWindows()
 {
     // 璁㈤槄鏁版嵁
     IRxWindows* pRxWindows = RX_GetRxWindows();
@@ -661,106 +715,163 @@
     auto pageFull = db.queryPaged(m_filters, rawLimit, rawOffset);
 #endif
 
-    // 濡傛灉澶氬嚭涓�鏉★紝鐪嬬湅瀹冩槸鍚︽槸鈥滄湰椤垫渶鍚庝竴鏉♀�濈殑 buddy
-    std::optional<decltype(pageFull.items)::value_type> lookahead; // 棰勮璁板綍锛堣嫢涓庢渶鍚庝竴鏉¢厤瀵癸級
+#if !USE_FAKE_DB_DEMO
+    // 鈥斺�� 涓夊厓閿伐鍏凤細<classId>|C<cassette>|J<job> 鈥斺�� //
+// 鈥斺�� 涓夊厓閿伐鍏凤細<classId>|C<cassette>|J<job> 鈥斺�� //
+    auto makeKey = [](const std::string& cls, int csn, int jsn) -> std::string {
+        std::string k;
+        k.reserve(cls.size() + 32);
+        k.append(cls);
+        k.push_back('|'); k.push_back('C');
+        k.append(std::to_string(csn));
+        k.push_back('|'); k.push_back('J');
+        k.append(std::to_string(jsn));
+        return k;
+    };
+
+    // 鈽呪槄鈽� 杩欓噷鏄叧閿慨澶嶏細鎺ユ敹鈥渃onst Row&鈥濓紝涓嶈闈� const 寮曠敤
+    using RowT = std::decay<decltype(pageFull.items.front())>::type;
+    auto makeKeyR = [&](const RowT& r) -> std::string {
+        return makeKey(r.classId, r.cassetteSeqNo, r.jobSeqNo);
+    };
+
+    // 涓嶅尯鍒嗗ぇ灏忓啓 classId 鐩哥瓑
     auto iEquals = [](const std::string& a, const std::string& b) {
 #ifdef _WIN32
         return _stricmp(a.c_str(), b.c_str()) == 0;
 #else
         return strcasecmp(a.c_str(), b.c_str()) == 0;
 #endif
-    };
+};
 
+
+    // 鈥斺�� lookahead 棰勮锛氳嫢瓒呭嚭 1 鏉★紝灏濊瘯鎶娾�滄渶鍚庝竴鏉♀�濅笌鈥滈璇烩�濆垽涓轰竴瀵癸紙涓ユ牸浼樺厛锛夆�斺��
+    std::optional<decltype(pageFull.items)::value_type> lookahead;
     if (pageFull.items.size() == rawLimit) {
         const auto& last = pageFull.items[PAGE_SIZE - 1];
         const auto& extra = pageFull.items[PAGE_SIZE];
 
-        bool pair =
+        bool strictPair =
+            (!last.buddyId.empty() && iEquals(last.buddyId, extra.classId)
+                && last.cassetteSeqNo == extra.cassetteSeqNo
+                && last.jobSeqNo == extra.jobSeqNo)
+            || (!extra.buddyId.empty() && iEquals(extra.buddyId, last.classId)
+                && extra.cassetteSeqNo == last.cassetteSeqNo
+                && extra.jobSeqNo == last.jobSeqNo);
+
+        bool loosePair =
             (!last.buddyId.empty() && iEquals(last.buddyId, extra.classId)) ||
             (!extra.buddyId.empty() && iEquals(extra.buddyId, last.classId));
 
-        if (pair) {
-            lookahead = extra;           // 鎶婇璇讳繚瀛樹笅鏉ワ紝绋嶅悗琛ユ垚瀛愯
+        if (strictPair || loosePair) {
+            lookahead = extra;
         }
-        // 鏃犺鏄惁閰嶅锛屽垪琛ㄩ兘缂╁洖 PAGE_SIZE 鏉★紙棰勮涓嶇畻鍏ユ湰椤垫暟鎹泦锛�
+        // 棰勮涓嶇畻鍏ユ湰椤�
         pageFull.items.pop_back();
     }
 
     // 涔嬪悗姝e父鎸� page 鏋勫缓
-    auto& page = pageFull; // 涓轰簡澶嶇敤浣犲師鏈夊彉閲忓悕
+    auto& pageRef = pageFull;
 
-    // 寤虹储寮曪細classId -> index
-    std::unordered_map<std::string, size_t> idxById;
-    idxById.reserve(page.items.size());
-    for (size_t i = 0; i < page.items.size(); ++i) {
-        idxById[page.items[i].classId] = i;
+    // 鈥斺�� 寤轰袱涓储寮� 鈥斺�� //
+    // A) byTriple: 涓夊厓閿� -> index锛堝敮涓�/宸叉秷璐逛緷鎹級
+    // B) byClass : classId -> indices锛坆uddy 鍊欓�夋睜锛屽厑璁稿涓級
+    std::unordered_map<std::string, size_t> byTriple;
+    std::unordered_map<std::string, std::vector<size_t>> byClass;
+    byTriple.reserve(pageRef.items.size());
+    byClass.reserve(pageRef.items.size());
+
+    for (size_t i = 0; i < pageRef.items.size(); ++i) {
+        const auto& r = pageRef.items[i];
+        byTriple[makeKeyR(r)] = i;
+        byClass[r.classId].push_back(i);
     }
 
-    // 宸叉秷璐癸紙宸叉彃鍏ヤ负鐖舵垨瀛愶級
+    // 鈥斺�� 宸叉秷璐归泦鍚堬紙鐢ㄤ笁鍏冮敭锛夆�斺��
     std::unordered_set<std::string> consumed;
+    consumed.reserve(pageRef.items.size());
+
     int zebra = 0;
     auto zebraBk = [&](int z) -> COLORREF {
         return (z % 2 == 0) ? RGB(255, 255, 255) : RGB(235, 235, 235);
     };
 
-    // -------- Phase 1: 鍏堝鐞嗏�滄湁 buddyId 鐨勮褰曗�濓紙鑳介厤灏遍厤锛涘崟鍚戜篃閰嶏級 ----------
-    for (size_t i = 0; i < page.items.size(); ++i) {
-        const auto& r = page.items[i];
-        // CopyUtf8ToClipboard(r.pretty);
-        
-        if (consumed.count(r.classId)) continue;
+    // -------- Phase 1: 鍏堝鐞嗏�滄湁 buddyId 鐨勮褰曗�� ----------
+    for (size_t i = 0; i < pageRef.items.size(); ++i) {
+        const auto& r = pageRef.items[i];
+        if (consumed.count(makeKeyR(r))) continue;
         if (r.buddyId.empty()) continue;
 
-        COLORREF bk = zebraBk(zebra);
+        // 鍦ㄥ悓椤甸噷涓� r 鎵� buddy 鍊欓��
+        size_t buddyIdx = (size_t)-1;
+        auto itVec = byClass.find(r.buddyId);
+        if (itVec != byClass.end()) {
+            const auto& vec = itVec->second;
 
-        auto it = idxById.find(r.buddyId);
-        if (it != idxById.end()) {
-            const auto& br = page.items[it->second];
-            if (!consumed.count(br.classId)) {
-                // 鈥斺�� 浠モ�滄湁 buddyId 鐨勮繖鏉� r鈥濅负鐖讹紝buddy 浣滀负瀛愶紙鍗曞悜涔熻兘閰嶏級鈥斺��
-                std::vector<CString> pcols(colCount);
-                pcols[1] = std::to_string(r.id).c_str();
-                pcols[2] = std::to_string(r.cassetteSeqNo).c_str();
-                pcols[3] = std::to_string(r.jobSeqNo).c_str();
-                pcols[4] = r.classId.c_str();
-                pcols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)r.materialType).c_str();
-                pcols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)r.state).c_str();
-                pcols[7] = r.tStart.c_str();
-                pcols[8] = r.tEnd.c_str();
-                pcols[9] = r.buddyId.c_str();
-                pcols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)r.aoiResult).c_str();
-                pcols[11] = r.path.c_str();
-                pcols[12] = r.params.c_str();
-
-                auto* nParent = m_listCtrl.InsertRoot(pcols);
-                MaybeRestoreExpandByKey(nParent, expandedKeys);
-                m_listCtrl.SetNodeColor(nParent, RGB(0, 0, 0), bk);
-
-                std::vector<CString> ccols(colCount);
-                ccols[1] = std::to_string(br.id).c_str();
-                ccols[2] = std::to_string(br.cassetteSeqNo).c_str();
-                ccols[3] = std::to_string(br.jobSeqNo).c_str();
-                ccols[4] = br.classId.c_str();
-                ccols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)br.materialType).c_str();
-                ccols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)br.state).c_str();
-                ccols[7] = br.tStart.c_str();
-                ccols[8] = br.tEnd.c_str();
-                ccols[9] = br.buddyId.c_str();
-                ccols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)br.aoiResult).c_str();
-                ccols[11] = br.path.c_str();
-                ccols[12] = br.params.c_str();
-
-                auto* nChild = m_listCtrl.InsertChild(nParent, ccols);
-                m_listCtrl.SetNodeColor(nChild, RGB(0, 0, 0), bk);
-
-                consumed.insert(r.classId);
-                consumed.insert(br.classId);
-                ++zebra;
-                continue;
+            // 1) 涓ユ牸鍖归厤锛欳assette/Job 涓�鑷�
+            for (size_t j : vec) {
+                const auto& br = pageRef.items[j];
+                if (br.cassetteSeqNo == r.cassetteSeqNo && br.jobSeqNo == r.jobSeqNo) {
+                    if (!consumed.count(makeKeyR(br))) { buddyIdx = j; break; }
+                }
+            }
+            // 2) 瀹芥澗鍖归厤锛氬悓 classId 鏈秷璐圭殑浠绘剰涓�鏉�
+            if (buddyIdx == (size_t)-1) {
+                for (size_t j : vec) {
+                    const auto& br = pageRef.items[j];
+                    if (!consumed.count(makeKeyR(br))) { buddyIdx = j; break; }
+                }
             }
         }
 
-        // 鍚岄〉娌℃壘鍒� buddy锛堟垨宸茶娑堣垂锛夆啋 鎻掑崰浣嶅瓙琛�
+        COLORREF bk = zebraBk(zebra);
+
+        if (buddyIdx != (size_t)-1) {
+            const auto& br = pageRef.items[buddyIdx];
+
+            // 鐖讹細r锛堟湁 buddyId锛夛紝瀛愶細br
+            std::vector<CString> pcols(colCount);
+            pcols[1] = std::to_string(r.id).c_str();
+            pcols[2] = std::to_string(r.cassetteSeqNo).c_str();
+            pcols[3] = std::to_string(r.jobSeqNo).c_str();
+            pcols[4] = r.classId.c_str();
+            pcols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)r.materialType).c_str();
+            pcols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)r.state).c_str();
+            pcols[7] = r.tStart.c_str();
+            pcols[8] = r.tEnd.c_str();
+            pcols[9] = r.buddyId.c_str();
+            pcols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)r.aoiResult).c_str();
+            pcols[11] = r.path.c_str();
+            pcols[12] = r.params.c_str();
+
+            auto* nParent = m_listCtrl.InsertRoot(pcols);
+            MaybeRestoreExpandByKey(nParent, expandedKeys);
+            m_listCtrl.SetNodeColor(nParent, RGB(0, 0, 0), bk);
+
+            std::vector<CString> ccols(colCount);
+            ccols[1] = std::to_string(br.id).c_str();
+            ccols[2] = std::to_string(br.cassetteSeqNo).c_str();
+            ccols[3] = std::to_string(br.jobSeqNo).c_str();
+            ccols[4] = br.classId.c_str();
+            ccols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)br.materialType).c_str();
+            ccols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)br.state).c_str();
+            ccols[7] = br.tStart.c_str();
+            ccols[8] = br.tEnd.c_str();
+            ccols[9] = br.buddyId.c_str();
+            ccols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)br.aoiResult).c_str();
+            ccols[11] = br.path.c_str();
+            ccols[12] = br.params.c_str();
+
+            auto* nChild = m_listCtrl.InsertChild(nParent, ccols);
+            m_listCtrl.SetNodeColor(nChild, RGB(0, 0, 0), bk);
+
+            consumed.insert(makeKeyR(r));
+            consumed.insert(makeKeyR(br));
+            ++zebra;
+            continue;
+        }
+
+        // 娌℃壘鍒� buddy 鈫� 鎻掑崰浣嶅瓙琛岋紙鍙啓 ClassID锛�
         std::vector<CString> pcols(colCount);
         pcols[1] = std::to_string(r.id).c_str();
         pcols[2] = std::to_string(r.cassetteSeqNo).c_str();
@@ -777,24 +888,162 @@
 
         auto* nParent = m_listCtrl.InsertRoot(pcols);
         MaybeRestoreExpandByKey(nParent, expandedKeys);
-        m_listCtrl.SetNodeColor(nParent, RGB(0, 0, 0), bk);
+        m_listCtrl.SetNodeColor(nParent, RGB(0, 0, 0), zebraBk(zebra));
 
-        std::vector<CString> ccols(colCount); // 鍗犱綅鍙啓 ClassID
-        ccols[4] = r.buddyId.c_str();
+        std::vector<CString> ccols(colCount);
+        ccols[4] = r.buddyId.c_str(); // 鍗犱綅
         auto* nChild = m_listCtrl.InsertChild(nParent, ccols);
-        m_listCtrl.SetNodeColor(nChild, RGB(0, 0, 0), bk);
+        m_listCtrl.SetNodeColor(nChild, RGB(0, 0, 0), zebraBk(zebra));
 
-        consumed.insert(r.classId);
+        consumed.insert(makeKeyR(r));
         ++zebra;
     }
 
     // -------- Phase 2: 鍓╀綑鏈秷璐圭殑锛屼綔涓衡�滃崟鏉℃牴琛屸�� ----------
-    for (size_t i = 0; i < page.items.size(); ++i) {
-        const auto& r = page.items[i];
-        if (consumed.count(r.classId)) continue;
+    for (size_t i = 0; i < pageRef.items.size(); ++i) {
+        const auto& r = pageRef.items[i];
+        if (consumed.count(makeKeyR(r))) continue;
 
         COLORREF bk = zebraBk(zebra);
 
+        std::vector<CString> cols(colCount);
+        cols[1] = std::to_string(r.id).c_str();
+        cols[2] = std::to_string(r.cassetteSeqNo).c_str();
+        cols[3] = std::to_string(r.jobSeqNo).c_str();
+        cols[4] = r.classId.c_str();
+        cols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)r.materialType).c_str();
+        cols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)r.state).c_str();
+        cols[7] = r.tStart.c_str();
+        cols[8] = r.tEnd.c_str();
+        cols[9] = r.buddyId.c_str();
+        cols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)r.aoiResult).c_str();
+        cols[11] = r.path.c_str();
+        cols[12] = r.params.c_str();
+
+        auto* n = m_listCtrl.InsertRoot(cols);
+        m_listCtrl.SetNodeColor(n, RGB(0, 0, 0), bk);
+
+        consumed.insert(makeKeyR(r));
+        ++zebra;
+    }
+
+    // 涓�娆℃�ч噸缁�
+    m_listCtrl.RebuildVisible();
+
+#else
+    // ===== DEMO 鍒嗘敮锛堜繚鎸佸師鏍凤紱鑻ヨ婕旂ず鍚屾牱閫昏緫锛屽彲浠跨収涓婇潰鏀归�狅級=====
+    // 濡傛灉澶氬嚭涓�鏉★紝鐪嬬湅瀹冩槸鍚︽槸鈥滄湰椤垫渶鍚庝竴鏉♀�濈殑 buddy
+    std::optional<decltype(page.items)::value_type> lookahead;
+    auto iEquals = [](const std::string& a, const std::string& b) {
+#ifdef _WIN32
+        return _stricmp(a.c_str(), b.c_str()) == 0;
+#else
+        return strcasecmp(a.c_str(), b.c_str()) == 0;
+#endif
+    };
+
+    if (page.items.size() == rawLimit) {
+        const auto& last = page.items[PAGE_SIZE - 1];
+        const auto& extra = page.items[PAGE_SIZE];
+        bool pair =
+            (!last.buddyId.empty() && iEquals(last.buddyId, extra.classId)) ||
+            (!extra.buddyId.empty() && iEquals(extra.buddyId, last.classId));
+        if (pair) lookahead = extra;
+        page.items.pop_back();
+    }
+
+    // 浣犲彲浠ユ妸 DEMO 鍒嗘敮涔熷垏鍒颁笁鍏冮敭閫昏緫锛涜繖閲屼粠鐣�
+    auto& pageRef = page;
+    std::unordered_map<std::string, size_t> idxById;
+    idxById.reserve(pageRef.items.size());
+    for (size_t i = 0; i < pageRef.items.size(); ++i) idxById[pageRef.items[i].classId] = i;
+
+    std::unordered_set<std::string> consumed;
+    int zebra = 0;
+    auto zebraBk = [&](int z) -> COLORREF {
+        return (z % 2 == 0) ? RGB(255, 255, 255) : RGB(235, 235, 235);
+    };
+
+    for (size_t i = 0; i < pageRef.items.size(); ++i) {
+        const auto& r = pageRef.items[i];
+        if (consumed.count(r.classId)) continue;
+        if (!r.buddyId.empty()) {
+            auto it = idxById.find(r.buddyId);
+            if (it != idxById.end()) {
+                const auto& br = pageRef.items[it->second];
+                if (!consumed.count(br.classId)) {
+                    COLORREF bk = zebraBk(zebra);
+                    std::vector<CString> pcols(colCount), ccols(colCount);
+                    pcols[1] = std::to_string(r.id).c_str();
+                    pcols[2] = std::to_string(r.cassetteSeqNo).c_str();
+                    pcols[3] = std::to_string(r.jobSeqNo).c_str();
+                    pcols[4] = r.classId.c_str();
+                    pcols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)r.materialType).c_str();
+                    pcols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)r.state).c_str();
+                    pcols[7] = r.tStart.c_str();
+                    pcols[8] = r.tEnd.c_str();
+                    pcols[9] = r.buddyId.c_str();
+                    pcols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)r.aoiResult).c_str();
+                    pcols[11] = r.path.c_str();
+                    pcols[12] = r.params.c_str();
+                    auto* nParent = m_listCtrl.InsertRoot(pcols);
+                    MaybeRestoreExpandByKey(nParent, expandedKeys);
+                    m_listCtrl.SetNodeColor(nParent, RGB(0, 0, 0), bk);
+
+                    ccols[1] = std::to_string(br.id).c_str();
+                    ccols[2] = std::to_string(br.cassetteSeqNo).c_str();
+                    ccols[3] = std::to_string(br.jobSeqNo).c_str();
+                    ccols[4] = br.classId.c_str();
+                    ccols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)br.materialType).c_str();
+                    ccols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)br.state).c_str();
+                    ccols[7] = br.tStart.c_str();
+                    ccols[8] = br.tEnd.c_str();
+                    ccols[9] = br.buddyId.c_str();
+                    ccols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)br.aoiResult).c_str();
+                    ccols[11] = br.path.c_str();
+                    ccols[12] = br.params.c_str();
+                    auto* nChild = m_listCtrl.InsertChild(nParent, ccols);
+                    m_listCtrl.SetNodeColor(nChild, RGB(0, 0, 0), bk);
+
+                    consumed.insert(r.classId);
+                    consumed.insert(br.classId);
+                    ++zebra;
+                    continue;
+                }
+            }
+
+            // 鎻掑崰浣嶅瓙
+            COLORREF bk = zebraBk(zebra);
+            std::vector<CString> pcols(colCount), ccols(colCount);
+            pcols[1] = std::to_string(r.id).c_str();
+            pcols[2] = std::to_string(r.cassetteSeqNo).c_str();
+            pcols[3] = std::to_string(r.jobSeqNo).c_str();
+            pcols[4] = r.classId.c_str();
+            pcols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)r.materialType).c_str();
+            pcols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)r.state).c_str();
+            pcols[7] = r.tStart.c_str();
+            pcols[8] = r.tEnd.c_str();
+            pcols[9] = r.buddyId.c_str();
+            pcols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)r.aoiResult).c_str();
+            pcols[11] = r.path.c_str();
+            pcols[12] = r.params.c_str();
+            auto* nParent = m_listCtrl.InsertRoot(pcols);
+            MaybeRestoreExpandByKey(nParent, expandedKeys);
+            m_listCtrl.SetNodeColor(nParent, RGB(0, 0, 0), bk);
+
+            ccols[4] = r.buddyId.c_str();
+            auto* nChild = m_listCtrl.InsertChild(nParent, ccols);
+            m_listCtrl.SetNodeColor(nChild, RGB(0, 0, 0), bk);
+
+            consumed.insert(r.classId);
+            ++zebra;
+        }
+    }
+    for (size_t i = 0; i < pageRef.items.size(); ++i) {
+        const auto& r = pageRef.items[i];
+        if (consumed.count(r.classId)) continue;
+
+        COLORREF bk = zebraBk(zebra);
         std::vector<CString> cols(colCount);
         cols[1] = std::to_string(r.id).c_str();
         cols[2] = std::to_string(r.cassetteSeqNo).c_str();
@@ -816,8 +1065,8 @@
         ++zebra;
     }
 
-    // 涓�娆℃�ч噸缁�
     m_listCtrl.RebuildVisible();
+#endif
 
     // 涓婁竴椤� / 涓嬩竴椤�
     UpdatePageControls();
@@ -946,7 +1195,7 @@
 {
     if (nIDEvent == 1) {
         KillTimer(1);
-        InitRxWindow();
+        InitRxWindows();
     }
     else if (nIDEvent == 2) {
         UpdateWipData();  // 鍙仛澧為噺锛屼笉閲嶅缓
@@ -1045,6 +1294,264 @@
     }
 }
 
+void CPageGlassList::OnBnClickedButtonExportRow()
+{
+    int nSelected = m_listCtrl.GetSelectionMark();
+    if (nSelected == -1) {
+        AfxMessageBox(_T("璇峰厛閫夋嫨涓�琛岃褰曪紒"));
+        return;
+    }
+
+    // 鐩存帴浠庣涓�鍒楄幏鍙� ID
+    CString strId = m_listCtrl.GetItemText(nSelected, 1);
+
+    if (strId.IsEmpty()) {
+        AfxMessageBox(_T("WIP璁板綍鏆備笉鏀寔淇濆瓨"));
+        return;
+    }
+
+    // 鏁版嵁搴撹褰�
+    long long recordId = _ttoi64(strId);
+
+    // 浠庢暟鎹簱鏌ヨ瀹屾暣璁板綍
+    auto& db = GlassLogDb::Instance();
+    auto row = db.queryById(recordId);
+
+    if (!row) {
+        AfxMessageBox(_T("鏌ヨ璁板綍澶辫触"));
+        return;
+    }
+
+    // 浣跨敤 Glass ID 鏋勫缓榛樿鏂囦欢鍚�
+    CString strDefaultFileName;
+    CString strGlassId = row->classId.c_str();
+
+    // 绉婚櫎鏂囦欢鍚嶄腑鐨勯潪娉曞瓧绗�
+    CString strSanitizedGlassId = strGlassId;
+    strSanitizedGlassId.Remove('\\');
+    strSanitizedGlassId.Remove('/');
+    strSanitizedGlassId.Remove(':');
+    strSanitizedGlassId.Remove('*');
+    strSanitizedGlassId.Remove('?');
+    strSanitizedGlassId.Remove('"');
+    strSanitizedGlassId.Remove('<');
+    strSanitizedGlassId.Remove('>');
+    strSanitizedGlassId.Remove('|');
+
+    strDefaultFileName.Format(_T("Glass_%s.csv"), strSanitizedGlassId);
+
+    // 鏂囦欢淇濆瓨瀵硅瘽妗嗭紝璁剧疆榛樿鏂囦欢鍚�
+    CFileDialog fileDialog(FALSE, _T("csv"), strDefaultFileName,
+        OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
+        _T("CSV Files (*.csv)|*.csv|JSON Files (*.json)|*.json||"));
+
+    if (fileDialog.DoModal() != IDOK) return;
+
+    CString filePath = fileDialog.GetPathName();
+    CString fileExt = fileDialog.GetFileExt();
+
+    if (fileExt.CompareNoCase(_T("json")) == 0) {
+        ExportToJson(*row, filePath);
+    }
+    else {
+        ExportToCsv(*row, filePath);
+    }
+}
+
+void CPageGlassList::ExportToJson(const GlassLogDb::Row& row, const CString& filePath)
+{
+    // 淇濆瓨涓� JSON
+    if (!row.pretty.empty()) {
+        CFile file;
+        if (file.Open(filePath, CFile::modeCreate | CFile::modeWrite)) {
+            file.Write(row.pretty.c_str(), (UINT)row.pretty.length());
+            file.Close();
+
+            CString strSuccess;
+            strSuccess.Format(_T("璁板綍宸蹭繚瀛樹负JSON鏂囦欢锛歕n%s"), filePath);
+            AfxMessageBox(strSuccess);
+        }
+        else {
+            AfxMessageBox(_T("淇濆瓨鏂囦欢澶辫触"));
+        }
+    }
+    else {
+        AfxMessageBox(_T("璇ヨ褰曟病鏈塉SON鏁版嵁"));
+    }
+}
+
+void CPageGlassList::ExportToCsv(const GlassLogDb::Row& row, const CString& filePath)
+{
+    CString csvContent;
+
+    // === 绗竴閮ㄥ垎锛氬熀纭�淇℃伅 ===
+    ExportBasicInfo(csvContent, row);
+
+    // === 绗簩閮ㄥ垎锛氬伐鑹哄弬鏁� ===
+    ExportProcessParams(csvContent, row);
+
+    // === 绗笁閮ㄥ垎锛氫紶鎰熷櫒鏁版嵁璇︽儏 ===
+    ExportSensorData(csvContent, row);
+
+    // 浣跨敤杈呭姪鍑芥暟淇濆瓨涓� UTF-8 缂栫爜
+    if (WriteAnsiStringAsUtf8ToFile(csvContent, filePath)) {
+        CString strSuccess;
+        strSuccess.Format(_T("璁板綍宸蹭繚瀛樹负CSV鏂囦欢锛歕n%s"), filePath);
+        AfxMessageBox(strSuccess);
+    }
+    else {
+        AfxMessageBox(_T("淇濆瓨鏂囦欢澶辫触"));
+    }
+}
+
+void CPageGlassList::ExportBasicInfo(CString& csvContent, const GlassLogDb::Row& row)
+{
+    csvContent += _T("=== 鍩虹淇℃伅 ===\n");
+    csvContent += _T("ID,Cassette搴忓垪鍙�,Job搴忓垪鍙�,Glass ID,鐗╂枡绫诲瀷,鐘舵��,寮�濮嬫椂闂�,缁撴潫鏃堕棿,缁戝畾Glass ID,AOI缁撴灉,璺緞\n");
+
+    CString baseInfoRow;
+    baseInfoRow.Format(_T("%lld,%d,%d,%s,%d,%d,%s,%s,%s,%d,%s\n"),
+        row.id, row.cassetteSeqNo, row.jobSeqNo,
+        CString(row.classId.c_str()), row.materialType, row.state,
+        CString(row.tStart.c_str()), CString(row.tEnd.c_str()),
+        CString(row.buddyId.c_str()), row.aoiResult,
+        CString(row.path.c_str()));
+    csvContent += baseInfoRow;
+}
+
+void CPageGlassList::ExportProcessParams(CString& csvContent, const GlassLogDb::Row& row)
+{
+    csvContent += _T("\n=== 宸ヨ壓鍙傛暟 ===\n");
+
+    // 濡傛灉鏈� pretty 瀛楁锛岃В鏋愬伐鑹哄弬鏁�
+    if (!row.pretty.empty()) {
+        SERVO::CGlass tempGlass;
+        if (GlassJson::FromString(row.pretty, tempGlass)) {
+            auto& params = tempGlass.getParams();
+            if (!params.empty()) {
+                // 宸ヨ壓鍙傛暟琛ㄥご
+                csvContent += _T("鍙傛暟鍚嶇О,鍙傛暟ID,鏁板��,鏈哄櫒鍗曞厓\n");
+
+                // 宸ヨ壓鍙傛暟鏁版嵁
+                for (auto& param : params) {
+                    CString paramRow;
+                    CString valueStr;
+
+                    // 鏍规嵁鍙傛暟绫诲瀷鏍煎紡鍖栨暟鍊�
+                    if (param.getValueType() == PVT_INT) {
+                        valueStr.Format(_T("%d"), param.getIntValue());
+                    }
+                    else {
+                        valueStr.Format(_T("%.3f"), param.getDoubleValue());
+                    }
+
+                    paramRow.Format(_T("%s,%s,%s,%s\n"),
+                        CString(param.getName().c_str()),
+                        CString(param.getId().c_str()),
+                        valueStr,
+                        CString(param.getUnit().c_str()));
+
+                    csvContent += paramRow;
+                }
+            }
+            else {
+                csvContent += _T("鏃犲伐鑹哄弬鏁版暟鎹甛n");
+            }
+        }
+        else {
+            csvContent += _T("鏃犳硶瑙f瀽宸ヨ壓鍙傛暟\n");
+        }
+    }
+    else {
+        csvContent += _T("鏃犲伐鑹哄弬鏁版暟鎹甛n");
+    }
+}
+
+void CPageGlassList::ExportSensorData(CString& csvContent, const GlassLogDb::Row& row)
+{
+    csvContent += _T("\n=== 浼犳劅鍣ㄦ暟鎹鎯� ===\n");
+
+    // 濡傛灉鏈� pretty 瀛楁锛岃В鏋愪紶鎰熷櫒鏁版嵁
+    if (!row.pretty.empty()) {
+        SERVO::CGlass tempGlass;
+        if (GlassJson::FromString(row.pretty, tempGlass)) {
+#if USE_MOCK_SENSOR_DATA
+            // 鐢熸垚妯℃嫙鐨凷VData鐢ㄤ簬娴嬭瘯
+            GenerateMockSVData(tempGlass);
+#endif
+            // 瀵规瘡涓満鍣ㄧ敓鎴愯〃鏍�
+            for (const auto& machinePair : tempGlass.getAllSVData()) {
+                int machineId = machinePair.first;
+                const auto& dataByType = machinePair.second;
+                CString machineName = CString(SERVO::CServoUtilsTool::getEqName(machineId).c_str());
+
+                csvContent += _T("\n[") + machineName + _T("]\n");
+
+                if (dataByType.empty()) {
+                    csvContent += _T("No sensor data\n");
+                    continue;
+                }
+
+                auto columnOrder = getMachineColumnOrder(machineId, &dataByType);
+                if (columnOrder.empty()) {
+                    csvContent += _T("No exportable columns\n");
+                    continue;
+                }
+
+                CString header = _T("Timestamp(ms),LocalTime");
+                for (const auto& dataType : columnOrder) {
+                    header += _T(",");
+                    header += CString(dataType.c_str());
+                }
+                header += _T("\n");
+                csvContent += header;
+
+                auto baselineIt = std::find_if(columnOrder.begin(), columnOrder.end(),
+                    [&](const std::string& type) {
+                        auto dataIt = dataByType.find(type);
+                        return dataIt != dataByType.end() && !dataIt->second.empty();
+                    });
+                if (baselineIt == columnOrder.end()) {
+                    csvContent += _T("No usable time series\n");
+                    continue;
+                }
+
+                const auto& timeSeries = dataByType.at(*baselineIt);
+                for (size_t i = 0; i < timeSeries.size(); ++i) {
+                    auto timestamp = timeSeries[i].timestamp;
+                    auto ms = timePointToMs(timestamp);
+                    CString row;
+                    row.Format(_T("%lld,"), ms);
+
+                    CString localTime = CString(timePointToString(timestamp).c_str());
+                    row += localTime;
+
+                    for (const auto& dataType : columnOrder) {
+                        row += _T(",");
+                        auto dataTypeIt = dataByType.find(dataType);
+                        if (dataTypeIt != dataByType.end() && i < dataTypeIt->second.size()) {
+                            CString valueStr;
+                            valueStr.Format(_T("%.3f"), dataTypeIt->second[i].value);
+                            row += valueStr;
+                        }
+                        else {
+                            row += _T("N/A");
+                        }
+                    }
+                    row += _T("\n");
+                    csvContent += row;
+                }
+            }
+        }
+        else {
+            csvContent += _T("鏃犳硶瑙f瀽浼犳劅鍣ㄦ暟鎹甛n");
+        }
+    }
+    else {
+        csvContent += _T("鏃犱紶鎰熷櫒鏁版嵁\n");
+    }
+}
+
 void CPageGlassList::OnBnClickedButtonPrevPage()
 {
     if (m_nCurPage > 1) {
@@ -1065,10 +1572,16 @@
 {
     auto* p = reinterpret_cast<NMC_ELC_SHOWFULLTEXT*>(pNMHDR);
 
-    // 杩欓噷鏆傛椂鐢ㄦ秷鎭鏄剧ず锛涘悗缁彲鎹㈡垚浣犵殑璇︽儏椤�
-    CString strNewMsg = p->text;
-    strNewMsg.Replace(_T(","), _T("\n"));
-    MessageBox(strNewMsg, _T("璇︾粏淇℃伅"), MB_OK | MB_ICONINFORMATION);
+    // 瀵硅瘽妗嗘樉绀哄伐鑹哄弬鏁�
+    if (p->iSubItem == 12) {
+        CProcessDataListDlg dlg;
+        dlg.setRawText(p->text);
+        dlg.DoModal();
+    }
+    else {
+        AfxMessageBox(p->text);
+    }
+
     *pResult = 0;
 }
 
@@ -1161,7 +1674,7 @@
     CExpandableListCtrl::Node* savedTop = nullptr;
 
     // 3) 閫愪釜澶勭悊 WIP锛氬凡瀛樺湪 -> 灏卞湴鏇存柊锛涘繀瑕佹椂鈥滃彧瀵规牴琛ュ瓙椤光��
-    //                 涓嶅瓨鍦� -> 浼樺厛鎸傚埌 buddy 瀹瑰櫒锛涘惁鍒欒Е鍙戞暣椤甸噸寤猴紙鏂版牴淇濇寔椤堕儴锛�
+    //                 涓嶅瓨鍦� -> 鎸傚埌 buddy 瀹瑰櫒锛涜嫢 buddy 涓嶅湪鍙琛紝瑙﹀彂鍏ㄩ噺閲嶅缓锛堜繚璇� WIP 椤堕儴锛�
     for (auto* g : wipGlasses) {
         if (!GlassMatchesFilters(*g, m_filters)) continue;
 
@@ -1204,7 +1717,7 @@
                 }
             }
 
-            // 鈥斺�� 鍙鈥滄牴鑺傜偣鈥濊ˉ瀛愰」锛屼笖浠呭綋 buddy 灏氭湭鍑虹幇鍦ㄥ彲瑙佽〃锛屼笖鏍逛笅涔熸病鏈夎 buddy 鈥斺�� 
+            // 鈥斺�� 鍙鈥滄牴鑺傜偣鈥濊ˉ瀛愰」 鈥斺�� 
             SERVO::CGlass* b = g->getBuddy();
             if (b) {
                 auto itRoot = wipRootById.find(cid);
@@ -1226,7 +1739,7 @@
                     bool buddyExistsAnywhere = (wipRowById.find(newBid) != wipRowById.end());
                     bool hasChildAlready = NodeHasChildWithClassId(container, newBuddyCid);
 
-                    // 鍏崇郴鏄惁鍙戠敓鍙樺寲锛燂紙oldChildCid 涓� newBuddyCid 涓嶅悓锛屾垨鏈夊瓙浣嗙幇鍦ㄦ病 buddy锛�
+                    // 鍏崇郴鏄惁鍙戠敓鍙樺寲锛�
                     bool relationChanged =
                         (!oldChildCid.IsEmpty() && newBuddyCid.IsEmpty()) ||
                         (oldChildCid.IsEmpty() && !newBuddyCid.IsEmpty()) ||
@@ -1269,10 +1782,9 @@
                         }
                     }
                 }
-                // 鑻ュ綋鍓嶆槸鈥滃瓙鑺傜偣鈥濓紝涓嶅湪杩欓噷璋冩暣鐖跺瓙鍏崇郴锛涜鈥滃叧绯诲彉鍖栤�濊蛋鍏ㄩ噺閲嶅缓
             }
             else {
-                // 娌℃湁 buddy锛氬鏋滃鍣ㄤ笅鐜板湪鏈夊瓙锛屼篃绠楀叧绯诲彉鍖栵紝瑙﹀彂閲嶅缓
+                // 娌� buddy 浣嗗鍣ㄤ笅鏈夊瓙 -> 鍏崇郴鍙樺寲锛岃Е鍙戝叏閲忛噸寤�
                 auto itRoot = wipRootById.find(cid);
                 if (itRoot != wipRootById.end()) {
                     CExpandableListCtrl::Node* container = itRoot->second;
@@ -1283,8 +1795,6 @@
         }
         else {
             // (B) 涓嶅瓨鍦細鏂板
-            //   鍏堝皾璇曗�滄寕鍒� buddy 鐨勫鍣ㄦ牴鈥濅笅闈紱
-            //   鑻� buddy 涓嶅湪褰撳墠鍙琛紝鍒欒Е鍙戝叏閲忛噸寤猴紙淇濊瘉 WIP 椤堕儴锛夈��
             SERVO::CGlass* b = g->getBuddy();
             CExpandableListCtrl::Node* container = nullptr;
 
@@ -1302,7 +1812,6 @@
             }
 
             if (container) {
-                // buddy 瀹瑰櫒瀛樺湪锛氭妸 g 浣滀负鈥滃瓙琛屸�濇寕涓婂幓锛堥伩鍏嶉噸澶嶏級
                 CString cidCs = g->getID().c_str();
                 if (!NodeHasChildWithClassId(container, cidCs)) {
                     if (!needRebuildChildren) { CaptureUiState(m_listCtrl, savedSel, savedTop); }
@@ -1395,3 +1904,159 @@
 
     return true;
 }
+
+BOOL CPageGlassList::PreTranslateMessage(MSG* pMsg)
+{
+    if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE) {
+        return TRUE;
+    }
+
+    return CDialogEx::PreTranslateMessage(pMsg);
+}
+
+// 鑾峰彇鏈哄櫒棰勫畾涔夌殑鍒楅『搴�
+std::vector<std::string> CPageGlassList::getMachineColumnOrder(int machineId,
+    const std::unordered_map<std::string, std::vector<SERVO::SVDataItem>>* actualData)
+{
+    std::vector<std::string> columnOrder;
+    auto dataTypes = SERVO::CServoUtilsTool::getEqDataTypes();
+    auto it = dataTypes.find(machineId);
+
+    if (actualData != nullptr) {
+        if (it != dataTypes.end()) {
+            for (const auto& name : it->second) {
+                if (actualData->find(name) != actualData->end()) {
+                    columnOrder.push_back(name);
+                }
+            }
+        }
+        for (const auto& kv : *actualData) {
+            if (std::find(columnOrder.begin(), columnOrder.end(), kv.first) == columnOrder.end()) {
+                columnOrder.push_back(kv.first);
+            }
+        }
+        return columnOrder;
+    }
+
+    if (it != dataTypes.end()) {
+        columnOrder = it->second;
+    }
+    return columnOrder;
+}
+
+// 鏃堕棿鎴宠浆鎹负瀛楃涓�
+std::string CPageGlassList::timePointToString(const std::chrono::system_clock::time_point& tp) 
+{
+    auto time_t = std::chrono::system_clock::to_time_t(tp);
+    std::tm tm;
+    localtime_s(&tm, &time_t);
+    char buffer[20];
+    std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm);
+    return buffer;
+}
+
+// 鏃堕棿鎴宠浆鎹负姣
+int64_t CPageGlassList::timePointToMs(const std::chrono::system_clock::time_point& tp)
+{
+    return std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch()).count();
+}
+
+// 鐢熸垚妯℃嫙鐨凷VData鐢ㄤ簬娴嬭瘯
+void CPageGlassList::GenerateMockSVData(SERVO::CGlass& glass)
+{
+    // 鑾峰彇璁惧鏁版嵁绫诲瀷閰嶇疆
+    auto& dataTypes = SERVO::CServoUtilsTool::getEqDataTypes();
+    
+    // 涓烘瘡涓澶囩敓鎴愭ā鎷熸暟鎹�
+    for (const auto& machinePair : dataTypes) {
+        int machineId = machinePair.first;
+        const auto& dataTypeList = machinePair.second;
+        std::vector<std::string> filteredTypes;
+
+        if (machineId == EQ_ID_VACUUMBAKE || machineId == EQ_ID_BAKE_COOLING) {
+            const char activePrefix = 'A';
+            for (const auto& dataType : dataTypeList) {
+                if (!dataType.empty() && dataType[0] == activePrefix) {
+                    filteredTypes.push_back(dataType);
+                }
+            }
+        }
+
+        const auto& typeList = filteredTypes.empty() ? dataTypeList : filteredTypes;
+        
+        // 鐢熸垚鏃堕棿搴忓垪锛氫粠褰撳墠鏃堕棿寰�鍓嶆帹10鍒嗛挓锛屾瘡1绉掍竴涓暟鎹偣
+        auto now = std::chrono::system_clock::now();
+        auto startTime = now - std::chrono::minutes(10);
+        
+        // 涓烘瘡涓暟鎹被鍨嬬敓鎴愭ā鎷熸暟鎹�
+        for (const auto& dataType : typeList) {
+            std::vector<SERVO::SVDataItem> mockData;
+            
+            // 鐢熸垚600涓暟鎹偣锛�10鍒嗛挓 * 60涓偣/鍒嗛挓锛�
+            for (int i = 0; i < 600; ++i) {
+                auto timestamp = startTime + std::chrono::seconds(i * 1);
+                
+                // 鏍规嵁璁惧绫诲瀷鍜屾暟鎹被鍨嬬敓鎴愪笉鍚岀殑妯℃嫙鍊�
+                double value = GenerateMockValue(machineId, dataType, i);
+                
+                mockData.emplace_back(timestamp, value);
+            }
+            
+            // 灏嗘ā鎷熸暟鎹坊鍔犲埌glass瀵硅薄涓�
+            glass.addSVData(machineId, dataType, mockData);
+        }
+    }
+}
+
+// 鏍规嵁璁惧绫诲瀷鍜屾暟鎹被鍨嬬敓鎴愭ā鎷熸暟鍊�
+double CPageGlassList::GenerateMockValue(int machineId, const std::string& dataType, int index)
+{
+    // 鍩虹鍊艰寖鍥�
+    double baseValue = 0.0;
+    double variation = 0.0;
+    
+    // 鏍规嵁璁惧绫诲瀷璁剧疆鍩虹鍊�
+    switch (machineId) {
+        case EQ_ID_Bonder1:
+        case EQ_ID_Bonder2:
+            if (dataType.find("鍘嬪姏") != std::string::npos) {
+                baseValue = 50.0;  // 鍘嬪姏鍩虹鍊�
+                variation = 10.0;  // 鍘嬪姏鍙樺寲鑼冨洿
+            } else if (dataType.find("娓╁害") != std::string::npos) {
+                baseValue = 180.0; // 娓╁害鍩虹鍊�
+                variation = 5.0;   // 娓╁害鍙樺寲鑼冨洿
+            } else if (dataType.find("鎵╁睍鍊�") != std::string::npos) {
+                baseValue = 100.0; // 鎵╁睍鍊煎熀纭�鍊�
+                variation = 15.0;  // 鎵╁睍鍊煎彉鍖栬寖鍥�
+            }
+            break;
+            
+        case EQ_ID_VACUUMBAKE:
+            if (dataType.find("鎵╁睍鍊�") != std::string::npos) {
+                baseValue = 80.0;
+                variation = 12.0;
+            } else if (dataType.find("娓╁害") != std::string::npos) {
+                baseValue = 200.0;
+                variation = 8.0;
+            }
+            break;
+            
+        case EQ_ID_BAKE_COOLING:
+            if (dataType.find("娓╁害") != std::string::npos) {
+                baseValue = 25.0;  // 鍐峰嵈娓╁害
+                variation = 3.0;
+            }
+            break;
+            
+        default:
+            baseValue = 50.0;
+            variation = 5.0;
+            break;
+    }
+    
+    // 娣诲姞鏃堕棿鐩稿叧鐨勮秼鍔垮拰闅忔満鍙樺寲
+    double timeTrend = sin(index * 0.1) * 2.0;  // 姝e鸡娉㈣秼鍔�
+    double randomNoise = (rand() % 100 - 50) / 100.0 * variation * 0.3;  // 闅忔満鍣0
+    
+    return baseValue + timeTrend + randomNoise;
+}
\ No newline at end of file

--
Gitblit v1.9.3