From 829fe6c6bc33d53fda9c31fd45a37e1df87befff Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期五, 30 一月 2026 11:16:24 +0800
Subject: [PATCH] Merge branch 'clh' into liuyang
---
SourceCode/Bond/Servo/CPageGlassList.cpp | 953 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 861 insertions(+), 92 deletions(-)
diff --git a/SourceCode/Bond/Servo/CPageGlassList.cpp b/SourceCode/Bond/Servo/CPageGlassList.cpp
index 62a83f6..29b3b23 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>
@@ -340,6 +344,88 @@
}
}
+bool CopyUtf8ToClipboard(const std::string& utf8)
+{
+ // 1) UTF-8 -> UTF-16 闀垮害锛堝惈缁撳熬 '\0'锛�
+ int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, nullptr, 0);
+ if (wlen <= 0) return false;
+
+ // 2) 涓哄壀璐存澘鍒嗛厤鍏ㄥ眬鍙Щ鍔ㄥ唴瀛橈紙蹇呴』 GMEM_MOVEABLE锛�
+ SIZE_T bytes = static_cast<SIZE_T>(wlen) * sizeof(wchar_t);
+ HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, bytes);
+ if (!hMem) return false;
+
+ // 3) 濉厖 UTF-16 鏂囨湰
+ wchar_t* wbuf = static_cast<wchar_t*>(GlobalLock(hMem));
+ if (!wbuf) { GlobalFree(hMem); return false; }
+ MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, wbuf, wlen);
+ GlobalUnlock(hMem);
+
+ // 4) 鎵撳紑鍓创鏉垮苟璁剧疆鏁版嵁锛圕F_UNICODETEXT锛�
+ if (!OpenClipboard(nullptr)) { GlobalFree(hMem); return false; }
+ if (!EmptyClipboard()) { CloseClipboard(); GlobalFree(hMem); return false; }
+
+ // 鎴愬姛鍚庯紝鍐呭瓨鎵�鏈夋潈浜ょ粰鍓创鏉匡紝涓嶈兘鍐� GlobalFree
+ if (!SetClipboardData(CF_UNICODETEXT, hMem)) {
+ CloseClipboard();
+ GlobalFree(hMem);
+ return false;
+ }
+
+ CloseClipboard();
+ 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 瀵硅瘽妗�
IMPLEMENT_DYNAMIC(CPageGlassList, CDialogEx)
@@ -393,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()
// ===== 绉佹湁灏忓伐鍏� =====
@@ -403,7 +490,7 @@
}
// ===== CPageGlassList 娑堟伅澶勭悊绋嬪簭 =====
-void CPageGlassList::InitRxWindow()
+void CPageGlassList::InitRxWindows()
{
// 璁㈤槄鏁版嵁
IRxWindows* pRxWindows = RX_GetRxWindows();
@@ -520,10 +607,10 @@
{
m_rebuilding = true;
- // 鏀惧湪浠讳綍娓呯┖/閲嶅缓鍔ㄤ綔涔嬪墠锛�
+ // 鏀惧湪浠讳綍娓呯┖/閲嶅缓鍔ㄤ綔涔嬪墠锛氳褰曞睍寮�鐨勭埗鑺傜偣 key锛圕lassID锛�
auto expandedKeys = SnapshotExpandedKeys(m_listCtrl);
- // 鈥斺�� 鍙屼繚闄╋細鍏堟竻鎺夊彲瑙侀」锛屽啀娓呮爲缁撴瀯 鈥斺��
+ // 鈥斺�� 鍙屼繚闄╋細鍏堟竻鎺夊彲瑙侀」锛屽啀娓呮爲缁撴瀯 鈥斺��
m_listCtrl.SetRedraw(FALSE);
m_listCtrl.DeleteAllItems();
m_listCtrl.SetRedraw(TRUE);
@@ -532,7 +619,7 @@
m_listCtrl.ClearTree();
const int colCount = m_listCtrl.GetHeaderCtrl() ? m_listCtrl.GetHeaderCtrl()->GetItemCount() : 0;
- if (colCount <= 0) return;
+ if (colCount <= 0) { m_rebuilding = false; return; }
// ==================== 1) WIP锛氫粎绗� 1 椤垫瀯寤猴紝涓旀斁鍦ㄦ渶椤堕儴 ====================
if (m_nCurPage == 1) {
@@ -551,9 +638,11 @@
SERVO::CGlass* b = g->getBuddy();
if (b) {
+ // 鎸変綘鐨勭害瀹氾細g 鏄埗锛宐uddy 鏄瓙
SERVO::CGlass* parent = g;
SERVO::CGlass* child = b;
+ // parent
std::vector<CString> pcols(colCount);
pcols[1] = _T("");
pcols[2] = std::to_string(parent->getCassetteSequenceNo()).c_str();
@@ -572,6 +661,7 @@
MaybeRestoreExpandByKey(nParent, expandedKeys);
m_listCtrl.SetNodeColor(nParent, kWipText, kWipParentBk); // 鐖讹細鍩虹缁�
+ // child
std::vector<CString> ccols(colCount);
ccols[1] = _T("");
ccols[2] = std::to_string(child->getCassetteSequenceNo()).c_str();
@@ -615,118 +705,375 @@
for (auto* item : tempGlasses) item->release();
}
- // ==================== 2) DB 褰撳墠椤碉紙鏃犺绗嚑椤甸兘鏋勫缓锛涙帓鍦� WIP 涔嬪悗锛� ====================
+ // ==================== 2) DB 褰撳墠椤碉紙涓ら樁娈垫瀯寤猴紝澶勭悊鍗曞悜 buddy锛� ====================
+ const int rawLimit = PAGE_SIZE + 1;
+ const int rawOffset = PAGE_SIZE * (m_nCurPage - 1);
#if USE_FAKE_DB_DEMO
- auto page = _make_page_fake(m_filters, PAGE_SIZE, PAGE_SIZE * (m_nCurPage - 1));
+ auto page = _make_page_fake(m_filters, rawLimit, rawOffset);
#else
auto& db = GlassLogDb::Instance();
- auto page = db.queryPaged(m_filters, PAGE_SIZE, PAGE_SIZE * (m_nCurPage - 1));
+ auto pageFull = db.queryPaged(m_filters, rawLimit, rawOffset);
#endif
- 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;
+#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;
+ };
- std::unordered_set<std::string> usedDb;
+ // 鈽呪槄鈽� 杩欓噷鏄叧閿慨澶嶏細鎺ユ敹鈥渃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 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 (strictPair || loosePair) {
+ lookahead = extra;
+ }
+ // 棰勮涓嶇畻鍏ユ湰椤�
+ pageFull.items.pop_back();
+ }
+
+ // 涔嬪悗姝e父鎸� page 鏋勫缓
+ auto& pageRef = pageFull;
+
+ // 鈥斺�� 寤轰袱涓储寮� 鈥斺�� //
+ // 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);
+ };
- for (size_t i = 0; i < page.items.size(); ++i) {
- const auto& r = page.items[i];
- if (usedDb.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 = (zebra % 2 == 0) ? RGB(255, 255, 255) : RGB(235, 235, 235);
- bool paired = false;
+ // 鍦ㄥ悓椤甸噷涓� r 鎵� buddy 鍊欓��
+ size_t buddyIdx = (size_t)-1;
+ auto itVec = byClass.find(r.buddyId);
+ if (itVec != byClass.end()) {
+ const auto& vec = itVec->second;
- if (!r.buddyId.empty()) {
- auto it = idxById.find(r.buddyId);
- if (it != idxById.end()) {
- const auto& br = page.items[it->second];
- if (!usedDb.count(br.classId)) {
- bool rIsParent = (r.classId <= br.classId);
- const auto& parentRec = rIsParent ? r : br;
- const auto& childRec = rIsParent ? br : r;
-
- std::vector<CString> pcols(colCount);
- pcols[1] = std::to_string(parentRec.id).c_str(); pcols[2] = std::to_string(parentRec.cassetteSeqNo).c_str();
- pcols[3] = std::to_string(parentRec.jobSeqNo).c_str(); pcols[4] = parentRec.classId.c_str();
- pcols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)parentRec.materialType).c_str();
- pcols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)parentRec.state).c_str();
- pcols[7] = parentRec.tStart.c_str(); pcols[8] = parentRec.tEnd.c_str(); pcols[9] = parentRec.buddyId.c_str();
- pcols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)parentRec.aoiResult).c_str();
- pcols[11] = parentRec.path.c_str(); pcols[12] = parentRec.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(childRec.id).c_str(); ccols[2] = std::to_string(childRec.cassetteSeqNo).c_str();
- ccols[3] = std::to_string(childRec.jobSeqNo).c_str(); ccols[4] = childRec.classId.c_str();
- ccols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)childRec.materialType).c_str();
- ccols[6] = SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)childRec.state).c_str();
- ccols[7] = childRec.tStart.c_str(); ccols[8] = childRec.tEnd.c_str(); ccols[9] = childRec.buddyId.c_str();
- ccols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)childRec.aoiResult).c_str();
- ccols[11] = childRec.path.c_str(); ccols[12] = childRec.params.c_str();
-
- auto* nChild = m_listCtrl.InsertChild(nParent, ccols);
- m_listCtrl.SetNodeColor(nChild, RGB(0, 0, 0), bk);
-
- usedDb.insert(parentRec.classId);
- usedDb.insert(childRec.classId);
- paired = true;
+ // 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; }
}
}
}
- if (!paired && !r.buddyId.empty()) {
+ 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[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[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();
+ 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[4] = r.buddyId.c_str(); // 鍗犱綅瀛愯锛氭樉绀� buddy 鐨� classId
+ 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);
- usedDb.insert(r.classId);
- paired = true;
+ consumed.insert(makeKeyR(r));
+ consumed.insert(makeKeyR(br));
+ ++zebra;
+ continue;
}
- if (!paired) {
- 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();
+ // 娌℃壘鍒� 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();
+ 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* n = m_listCtrl.InsertRoot(cols);
- m_listCtrl.SetNodeColor(n, RGB(0, 0, 0), bk);
- usedDb.insert(r.classId);
- }
+ auto* nParent = m_listCtrl.InsertRoot(pcols);
+ MaybeRestoreExpandByKey(nParent, expandedKeys);
+ m_listCtrl.SetNodeColor(nParent, RGB(0, 0, 0), zebraBk(zebra));
+ 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), zebraBk(zebra));
+
+ consumed.insert(makeKeyR(r));
+ ++zebra;
+ }
+
+ // -------- Phase 2: 鍓╀綑鏈秷璐圭殑锛屼綔涓衡�滃崟鏉℃牴琛屸�� ----------
+ 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();
+ 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(r.classId);
+ ++zebra;
+ }
+
+ m_listCtrl.RebuildVisible();
+#endif
+
// 涓婁竴椤� / 涓嬩竴椤�
UpdatePageControls();
m_rebuilding = false;
}
+
void CPageGlassList::UpdatePageControls()
{
@@ -741,9 +1088,10 @@
{
CDialogEx::OnInitDialog();
- // 瀹氭椂鍣細1=鍒濆鍖栬闃咃紝2=鍛ㄦ湡鍒锋柊锛堝彧澧為噺锛�
+ // 瀹氭椂鍣細1=鍒濆鍖栬闃咃紝2=鍛ㄦ湡鍒锋柊锛堝彧澧為噺锛夛紝3=寤惰繜鍔犺浇棣栧睆鏁版嵁
SetTimer(1, 3000, nullptr);
SetTimer(2, 2000, nullptr);
+ SetTimer(3, 10, nullptr);
// 涓嬫媺妗嗘帶浠�
InitStatusCombo();
@@ -768,8 +1116,8 @@
CString headers[] = {
_T(""),
_T("id"),
- _T("Cassette Sequence No"),
- _T("Job Sequence No"),
+ _T("Cassette SN"),
+ _T("Job SN"),
_T("Class ID"),
_T("鐗╂枡绫诲瀷"),
_T("鐘舵��"),
@@ -793,7 +1141,6 @@
m_listCtrl.SetPopupFullTextColumns({ 11, 12 });
Resize();
- OnBnClickedButtonSearch(); // 瑙﹀彂涓�娆℃煡璇笌棣栧睆濉厖
return TRUE; // return TRUE unless you set the focus to a control
}
@@ -848,10 +1195,14 @@
{
if (nIDEvent == 1) {
KillTimer(1);
- InitRxWindow();
+ InitRxWindows();
}
else if (nIDEvent == 2) {
UpdateWipData(); // 鍙仛澧為噺锛屼笉閲嶅缓
+ }
+ else if (nIDEvent == 3) {
+ KillTimer(3);
+ OnBnClickedButtonSearch(); // 寤惰繜棣栧睆鏌ヨ锛岄伩鍏嶅崱浣� OnInitDialog
}
CDialogEx::OnTimer(nIDEvent);
@@ -882,6 +1233,8 @@
void CPageGlassList::OnBnClickedButtonSearch()
{
+ CWaitCursor wait; // 鏄剧ず绛夊緟鍏夋爣锛屾彁绀烘鍦ㄥ姞杞�
+
// 鑾峰彇鍏抽敭瀛楄緭鍏ユ鍐呭
CString strKeyword;
GetDlgItemText(IDC_EDIT_KEYWORD, strKeyword);
@@ -947,6 +1300,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) {
@@ -967,10 +1578,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;
}
@@ -1063,7 +1680,7 @@
CExpandableListCtrl::Node* savedTop = nullptr;
// 3) 閫愪釜澶勭悊 WIP锛氬凡瀛樺湪 -> 灏卞湴鏇存柊锛涘繀瑕佹椂鈥滃彧瀵规牴琛ュ瓙椤光��
- // 涓嶅瓨鍦� -> 浼樺厛鎸傚埌 buddy 瀹瑰櫒锛涘惁鍒欒Е鍙戞暣椤甸噸寤猴紙鏂版牴淇濇寔椤堕儴锛�
+ // 涓嶅瓨鍦� -> 鎸傚埌 buddy 瀹瑰櫒锛涜嫢 buddy 涓嶅湪鍙琛紝瑙﹀彂鍏ㄩ噺閲嶅缓锛堜繚璇� WIP 椤堕儴锛�
for (auto* g : wipGlasses) {
if (!GlassMatchesFilters(*g, m_filters)) continue;
@@ -1106,7 +1723,7 @@
}
}
- // 鈥斺�� 鍙鈥滄牴鑺傜偣鈥濊ˉ瀛愰」锛屼笖浠呭綋 buddy 灏氭湭鍑虹幇鍦ㄥ彲瑙佽〃锛屼笖鏍逛笅涔熸病鏈夎 buddy 鈥斺��
+ // 鈥斺�� 鍙鈥滄牴鑺傜偣鈥濊ˉ瀛愰」 鈥斺��
SERVO::CGlass* b = g->getBuddy();
if (b) {
auto itRoot = wipRootById.find(cid);
@@ -1128,7 +1745,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()) ||
@@ -1171,10 +1788,9 @@
}
}
}
- // 鑻ュ綋鍓嶆槸鈥滃瓙鑺傜偣鈥濓紝涓嶅湪杩欓噷璋冩暣鐖跺瓙鍏崇郴锛涜鈥滃叧绯诲彉鍖栤�濊蛋鍏ㄩ噺閲嶅缓
}
else {
- // 娌℃湁 buddy锛氬鏋滃鍣ㄤ笅鐜板湪鏈夊瓙锛屼篃绠楀叧绯诲彉鍖栵紝瑙﹀彂閲嶅缓
+ // 娌� buddy 浣嗗鍣ㄤ笅鏈夊瓙 -> 鍏崇郴鍙樺寲锛岃Е鍙戝叏閲忛噸寤�
auto itRoot = wipRootById.find(cid);
if (itRoot != wipRootById.end()) {
CExpandableListCtrl::Node* container = itRoot->second;
@@ -1185,8 +1801,6 @@
}
else {
// (B) 涓嶅瓨鍦細鏂板
- // 鍏堝皾璇曗�滄寕鍒� buddy 鐨勫鍣ㄦ牴鈥濅笅闈紱
- // 鑻� buddy 涓嶅湪褰撳墠鍙琛紝鍒欒Е鍙戝叏閲忛噸寤猴紙淇濊瘉 WIP 椤堕儴锛夈��
SERVO::CGlass* b = g->getBuddy();
CExpandableListCtrl::Node* container = nullptr;
@@ -1204,7 +1818,6 @@
}
if (container) {
- // buddy 瀹瑰櫒瀛樺湪锛氭妸 g 浣滀负鈥滃瓙琛屸�濇寕涓婂幓锛堥伩鍏嶉噸澶嶏級
CString cidCs = g->getID().c_str();
if (!NodeHasChildWithClassId(container, cidCs)) {
if (!needRebuildChildren) { CaptureUiState(m_listCtrl, savedSel, savedTop); }
@@ -1297,3 +1910,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;
+}
--
Gitblit v1.9.3