From bc7f1c4e028e69be51079b59dae4ae5c4d43f5bb Mon Sep 17 00:00:00 2001
From: chenluhua1980 <Chenluhua@qq.com>
Date: 星期六, 31 一月 2026 21:54:56 +0800
Subject: [PATCH] 1.状态指示图,目前灰色表示掉线,绿色表示在线。增加Slot的小点表示有没有料,及加工状态 。 2.增加图示
---
SourceCode/Bond/Servo/CPageGlassList.cpp | 2339 +++++++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 1,911 insertions(+), 428 deletions(-)
diff --git a/SourceCode/Bond/Servo/CPageGlassList.cpp b/SourceCode/Bond/Servo/CPageGlassList.cpp
index 1a4cabb..29b3b23 100644
--- a/SourceCode/Bond/Servo/CPageGlassList.cpp
+++ b/SourceCode/Bond/Servo/CPageGlassList.cpp
@@ -9,577 +9,2060 @@
#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)
+
+// WIP 棰滆壊锛氱埗锛堟牴/鏃� buddy锛�= 鍩虹缁匡紱瀛愶紙buddy锛�= 鏇存祬
+static const COLORREF kWipText = RGB(0, 0, 0);
+static const COLORREF kWipParentBk = RGB(201, 228, 180); // 鍩虹缁�
+static const COLORREF kWipChildBk = RGB(221, 241, 208); // 鏇存祬涓�鐐�
+
+// ===== 鏀惧湪 CPageGlassList.cpp 椤堕儴鐨勫尶鍚嶅伐鍏凤紙鏂囦欢鍐呴潤鎬侊級 =====
+// 鎶婂綋鍓嶁�滃凡灞曞紑鈥濈殑鐖惰锛岀敤瀹冧滑鐨� classId锛堢4鍒楁枃鏈級鍋� key 璁板綍涓嬫潵
+static std::unordered_set<std::string> SnapshotExpandedKeys(CExpandableListCtrl& lv) {
+ std::unordered_set<std::string> keys;
+ for (int i = 0; i < lv.GetItemCount(); ++i) {
+ auto* n = lv.GetNodeByVisibleIndex(i);
+ if (!n || n->children.empty() || !n->expanded) continue;
+ if ((int)n->cols.size() > 4) {
+#ifdef _UNICODE
+ keys.insert(CT2A(n->cols[4]));
+#else
+ keys.insert(n->cols[4].GetString());
+#endif
+ }
+ }
+ return keys;
+}
+
+// 鏍规嵁蹇収鎭㈠灞曞紑鐘舵�侊紙鍦ㄤ綘鏂板缓瀹屾瘡涓�滅埗鑺傜偣鈥濇椂璋冪敤涓�娆★級
+static void MaybeRestoreExpandByKey(CExpandableListCtrl::Node* n,
+ const std::unordered_set<std::string>& keys) {
+ if (!n || (int)n->cols.size() <= 4) return;
+#ifdef _UNICODE
+ std::string k = CT2A(n->cols[4]);
+#else
+ std::string k = n->cols[4].GetString();
+#endif
+ if (keys.find(k) != keys.end())
+ n->expanded = true;
+}
+
+static void CaptureUiState(CExpandableListCtrl& lv,
+ std::vector<CExpandableListCtrl::Node*>& outSel,
+ CExpandableListCtrl::Node*& outTopNode)
+{
+ outSel.clear(); outTopNode = nullptr;
+ const int top = lv.GetTopIndex();
+ if (top >= 0 && top < lv.GetItemCount())
+ outTopNode = lv.GetNodeByVisibleIndex(top);
+ for (int i = 0; i < lv.GetItemCount(); ++i) {
+ if ((lv.GetItemState(i, LVIS_SELECTED) & LVIS_SELECTED) != 0) {
+ auto* n = lv.GetNodeByVisibleIndex(i);
+ if (n) outSel.push_back(n);
+ }
+ }
+}
+static void RestoreUiState(CExpandableListCtrl& lv,
+ const std::vector<CExpandableListCtrl::Node*>& sel,
+ CExpandableListCtrl::Node* topNode)
+{
+ // 娓呮帀鐜版湁閫夋嫨
+ for (int i = 0; i < lv.GetItemCount(); ++i)
+ lv.SetItemState(i, 0, LVIS_SELECTED);
+
+ // 鎭㈠閫夋嫨
+ for (auto* n : sel) {
+ for (int i = 0; i < lv.GetItemCount(); ++i) {
+ if (lv.GetNodeByVisibleIndex(i) == n) {
+ lv.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);
+ break;
+ }
+ }
+ }
+ // 灏介噺鎶婁箣鍓嶇殑椤惰婊氬洖鍙
+ if (topNode) {
+ for (int i = 0; i < lv.GetItemCount(); ++i) {
+ if (lv.GetNodeByVisibleIndex(i) == topNode) {
+ lv.EnsureVisible(i, FALSE);
+ break;
+ }
+ }
+ }
+}
+
+// ====== 寮�鍏筹細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>
+#include <atlconv.h> // CStringA
+#include <initializer_list>
+#include <string>
+#include <vector>
+
+// ---- 妯℃嫙璁板綍/鍒嗛〉缁撴瀯锛堝瓧娈典笌浣犵幇鏈変唬鐮佷竴鑷达級----
+struct FakeDbRecord {
+ int id;
+ int cassetteSeqNo;
+ int jobSeqNo;
+ std::string classId;
+ int materialType;
+ int state;
+ std::string tStart;
+ std::string tEnd;
+ std::string buddyId;
+ int aoiResult;
+ std::string path;
+ std::string params;
+};
+struct FakeDbPage { std::vector<FakeDbRecord> items; };
+
+// ---- CString -> std::string锛圓NSI锛屾湰鍦颁唬鐮侀〉锛涗粎鐢ㄤ簬娴嬭瘯妯℃嫙锛�----
+static std::string toAnsi(const CString& s) {
+#ifdef _UNICODE
+ CStringA a(s);
+ return std::string(a.GetString());
+#else
+ return std::string(s.GetString());
+#endif
+}
+
+// ---- 瀹夊叏鎷兼帴宸ュ叿锛氫笉浣跨敤杩愮畻绗� +锛堥伩鍏嶉噸杞�/杞崲闂锛�----
+static std::string sjoin(std::initializer_list<std::string> parts) {
+ std::string out;
+ size_t total = 0; for (const auto& p : parts) total += p.size();
+ out.reserve(total);
+ for (const auto& p : parts) out.append(p);
+ return out;
+}
+
+// ---- 鏃堕棿鏍煎紡宸ュ叿锛歯ow + days/minutes 鍋忕Щ ----
+static std::string _fmt_time(int daysOff, int minutesOff) {
+ using namespace std::chrono;
+ auto now = system_clock::now() + hours(24 * daysOff) + minutes(minutesOff);
+ std::time_t tt = system_clock::to_time_t(now);
+ std::tm tm{};
+#ifdef _WIN32
+ localtime_s(&tm, &tt);
+#else
+ tm = *std::localtime(&tt);
+#endif
+ char buf[32];
+ std::snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+ return std::string(buf);
+}
+
+// ---- 閫犲叏閲忓亣鏁版嵁锛堝惈鍚岄〉閰嶅/璺ㄩ〉閰嶅/鍗曟潯锛�----
+static void _make_all_fake(std::vector<FakeDbRecord>& outAll) {
+ outAll.clear();
+ int id = 1000;
+
+ // ===== 鍏堥�犲嚑鏉♀�滄病鏈� Buddy鈥濈殑璁板綍锛堜繚璇佸嚭鐜板湪绗� 1 椤靛紑澶达級=====
+ for (int n = 1; n <= 4; ++n) {
+ CString cid; cid.Format(_T("NB%03d"), n);
+ outAll.push_back(FakeDbRecord{
+ id++, 700 + n, 800 + n, toAnsi(cid),
+ n % 3, n % 5,
+ _fmt_time(0, -n * 5), // 寮�濮嬫椂闂寸◢鏃╀竴鐐�
+ _fmt_time(0, -n * 5 + 1),
+ std::string(), // buddyId 涓虹┖
+ n % 4,
+ sjoin({ "path/", toAnsi(cid) }),
+ sjoin({ "{\"noBuddy\":", std::to_string(n), "}" })
+ });
+ }
+
+ // ===== 閫犻厤瀵规暟鎹殑宸ュ叿 =====
+ auto mkPair = [&](int k, bool crossPage) {
+ // 浜掍负 buddy 鐨勪袱鏉�
+ CString a; a.Format(_T("G%04dA"), k);
+ CString b; b.Format(_T("G%04dB"), k);
+
+ FakeDbRecord A{
+ id++, 100 + k, 200 + k, toAnsi(a),
+ k % 3, k % 5, _fmt_time(0, k * 3), _fmt_time(0, k * 3 + 2),
+ toAnsi(b), k % 4,
+ sjoin({ "path/", toAnsi(a) }),
+ sjoin({ "{\"k\":\"", toAnsi(a), "\"}" })
+ };
+ FakeDbRecord B{
+ id++, 110 + k, 210 + k, toAnsi(b),
+ (k + 1) % 3, (k + 2) % 5, _fmt_time(0, k * 3 + 1), _fmt_time(0, k * 3 + 4),
+ toAnsi(a), (k + 1) % 4,
+ sjoin({ "path/", toAnsi(b) }),
+ sjoin({ "{\"k\":\"", toAnsi(b), "\"}" })
+ };
+
+ if (crossPage) {
+ // 鍏堟斁 A锛屽啀鎻� 3 鏉♀�滃崟鏉♀�濇妸 B 鎸ゅ埌鍚庨〉锛屾渶鍚庢斁 B
+ outAll.push_back(A);
+ for (int s = 0; s < 3; ++s) {
+ CString sid; sid.Format(_T("S%04d_%d"), k, s);
+ outAll.push_back(FakeDbRecord{
+ id++, 300 + k * 10 + s, 400 + k * 10 + s, toAnsi(sid),
+ (k + s) % 3, (k + s) % 5, _fmt_time(0, k * 2 + s), _fmt_time(0, k * 2 + s + 1),
+ std::string(), (k + s) % 4,
+ sjoin({ "path/", toAnsi(sid) }),
+ sjoin({ "{\"single\":", std::to_string(s), "}" })
+ });
+ }
+ outAll.push_back(B);
+ }
+ else {
+ // 鍚岄〉绱ф尐鐫�
+ outAll.push_back(A);
+ outAll.push_back(B);
+ }
+ };
+
+ // ===== 鐒跺悗鎸夊師閫昏緫杩藉姞锛氬悓椤甸厤瀵� / 璺ㄩ〉閰嶅 / 鍗曟潯 =====
+ // 6 缁勫悓椤甸厤瀵癸紙12 鏉★級
+ for (int k = 1; k <= 6; ++k) mkPair(k, false);
+ // 4 缁勮法椤甸厤瀵癸紙姣忕粍涓棿鎻� 3 鏉♀�滃崟鏉♀�濓級
+ for (int k = 101; k <= 104; ++k) mkPair(k, true);
+ // 鑻ュ共鈥滃崟鏉♀��
+ for (int u = 201; u < 806; ++u) {
+ CString cid; cid.Format(_T("U%04d"), u);
+ outAll.push_back(FakeDbRecord{
+ id++, 500 + u, 600 + u, toAnsi(cid),
+ u % 3, u % 5, _fmt_time(0, u % 17), _fmt_time(0, (u % 17) + 1),
+ std::string(), u % 4,
+ sjoin({ "path/", toAnsi(cid) }),
+ sjoin({ "{\"u\":", std::to_string(u), "}" })
+ });
+ }
+}
-#define PAGE_SIZE 10
-#define PAGE_BACKGROUND_COLOR RGB(252, 252, 255)
+// ---- 鍋氬垎椤靛垏鐗囷紙鍙寜闇�鍔犳洿涓ユ牸鐨� filters锛�----
+static FakeDbPage _make_page_fake(const GlassLogDb::Filters& /*f*/, int pageSize, int offset) {
+ std::vector<FakeDbRecord> all;
+ _make_all_fake(all);
+
+ FakeDbPage page;
+ int n = (int)all.size();
+ int beg = min(max(0, offset), n);
+ int end = min(beg + max(0, pageSize), n);
+ page.items.insert(page.items.end(), all.begin() + beg, all.begin() + end);
+ return page;
+}
+static int _fake_total_count() {
+ std::vector<FakeDbRecord> all;
+ _make_all_fake(all);
+ return (int)all.size();
+}
+#endif // USE_FAKE_DB_DEMO
+
+// 鍒ゆ柇鏌� parent 涓嬫槸鍚﹀凡瀛樺湪 classId == cid 鐨勫瓙鑺傜偣锛堝拷鐣ュぇ灏忓啓锛�
+static bool NodeHasChildWithClassId(CExpandableListCtrl::Node* parent, const CString& cid)
+{
+ if (!parent) return false;
+ for (auto& ch : parent->children) {
+ if (ch && ch->cols.size() > 4) {
+ if (ch->cols[4].CompareNoCase(cid) == 0)
+ return true;
+ }
+ }
+ return false;
+}
+
+// 鎶� cols 鍐欏洖鍒版煇涓�琛岋紙浠庣1鍒楀紑濮嬶紱绗�0鍒楁垜浠病鐢級
+static void ApplyColsToRow(CListCtrl& lv, int row, const std::vector<CString>& cols) {
+ int colCount = 0;
+ if (auto* hdr = lv.GetHeaderCtrl()) colCount = hdr->GetItemCount();
+ colCount = min(colCount, (int)cols.size());
+ for (int c = 1; c < colCount; ++c) {
+ lv.SetItemText(row, c, cols[c]);
+ }
+}
+
+// 閫変腑琛岀殑 ClassID 蹇収锛堢敤浜庨噸寤哄悗鎭㈠锛�
+static std::unordered_set<std::string> SnapshotSelectedKeys(CListCtrl& lv) {
+ std::unordered_set<std::string> keys;
+ int n = lv.GetItemCount();
+ for (int i = 0; i < n; ++i) {
+ if ((lv.GetItemState(i, LVIS_SELECTED) & LVIS_SELECTED) == 0) continue;
+ CString cls = lv.GetItemText(i, 4);
+#ifdef _UNICODE
+ keys.insert(CT2A(cls));
+#else
+ keys.insert(cls.GetString());
+#endif
+ }
+ return keys;
+}
+
+// 椤惰锛圱opIndex锛夊搴旂殑 ClassID
+static std::optional<std::string> SnapshotTopKey(CListCtrl& lv) {
+ int top = lv.GetTopIndex();
+ if (top < 0 || top >= lv.GetItemCount()) return std::nullopt;
+ CString cls = lv.GetItemText(top, 4);
+#ifdef _UNICODE
+ return std::optional<std::string>(CT2A(cls));
+#else
+ return std::optional<std::string>(cls.GetString());
+#endif
+}
+
+// 鐢� ClassID 闆嗗悎鎭㈠閫変腑
+static void RestoreSelectionByKeys(CListCtrl& lv, const std::unordered_set<std::string>& keys) {
+ int n = lv.GetItemCount();
+ for (int i = 0; i < n; ++i) lv.SetItemState(i, 0, LVIS_SELECTED);
+ for (int i = 0; i < n; ++i) {
+ CString cls = lv.GetItemText(i, 4);
+#ifdef _UNICODE
+ if (keys.count(CT2A(cls))) lv.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);
+#else
+ if (keys.count(cls.GetString())) lv.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);
+#endif
+ }
+}
+
+// 灏介噺鎶婃煇涓� ClassID 婊氬洖鍙
+static void RestoreTopByKey(CListCtrl& lv, const std::optional<std::string>& key) {
+ if (!key) return;
+ int n = lv.GetItemCount();
+ for (int i = 0; i < n; ++i) {
+ CString cls = lv.GetItemText(i, 4);
+#ifdef _UNICODE
+ if (CT2A(cls) == *key) { lv.EnsureVisible(i, FALSE); break; }
+#else
+ if (cls.GetString() == *key) { lv.EnsureVisible(i, FALSE); break; }
+#endif
+ }
+}
+
+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)
CPageGlassList::CPageGlassList(CWnd* pParent /*=nullptr*/)
- : CDialogEx(IDD_PAGE_GLASS_LIST, pParent)
+ : CDialogEx(IDD_PAGE_GLASS_LIST, pParent)
{
- m_crBkgnd = PAGE_BACKGROUND_COLOR;
- m_hbrBkgnd = nullptr;
- m_pObserver = nullptr;
+ m_crBkgnd = PAGE_BACKGROUND_COLOR;
+ m_hbrBkgnd = nullptr;
+ m_pObserver = nullptr;
- m_strStatus = "";
- m_nCurPage = 0;
- m_nTotalPages = 1;
+ m_strStatus = "";
+ m_nCurPage = 1;
+ m_nTotalPages = 1;
- memset(m_szTimeStart, 0, sizeof(m_szTimeStart));
- memset(m_szTimeEnd, 0, sizeof(m_szTimeEnd));
- m_szTimeStart[0] = '\0';
- m_szTimeEnd[0] = '\0';
+ memset(m_szTimeStart, 0, sizeof(m_szTimeStart));
+ memset(m_szTimeEnd, 0, sizeof(m_szTimeEnd));
+ m_szTimeStart[0] = '\0';
+ m_szTimeEnd[0] = '\0';
}
CPageGlassList::~CPageGlassList()
{
- if (m_hbrBkgnd != nullptr) {
- ::DeleteObject(m_hbrBkgnd);
- }
- if (m_pObserver != nullptr) {
- m_pObserver->unsubscribe();
- m_pObserver = nullptr;
- }
+ if (m_hbrBkgnd != nullptr) {
+ ::DeleteObject(m_hbrBkgnd);
+ m_hbrBkgnd = nullptr;
+ }
+ if (m_pObserver != nullptr) {
+ m_pObserver->unsubscribe();
+ m_pObserver = nullptr;
+ }
}
void CPageGlassList::DoDataExchange(CDataExchange* pDX)
{
- CDialogEx::DoDataExchange(pDX);
- DDX_Control(pDX, IDC_DATETIMEPICKER_START, m_dateTimeStart);
- DDX_Control(pDX, IDC_DATETIMEPICKER_END, m_dateTimeEnd);
- DDX_Control(pDX, IDC_LIST_ALARM, m_listCtrl);
+ CDialogEx::DoDataExchange(pDX);
+ DDX_Control(pDX, IDC_DATETIMEPICKER_START, m_dateTimeStart);
+ DDX_Control(pDX, IDC_DATETIMEPICKER_END, m_dateTimeEnd);
+ DDX_Control(pDX, IDC_LIST_ALARM, m_listCtrl);
}
-
BEGIN_MESSAGE_MAP(CPageGlassList, CDialogEx)
- ON_WM_CTLCOLOR()
- ON_WM_DESTROY()
- ON_WM_SIZE()
- ON_WM_TIMER()
- ON_CBN_SELCHANGE(IDC_COMBO_DATETIME, &CPageGlassList::OnCbnSelchangeComboDatetime)
- ON_CBN_SELCHANGE(IDC_COMBO_STATUS_FILTER, &CPageGlassList::OnCbnSelchangeComboStatusFilter)
- ON_BN_CLICKED(IDC_BUTTON_SEARCH, &CPageGlassList::OnBnClickedButtonSearch)
- ON_BN_CLICKED(IDC_BUTTON_EXPORT, &CPageGlassList::OnBnClickedButtonExport)
- ON_BN_CLICKED(IDC_BUTTON_PREV_PAGE, &CPageGlassList::OnBnClickedButtonPrevPage)
- ON_BN_CLICKED(IDC_BUTTON_NEXT_PAGE, &CPageGlassList::OnBnClickedButtonNextPage)
+ ON_WM_CTLCOLOR()
+ ON_WM_DESTROY()
+ ON_WM_SIZE()
+ ON_WM_TIMER()
+ ON_CBN_SELCHANGE(IDC_COMBO_DATETIME, &CPageGlassList::OnCbnSelchangeComboDatetime)
+ ON_CBN_SELCHANGE(IDC_COMBO_STATUS_FILTER, &CPageGlassList::OnCbnSelchangeComboStatusFilter)
+ ON_BN_CLICKED(IDC_BUTTON_SEARCH, &CPageGlassList::OnBnClickedButtonSearch)
+ ON_BN_CLICKED(IDC_BUTTON_EXPORT, &CPageGlassList::OnBnClickedButtonExport)
+ 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()
-
-// CPageGlassList 娑堟伅澶勭悊绋嬪簭
-void CPageGlassList::InitRxWindow()
+// ===== 绉佹湁灏忓伐鍏� =====
+static int GetColumnCount(CListCtrl& lv)
{
- /* code */
- // 璁㈤槄鏁版嵁
- IRxWindows* pRxWindows = RX_GetRxWindows();
- pRxWindows->enableLog(5);
- if (m_pObserver == NULL) {
- m_pObserver = pRxWindows->allocObserver([&](IAny* pAny) -> void {
- // onNext
- pAny->addRef();
- int code = pAny->getCode();
+ CHeaderCtrl* pHdr = lv.GetHeaderCtrl();
+ return pHdr ? pHdr->GetItemCount() : 0;
+}
- if (RX_CODE_EQ_ROBOT_TASK == code) {
- UpdatePageData();
- }
+// ===== CPageGlassList 娑堟伅澶勭悊绋嬪簭 =====
+void CPageGlassList::InitRxWindows()
+{
+ // 璁㈤槄鏁版嵁
+ IRxWindows* pRxWindows = RX_GetRxWindows();
+ pRxWindows->enableLog(5);
+ if (m_pObserver == NULL) {
+ m_pObserver = pRxWindows->allocObserver([&](IAny* pAny) -> void {
+ // onNext
+ pAny->addRef();
+ int code = pAny->getCode();
- pAny->release();
- }, [&]() -> void {
- // onComplete
- }, [&](IThrowable* pThrowable) -> void {
- // onErrorm
- pThrowable->printf();
- });
+ if (RX_CODE_EQ_ROBOT_TASK == code) {
+ UpdateWipData(); // 鍙洿鏂帮紝涓嶉噸寤猴紝涓嶆敼鍙樺睍寮�/閫夋嫨
+ }
- theApp.m_model.getObservable()->observeOn(pRxWindows->mainThread())->subscribe(m_pObserver);
- }
+ pAny->release();
+ }, [&]() -> void {
+ // onComplete
+ }, [&](IThrowable* pThrowable) -> void {
+ // onError
+ pThrowable->printf();
+ });
+
+ theApp.m_model.getObservable()->observeOn(pRxWindows->mainThread())->subscribe(m_pObserver);
+ }
}
void CPageGlassList::Resize()
{
- CRect rcClient;
- GetClientRect(&rcClient);
+ CRect rcClient;
+ GetClientRect(&rcClient);
- // ===== 甯搁噺瀹氫箟 =====
- const int nLeft = 12;
- const int nRight = 12;
- const int nTop = 58;
- const int nButtonHeight = 28;
- const int nButtonMarginBottom = 12;
- const int nSpacing = 8;
- const int nButtonWidth = 80;
- const int nLabelWidth = 100;
+ // ===== 甯搁噺瀹氫箟 =====
+ const int nLeft = 12;
+ const int nRight = 12;
+ const int nTop = 58;
+ const int nButtonHeight = 28;
+ const int nButtonMarginBottom = 12;
+ const int nSpacing = 8;
+ const int nButtonWidth = 80;
+ const int nLabelWidth = 100;
- // ===== 鍒嗛〉鎺т欢甯冨眬 =====
- int yBottom = rcClient.bottom - nButtonMarginBottom - nButtonHeight;
- int xRight = rcClient.Width() - nRight;
+ // ===== 鍒嗛〉鎺т欢甯冨眬 =====
+ int yBottom = rcClient.bottom - nButtonMarginBottom - nButtonHeight;
+ int xRight = rcClient.Width() - nRight;
- CWnd* pBtnNext = GetDlgItem(IDC_BUTTON_NEXT_PAGE);
- CWnd* pBtnPrev = GetDlgItem(IDC_BUTTON_PREV_PAGE);
- CWnd* pLabelPage = GetDlgItem(IDC_LABEL_PAGE_NUMBER);
+ CWnd* pBtnNext = GetDlgItem(IDC_BUTTON_NEXT_PAGE);
+ CWnd* pBtnPrev = GetDlgItem(IDC_BUTTON_PREV_PAGE);
+ CWnd* pLabelPage = GetDlgItem(IDC_LABEL_PAGE_NUMBER);
- if (pBtnNext && pBtnPrev && pLabelPage) {
- // 鑾峰彇鍒嗛〉鏂囨湰瀹藉害浼扮畻
- //CString strLabel;
- //GetDlgItemText(IDC_LABEL_PAGE_NUMBER, strLabel);
- //if (strLabel.IsEmpty()) {
- // strLabel = _T("绗� 1 / 1 椤�");
- //}
- //int nCharWidth = 8;
- //int nLabelWidth = strLabel.GetLength() * nCharWidth + 20;
+ if (pBtnNext && pBtnPrev && pLabelPage) {
+ pBtnNext->MoveWindow(xRight - nButtonWidth, yBottom, nButtonWidth, nButtonHeight);
+ xRight -= nButtonWidth + nSpacing;
- // 璁剧疆鎸夐挳鍜屾爣绛句綅缃�
- pBtnNext->MoveWindow(xRight - nButtonWidth, yBottom, nButtonWidth, nButtonHeight);
- xRight -= nButtonWidth + nSpacing;
+ pLabelPage->MoveWindow(xRight - nLabelWidth, yBottom, nLabelWidth, nButtonHeight);
+ xRight -= nLabelWidth + nSpacing;
- pLabelPage->MoveWindow(xRight - nLabelWidth, yBottom, nLabelWidth, nButtonHeight);
- xRight -= nLabelWidth + nSpacing;
+ pBtnPrev->MoveWindow(xRight - nButtonWidth, yBottom, nButtonWidth, nButtonHeight);
+ }
- pBtnPrev->MoveWindow(xRight - nButtonWidth, yBottom, nButtonWidth, nButtonHeight);
- }
-
- // ===== 琛ㄦ牸鍖哄煙甯冨眬 =====
- if (nullptr != m_listCtrl.m_hWnd) {
- int listHeight = yBottom - nTop - nSpacing;
- m_listCtrl.MoveWindow(nLeft, nTop, rcClient.Width() - nLeft - nRight, listHeight);
- }
+ // ===== 琛ㄦ牸鍖哄煙甯冨眬 =====
+ if (nullptr != m_listCtrl.m_hWnd) {
+ int listHeight = yBottom - nTop - nSpacing;
+ m_listCtrl.MoveWindow(nLeft, nTop, rcClient.Width() - nLeft - nRight, listHeight);
+ }
}
void CPageGlassList::InitStatusCombo()
{
- CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_STATUS_FILTER);
- if (nullptr != pComboBox) {
- pComboBox->ResetContent();
- pComboBox->AddString(_T("鍏ㄩ儴"));
- pComboBox->AddString(_T("Ready"));
- pComboBox->AddString(_T("Running"));
- pComboBox->AddString(_T("Error"));
- pComboBox->AddString(_T("Abort"));
- pComboBox->AddString(_T("Completed"));
- pComboBox->SetCurSel(0);
- }
+ CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_STATUS_FILTER);
+ if (nullptr != pComboBox) {
+ pComboBox->ResetContent();
+ pComboBox->AddString(_T("鍏ㄩ儴"));
+ pComboBox->AddString(_T("Ready"));
+ pComboBox->AddString(_T("Running"));
+ pComboBox->AddString(_T("Error"));
+ pComboBox->AddString(_T("Abort"));
+ pComboBox->AddString(_T("Completed"));
+ pComboBox->SetCurSel(0);
+ }
}
void CPageGlassList::InitTimeRangeCombo()
{
- CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_DATETIME);
- if (nullptr != pComboBox) {
- pComboBox->ResetContent();
- pComboBox->AddString(_T("涓嶉檺"));
- pComboBox->AddString(_T("浠婂ぉ"));
- pComboBox->AddString(_T("涓冨ぉ鍐�"));
- pComboBox->AddString(_T("鏈湀"));
- pComboBox->AddString(_T("浠婂勾"));
- pComboBox->AddString(_T("鑷畾涔�"));
- pComboBox->SetCurSel(0);
- }
+ CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_DATETIME);
+ if (nullptr != pComboBox) {
+ pComboBox->ResetContent();
+ pComboBox->AddString(_T("涓嶉檺"));
+ pComboBox->AddString(_T("浠婂ぉ"));
+ pComboBox->AddString(_T("涓冨ぉ鍐�"));
+ pComboBox->AddString(_T("鏈湀"));
+ pComboBox->AddString(_T("浠婂勾"));
+ pComboBox->AddString(_T("鑷畾涔�"));
+ pComboBox->SetCurSel(0);
+ }
}
void CPageGlassList::InitDateTimeControls()
{
- if (m_dateTimeStart.m_hWnd == nullptr || m_dateTimeEnd.m_hWnd == nullptr) {
- return;
- }
-
- // 绂佺敤鍒濆鐘舵��
- m_dateTimeStart.EnableWindow(FALSE);
- m_dateTimeEnd.EnableWindow(FALSE);
-
- // 璁剧疆鏍煎紡锛氭樉绀烘棩鏈� + 鏃堕棿
- //m_dateTimeStart.SetFormat(_T("yyyy/MM/dd HH:mm:ss"));
- //m_dateTimeEnd.SetFormat(_T("yyyy/MM/dd HH:mm:ss"));
-
- // 淇敼鏍峰紡浠ユ敮鎸佹椂闂存牸寮�
- //DWORD dwStyleStart = m_dateTimeStart.GetStyle();
- //DWORD dwStyleEnd = m_dateTimeEnd.GetStyle();
-
- //m_dateTimeStart.ModifyStyle(0, DTS_TIMEFORMAT | DTS_UPDOWN);
- //m_dateTimeEnd.ModifyStyle(0, DTS_TIMEFORMAT);
+ if (m_dateTimeStart.m_hWnd == nullptr || m_dateTimeEnd.m_hWnd == nullptr) {
+ return;
+ }
+ // 鑷畾涔夎寖鍥存椂鎵嶅彲缂栬緫
+ m_dateTimeStart.EnableWindow(FALSE);
+ m_dateTimeEnd.EnableWindow(FALSE);
}
void CPageGlassList::LoadData()
{
- m_nCurPage = 1;
- UpdatePageData();
+ m_nCurPage = 1;
+ UpdatePageData();
}
void CPageGlassList::UpdatePageData()
{
- // 濡傛灉涓虹1椤�, 鍙栧嚭缂撳瓨Glass, 绗﹀悎鏉′欢鍒欐樉绀猴紱
- m_listCtrl.DeleteAllItems();
- UpdateWipData();
+ m_rebuilding = true;
+
+ // 鏀惧湪浠讳綍娓呯┖/閲嶅缓鍔ㄤ綔涔嬪墠锛氳褰曞睍寮�鐨勭埗鑺傜偣 key锛圕lassID锛�
+ auto expandedKeys = SnapshotExpandedKeys(m_listCtrl);
+
+ // 鈥斺�� 鍙屼繚闄╋細鍏堟竻鎺夊彲瑙侀」锛屽啀娓呮爲缁撴瀯 鈥斺��
+ m_listCtrl.SetRedraw(FALSE);
+ m_listCtrl.DeleteAllItems();
+ m_listCtrl.SetRedraw(TRUE);
+
+ // 鈥斺�� 娓呯┖鏍戯紙渚濊禆 CExpandableListCtrl::ClearTree()锛夆�斺��
+ m_listCtrl.ClearTree();
+
+ const int colCount = m_listCtrl.GetHeaderCtrl() ? m_listCtrl.GetHeaderCtrl()->GetItemCount() : 0;
+ if (colCount <= 0) { m_rebuilding = false; return; }
+
+ // ==================== 1) WIP锛氫粎绗� 1 椤垫瀯寤猴紝涓旀斁鍦ㄦ渶椤堕儴 ====================
+ if (m_nCurPage == 1) {
+ std::vector<SERVO::CGlass*> wipGlasses;
+ theApp.m_model.m_master.getWipGlasses(wipGlasses);
+ std::vector<SERVO::CGlass*> tempGlasses = wipGlasses; // 寰呴噴鏀�
+
+ auto glassHit = [&](SERVO::CGlass* g) -> bool {
+ return g && GlassMatchesFilters(*g, m_filters);
+ };
+
+ std::unordered_set<SERVO::CGlass*> usedWip;
+
+ for (auto* g : wipGlasses) {
+ if (!glassHit(g) || usedWip.count(g)) continue;
+
+ 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();
+ pcols[3] = std::to_string(parent->getJobSequenceNo()).c_str();
+ pcols[4] = parent->getID().c_str();
+ pcols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText(parent->getType()).c_str();
+ pcols[6] = SERVO::CServoUtilsTool::getGlassStateText(parent->state()).c_str();
+ pcols[7] = CToolUnits::TimePointToLocalString(parent->tStart()).c_str();
+ pcols[8] = CToolUnits::TimePointToLocalString(parent->tEnd()).c_str();
+ pcols[9] = parent->getBuddyId().c_str();
+ pcols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)parent->getAOIInspResult()).c_str();
+ pcols[11] = parent->getPathDescription().c_str();
+ pcols[12] = parent->getParamsDescription().c_str();
+
+ auto* nParent = m_listCtrl.InsertRoot(pcols);
+ 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();
+ ccols[3] = std::to_string(child->getJobSequenceNo()).c_str();
+ ccols[4] = child->getID().c_str();
+ ccols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText(child->getType()).c_str();
+ ccols[6] = SERVO::CServoUtilsTool::getGlassStateText(child->state()).c_str();
+ ccols[7] = CToolUnits::TimePointToLocalString(child->tStart()).c_str();
+ ccols[8] = CToolUnits::TimePointToLocalString(child->tEnd()).c_str();
+ ccols[9] = child->getBuddyId().c_str();
+ ccols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)child->getAOIInspResult()).c_str();
+ ccols[11] = child->getPathDescription().c_str();
+ ccols[12] = child->getParamsDescription().c_str();
+
+ auto* nChild = m_listCtrl.InsertChild(nParent, ccols);
+ m_listCtrl.SetNodeColor(nChild, kWipText, kWipChildBk); // 瀛愶細鏇存祬
+
+ usedWip.insert(parent);
+ usedWip.insert(child);
+ }
+ else {
+ std::vector<CString> cols(colCount);
+ cols[1] = _T("");
+ cols[2] = std::to_string(g->getCassetteSequenceNo()).c_str();
+ cols[3] = std::to_string(g->getJobSequenceNo()).c_str();
+ cols[4] = g->getID().c_str();
+ cols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText(g->getType()).c_str();
+ cols[6] = SERVO::CServoUtilsTool::getGlassStateText(g->state()).c_str();
+ cols[7] = CToolUnits::TimePointToLocalString(g->tStart()).c_str();
+ cols[8] = CToolUnits::TimePointToLocalString(g->tEnd()).c_str();
+ cols[9] = g->getBuddyId().c_str();
+ cols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)g->getAOIInspResult()).c_str();
+ cols[11] = g->getPathDescription().c_str();
+ cols[12] = g->getParamsDescription().c_str();
+
+ auto* n = m_listCtrl.InsertRoot(cols);
+ m_listCtrl.SetNodeColor(n, kWipText, kWipParentBk); // 浠嶇敤鍩虹缁�
+ usedWip.insert(g);
+ }
+ }
+ for (auto* item : tempGlasses) item->release();
+ }
+
+ // ==================== 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, rawLimit, rawOffset);
+#else
+ auto& db = GlassLogDb::Instance();
+ auto pageFull = db.queryPaged(m_filters, rawLimit, rawOffset);
+#endif
+
+#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
+};
- // 鏌ヨ
- auto& db = GlassLogDb::Instance();
- auto page = db.queryPaged(m_filters, PAGE_SIZE, PAGE_SIZE * (m_nCurPage - 1));
- for (const auto& r : page.items) {
- int index = m_listCtrl.InsertItem(m_listCtrl.GetItemCount(), "");
- m_listCtrl.SetItemText(index, 1, std::to_string(r.id).c_str());
- m_listCtrl.SetItemText(index, 2, std::to_string(r.cassetteSeqNo).c_str());
- m_listCtrl.SetItemText(index, 3, std::to_string(r.jobSeqNo).c_str());
- m_listCtrl.SetItemText(index, 4, r.classId.c_str());
- m_listCtrl.SetItemText(index, 5, SERVO::CServoUtilsTool::getMaterialsTypeText((SERVO::MaterialsType)r.materialType).c_str());
- m_listCtrl.SetItemText(index, 6, SERVO::CServoUtilsTool::getGlassStateText((SERVO::GlsState)r.state).c_str());
- m_listCtrl.SetItemText(index, 7, r.tStart.c_str());
- m_listCtrl.SetItemText(index, 8, r.tEnd.c_str());
- m_listCtrl.SetItemText(index, 9, r.buddyId.c_str());
- m_listCtrl.SetItemText(index, 10, SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)r.aoiResult).c_str());
- m_listCtrl.SetItemText(index, 11, r.path.c_str());
- m_listCtrl.SetItemText(index, 12, r.params.c_str());
- m_listCtrl.SetItemColor(index, RGB(0, 0, 0), index % 2 == 0 ? RGB(255, 255, 255) : RGB(235, 235, 235));
+ // 鈥斺�� 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];
- // 娴嬭瘯鍙嶅簭鍒楀寲
- /*
- SERVO::CGlass g2;
- std::string err;
- if (GlassJson::FromString(r.pretty, g2, &err)) {
- AfxMessageBox(r.pretty.c_str());
- }
- */
- }
+ 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);
- // 涓婁竴椤� / 涓嬩竴椤�
- UpdatePageControls();
+ 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);
+ };
+
+ // -------- 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;
+
+ // 鍦ㄥ悓椤甸噷涓� r 鎵� buddy 鍊欓��
+ size_t buddyIdx = (size_t)-1;
+ auto itVec = byClass.find(r.buddyId);
+ if (itVec != byClass.end()) {
+ const auto& vec = itVec->second;
+
+ // 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; }
+ }
+ }
+ }
+
+ 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();
+ 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), 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::UpdateWipData()
-{
- if (m_nCurPage != 1) return;
-
- // 鍙栧嚭缂撳瓨Glass, 绗﹀悎鏉′欢鍒欐樉绀猴紱
- // 浣嗚鍒犻櫎鏃х殑鏁版嵁
- std::vector<SERVO::CGlass*> wipGlasses;
- theApp.m_model.m_master.getWipGlasses(wipGlasses);
- std::vector<SERVO::CGlass*> tempGlasses = wipGlasses;
- int count = m_listCtrl.GetItemCount();
- if (count > 0) {
- for (int i = count - 1; i >= 0; i--) {
- SERVO::CGlass* pGlass = (SERVO::CGlass*)m_listCtrl.GetItemData(i);
- if (eraseGlassInVector(pGlass, wipGlasses)
- && GlassMatchesFilters(*pGlass, m_filters)) {
- // 鏇存柊
- UpdateWipRow(i, pGlass);
- }
- else {
- // 鍒犻櫎
- m_listCtrl.DeleteItem(i);
- }
- }
- }
-
- // 鍓╀笅鐨勫绗﹀彿鎻掑叆
- for (auto* item : wipGlasses) {
- if (GlassMatchesFilters(*item, m_filters)) {
- InsertWipRow(item);
- }
- }
- for (auto* item : tempGlasses) {
- item->release();
- }
-}
void CPageGlassList::UpdatePageControls()
{
- CString strPage;
- strPage.Format(_T("绗� %d / %d 椤�"), m_nCurPage, m_nTotalPages);
- SetDlgItemText(IDC_LABEL_PAGE_NUMBER, strPage);
- GetDlgItem(IDC_BUTTON_PREV_PAGE)->EnableWindow(m_nCurPage > 1);
- GetDlgItem(IDC_BUTTON_NEXT_PAGE)->EnableWindow(m_nCurPage < m_nTotalPages);
+ CString strPage;
+ strPage.Format(_T("绗� %d / %d 椤�"), m_nCurPage, m_nTotalPages);
+ SetDlgItemText(IDC_LABEL_PAGE_NUMBER, strPage);
+ GetDlgItem(IDC_BUTTON_PREV_PAGE)->EnableWindow(m_nCurPage > 1);
+ GetDlgItem(IDC_BUTTON_NEXT_PAGE)->EnableWindow(m_nCurPage < m_nTotalPages);
}
-
-// CPageTransferLog 娑堟伅澶勭悊绋嬪簭
BOOL CPageGlassList::OnInitDialog()
{
- CDialogEx::OnInitDialog();
+ CDialogEx::OnInitDialog();
- // TODO: 鍦ㄦ娣诲姞棰濆鐨勫垵濮嬪寲
- SetTimer(1, 3000, nullptr);
- SetTimer(2, 2000, nullptr);
+ // 瀹氭椂鍣細1=鍒濆鍖栬闃咃紝2=鍛ㄦ湡鍒锋柊锛堝彧澧為噺锛夛紝3=寤惰繜鍔犺浇棣栧睆鏁版嵁
+ SetTimer(1, 3000, nullptr);
+ SetTimer(2, 2000, nullptr);
+ SetTimer(3, 10, nullptr);
- // 涓嬫媺妗嗘帶浠�
- InitStatusCombo();
- InitTimeRangeCombo();
+ // 涓嬫媺妗嗘帶浠�
+ InitStatusCombo();
+ InitTimeRangeCombo();
- // 鏃ユ湡鎺т欢
- InitDateTimeControls();
+ // 鏃ユ湡鎺т欢
+ InitDateTimeControls();
- // 鎶ヨ〃鎺т欢
- CString strIniFile, strItem;
- strIniFile.Format(_T("%s\\configuration.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
+ // 鎶ヨ〃鎺т欢
+ CString strIniFile, strItem;
+ strIniFile.Format(_T("%s\\configuration.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
- DWORD dwStyle = m_listCtrl.GetExtendedStyle();
- dwStyle |= LVS_EX_FULLROWSELECT;
- dwStyle |= LVS_EX_GRIDLINES;
- m_listCtrl.SetExtendedStyle(dwStyle);
+ DWORD dwStyle = m_listCtrl.GetExtendedStyle();
+ dwStyle |= LVS_EX_FULLROWSELECT;
+ dwStyle |= LVS_EX_GRIDLINES;
+ dwStyle |= LVS_EX_DOUBLEBUFFER;
+ m_listCtrl.SetExtendedStyle(dwStyle);
- HIMAGELIST imageList = ImageList_Create(24, 24, ILC_COLOR24, 1, 1);
- ListView_SetImageList(m_listCtrl.GetSafeHwnd(), imageList, LVSIL_SMALL);
+ HIMAGELIST imageList = ImageList_Create(24, 24, ILC_COLOR24, 1, 1);
+ ListView_SetImageList(m_listCtrl.GetSafeHwnd(), imageList, LVSIL_SMALL);
- CString headers[] = {
- _T(""),
- _T("id"),
- _T("Cassette Sequence No"),
- _T("Job Sequence No"),
- _T("Class ID"),
- _T("鐗╂枡绫诲瀷"),
- _T("鐘舵��"),
- _T("宸ヨ壓寮�濮嬫椂闂�"),
- _T("宸ヨ壓缁撴潫鏃堕棿"),
- _T("閭﹀畾Glass ID"),
- _T("AOI妫�娴嬬粨鏋�"),
- _T("璺緞"),
- _T("宸ヨ壓鍙傛暟")
- };
- int widths[] = { 0, 80, 80, 80, 100, 120, 120, 120, 120, 200, 200, 200, 200 };
- for (int i = 0; i < _countof(headers); ++i) {
- strItem.Format(_T("Col_%d_Width"), i);
- widths[i] = GetPrivateProfileInt("GlassListCtrl", strItem, widths[i], strIniFile);
- m_listCtrl.InsertColumn(i, headers[i], i == 0 ? LVCFMT_RIGHT : LVCFMT_LEFT, widths[i]);
- }
+ CString headers[] = {
+ _T(""),
+ _T("id"),
+ _T("Cassette SN"),
+ _T("Job SN"),
+ _T("Class ID"),
+ _T("鐗╂枡绫诲瀷"),
+ _T("鐘舵��"),
+ _T("宸ヨ壓寮�濮嬫椂闂�"),
+ _T("宸ヨ壓缁撴潫鏃堕棿"),
+ _T("閭﹀畾Glass ID"),
+ _T("AOI妫�娴嬬粨鏋�"),
+ _T("璺緞"),
+ _T("宸ヨ壓鍙傛暟")
+ };
+ int widths[] = { 24, 80, 80, 80, 100, 120, 120, 120, 120, 200, 200, 200, 200 };
+ for (int i = 0; i < _countof(headers); ++i) {
+ strItem.Format(_T("Col_%d_Width"), i);
+ int def = widths[i];
+ widths[i] = GetPrivateProfileInt("GlassListCtrl", strItem, def, strIniFile);
+ if (i == 0 && widths[i] < 16) widths[i] = 24; // 璁╀笁瑙掑浘鏍囨湁绌洪棿灞曠ず
+ m_listCtrl.InsertColumn(i, headers[i], i == 0 ? LVCFMT_RIGHT : LVCFMT_LEFT, widths[i]);
+ }
+ // 浜屾鍏滃簳锛岄槻姝� ini 鍐欒繘浜� 0
+ if (m_listCtrl.GetColumnWidth(0) < 16) m_listCtrl.SetColumnWidth(0, 24);
+ m_listCtrl.SetPopupFullTextColumns({ 11, 12 });
- Resize();
- OnBnClickedButtonSearch();
+ Resize();
- return TRUE; // return TRUE unless you set the focus to a control
- // 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+ return TRUE; // return TRUE unless you set the focus to a control
}
HBRUSH CPageGlassList::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
- if (nCtlColor == CTLCOLOR_STATIC) {
- pDC->SetBkColor(m_crBkgnd);
- }
-
- if (m_hbrBkgnd == nullptr) {
- m_hbrBkgnd = CreateSolidBrush(m_crBkgnd);
- }
-
- return m_hbrBkgnd;
+ if (nCtlColor == CTLCOLOR_STATIC) {
+ pDC->SetBkColor(m_crBkgnd);
+ }
+ if (m_hbrBkgnd == nullptr) {
+ m_hbrBkgnd = CreateSolidBrush(m_crBkgnd);
+ }
+ return m_hbrBkgnd;
}
void CPageGlassList::OnDestroy()
{
- CDialogEx::OnDestroy();
- if (m_hbrBkgnd != nullptr) {
- ::DeleteObject(m_hbrBkgnd);
- m_hbrBkgnd = nullptr;
- }
- if (m_pObserver != nullptr) {
- m_pObserver->unsubscribe();
- m_pObserver = nullptr;
- }
+ CDialogEx::OnDestroy();
+ if (m_hbrBkgnd != nullptr) {
+ ::DeleteObject(m_hbrBkgnd);
+ m_hbrBkgnd = nullptr;
+ }
+ if (m_pObserver != nullptr) {
+ m_pObserver->unsubscribe();
+ m_pObserver = nullptr;
+ }
- // 淇濆瓨鍒楀
- CString strIniFile, strItem, strTemp;
- strIniFile.Format(_T("%s\\configuration.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
- CHeaderCtrl* pHeader = m_listCtrl.GetHeaderCtrl();
- for (int i = 0; i < pHeader->GetItemCount(); i++) {
- RECT rect;
- pHeader->GetItemRect(i, &rect);
- strItem.Format(_T("Col_%d_Width"), i);
- strTemp.Format(_T("%d"), rect.right - rect.left);
- WritePrivateProfileString("GlassListCtrl", strItem, strTemp, strIniFile);
- }
+ // 淇濆瓨鍒楀锛堥鍒楀厹搴曪紝閬垮厤鎶� 0 鍐欏洖鍘伙級
+ CString strIniFile, strItem, strTemp;
+ strIniFile.Format(_T("%s\\configuration.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
+ CHeaderCtrl* pHeader = m_listCtrl.GetHeaderCtrl();
+ if (pHeader) {
+ for (int i = 0; i < pHeader->GetItemCount(); i++) {
+ RECT rect;
+ pHeader->GetItemRect(i, &rect);
+ strItem.Format(_T("Col_%d_Width"), i);
+ int w = rect.right - rect.left;
+ if (i == 0 && w < 16) w = 24;
+ strTemp.Format(_T("%d"), w);
+ WritePrivateProfileString("GlassListCtrl", strItem, strTemp, strIniFile);
+ }
+ }
}
void CPageGlassList::OnSize(UINT nType, int cx, int cy)
{
- CDialogEx::OnSize(nType, cx, cy);
- Resize();
+ CDialogEx::OnSize(nType, cx, cy);
+ Resize();
}
void CPageGlassList::OnTimer(UINT_PTR nIDEvent)
{
- if (nIDEvent == 1) {
- KillTimer(1);
- InitRxWindow();
- }
+ if (nIDEvent == 1) {
+ KillTimer(1);
+ InitRxWindows();
+ }
+ else if (nIDEvent == 2) {
+ UpdateWipData(); // 鍙仛澧為噺锛屼笉閲嶅缓
+ }
+ else if (nIDEvent == 3) {
+ KillTimer(3);
+ OnBnClickedButtonSearch(); // 寤惰繜棣栧睆鏌ヨ锛岄伩鍏嶅崱浣� OnInitDialog
+ }
- else if (nIDEvent == 2) {
- UpdateWipData();
- }
-
- CDialogEx::OnTimer(nIDEvent);
+ CDialogEx::OnTimer(nIDEvent);
}
void CPageGlassList::OnCbnSelchangeComboDatetime()
{
- CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_DATETIME);
- int nIndex = pComboBox->GetCurSel();
- int nCount = pComboBox->GetCount();
- m_dateTimeStart.EnableWindow(nIndex == nCount - 1);
- m_dateTimeEnd.EnableWindow(nIndex == nCount - 1);
-
- // 鏇存柊鏃ユ湡杩囨护鍣ㄥ拰椤甸潰鏁版嵁
- // UpdateDateFilter();
- // LoadTransfers();
+ CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_DATETIME);
+ int nIndex = pComboBox->GetCurSel();
+ int nCount = pComboBox->GetCount();
+ m_dateTimeStart.EnableWindow(nIndex == nCount - 1);
+ m_dateTimeEnd.EnableWindow(nIndex == nCount - 1);
}
void CPageGlassList::OnCbnSelchangeComboStatusFilter()
{
- CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_STATUS_FILTER);
- int nIndex = pComboBox->GetCurSel();
- if (nIndex == 0) {
- m_strStatus.clear();
- }
- else {
- CString cstrText;
- pComboBox->GetLBText(nIndex, cstrText);
- m_strStatus = CT2A(cstrText);
- }
- // LoadTransfers();
+ CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_STATUS_FILTER);
+ int nIndex = pComboBox->GetCurSel();
+ if (nIndex == 0) {
+ m_strStatus.clear();
+ }
+ else {
+ CString cstrText;
+ pComboBox->GetLBText(nIndex, cstrText);
+ m_strStatus = CT2A(cstrText);
+ }
}
void CPageGlassList::OnBnClickedButtonSearch()
{
- // 鑾峰彇鍏抽敭瀛楄緭鍏ユ鍐呭
- CString strKeyword;
- GetDlgItemText(IDC_EDIT_KEYWORD, strKeyword);
- m_filters.keyword = CT2A(strKeyword);
+ CWaitCursor wait; // 鏄剧ず绛夊緟鍏夋爣锛屾彁绀烘鍦ㄥ姞杞�
- CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_DATETIME);
- int index = pComboBox->GetCurSel();
- if (index == 0) {
- // 涓嶉檺
- m_filters.tStartFrom = std::nullopt;
- m_filters.tStartTo = std::nullopt;
- }
- else if (index == 1) {
- auto [fromUtc, toUtc] = CToolUnits::CalcQuickRangeUtc(QuickRange::Today);
- m_filters.tStartFrom = fromUtc;
- m_filters.tStartTo = toUtc;
- }
- else if (index == 2) {
- auto [fromUtc, toUtc] = CToolUnits::CalcQuickRangeUtc(QuickRange::Last7Days);
- m_filters.tStartFrom = fromUtc;
- m_filters.tStartTo = toUtc;
- }
- else if (index == 3) {
- auto [fromUtc, toUtc] = CToolUnits::CalcQuickRangeUtc(QuickRange::ThisMonth);
- m_filters.tStartFrom = fromUtc;
- m_filters.tStartTo = toUtc;
- }
- else if (index == 4) {
- auto [fromUtc, toUtc] = CToolUnits::CalcQuickRangeUtc(QuickRange::ThisYear);
- m_filters.tStartFrom = fromUtc;
- m_filters.tStartTo = toUtc;
- }
- else if(index == 5){
- // 鑷畾涔�
- std::chrono::system_clock::time_point tp;
- if (CToolUnits::GetCtrlDateRangeUtc_StartOfDay(m_dateTimeStart, tp)) m_filters.tStartFrom = tp;
- if (CToolUnits::GetCtrlDateRangeUtc_EndOfDay(m_dateTimeEnd, tp)) m_filters.tStartTo = tp;
- }
+ // 鑾峰彇鍏抽敭瀛楄緭鍏ユ鍐呭
+ CString strKeyword;
+ GetDlgItemText(IDC_EDIT_KEYWORD, strKeyword);
+ m_filters.keyword = CT2A(strKeyword);
- auto& db = GlassLogDb::Instance();
- long long total = db.count(m_filters);
- m_nTotalPages = (PAGE_SIZE > 0) ? int((total + PAGE_SIZE - 1) / PAGE_SIZE) : 1;
+ CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_DATETIME);
+ int index = pComboBox->GetCurSel();
+ if (index == 0) {
+ // 涓嶉檺
+ m_filters.tStartFrom = std::nullopt;
+ m_filters.tStartTo = std::nullopt;
+ }
+ else if (index == 1) {
+ auto [fromUtc, toUtc] = CToolUnits::CalcQuickRangeUtc(QuickRange::Today);
+ m_filters.tStartFrom = fromUtc;
+ m_filters.tStartTo = toUtc;
+ }
+ else if (index == 2) {
+ auto [fromUtc, toUtc] = CToolUnits::CalcQuickRangeUtc(QuickRange::Last7Days);
+ m_filters.tStartFrom = fromUtc;
+ m_filters.tStartTo = toUtc;
+ }
+ else if (index == 3) {
+ auto [fromUtc, toUtc] = CToolUnits::CalcQuickRangeUtc(QuickRange::ThisMonth);
+ m_filters.tStartFrom = fromUtc;
+ m_filters.tStartTo = toUtc;
+ }
+ else if (index == 4) {
+ auto [fromUtc, toUtc] = CToolUnits::CalcQuickRangeUtc(QuickRange::ThisYear);
+ m_filters.tStartFrom = fromUtc;
+ m_filters.tStartTo = toUtc;
+ }
+ else if (index == 5) {
+ // 鑷畾涔�
+ std::chrono::system_clock::time_point tp;
+ if (CToolUnits::GetCtrlDateRangeUtc_StartOfDay(m_dateTimeStart, tp)) m_filters.tStartFrom = tp;
+ if (CToolUnits::GetCtrlDateRangeUtc_EndOfDay(m_dateTimeEnd, tp)) m_filters.tStartTo = tp;
+ }
- LoadData();
+#if USE_FAKE_DB_DEMO
+ long long total = _fake_total_count();
+#else
+ auto& db = GlassLogDb::Instance();
+ long long total = db.count(m_filters);
+#endif
+ m_nTotalPages = (PAGE_SIZE > 0) ? int((total + PAGE_SIZE - 1) / PAGE_SIZE) : 1;
+
+ LoadData();
}
void CPageGlassList::OnBnClickedButtonExport()
{
- CFileDialog fileDialog(FALSE, _T("csv"), NULL, OFN_HIDEREADONLY, _T("CSV Files (*.csv)|*.csv||"));
- if (fileDialog.DoModal() != IDOK) {
- return;
- }
+ CFileDialog fileDialog(FALSE, _T("csv"), NULL, OFN_HIDEREADONLY, _T("CSV Files (*.csv)|*.csv||"));
+ if (fileDialog.DoModal() != IDOK) {
+ return;
+ }
- // 瀵煎嚭 CSV锛氬鍑虹鍚� filters 鐨勨�滃叏閮ㄨ褰曗�濓紙涓嶅彈鍒嗛〉闄愬埗锛�
- // 杩斿洖瀵煎嚭鐨勮鏁帮紙涓嶅惈琛ㄥご锛�
- // csvPath锛氱洰鏍囨枃浠惰矾寰勶紙UTF-8锛�
- auto& db = GlassLogDb::Instance();
- std::string csvPath((LPTSTR)(LPCTSTR)fileDialog.GetPathName());
- if (db.exportCsv(csvPath, m_filters) > 0) {
- AfxMessageBox("瀵煎嚭CSV鎴愬姛锛�");
- }
+ // 瀵煎嚭 CSV锛氬鍑虹鍚� filters 鐨勨�滃叏閮ㄨ褰曗�濓紙涓嶅彈鍒嗛〉闄愬埗锛�
+ auto& db = GlassLogDb::Instance();
+ std::string csvPath((LPTSTR)(LPCTSTR)fileDialog.GetPathName());
+ if (db.exportCsv(csvPath, m_filters) > 0) {
+ AfxMessageBox("瀵煎嚭CSV鎴愬姛锛�");
+ }
+}
+
+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) {
- m_nCurPage--;
- UpdatePageData();
- }
+ if (m_nCurPage > 1) {
+ m_nCurPage--;
+ UpdatePageData();
+ }
}
void CPageGlassList::OnBnClickedButtonNextPage()
{
- if (m_nCurPage < m_nTotalPages) {
- m_nCurPage++;
- UpdatePageData();
- }
+ if (m_nCurPage < m_nTotalPages) {
+ m_nCurPage++;
+ UpdatePageData();
+ }
}
+
+void CPageGlassList::OnShowFullText(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ auto* p = reinterpret_cast<NMC_ELC_SHOWFULLTEXT*>(pNMHDR);
+
+ // 瀵硅瘽妗嗘樉绀哄伐鑹哄弬鏁�
+ if (p->iSubItem == 12) {
+ CProcessDataListDlg dlg;
+ dlg.setRawText(p->text);
+ dlg.DoModal();
+ }
+ else {
+ AfxMessageBox(p->text);
+ }
+
+ *pResult = 0;
+}
+
+void CPageGlassList::UpdateWipData()
+{
+ // 鍙湪绗� 1 椤靛埛鏂� WIP锛涘叾瀹冮〉涓嶅姩
+ if (m_nCurPage != 1) return;
+ // 鑻ュ垰濂藉湪 UpdatePageData() 閲嶅缓鏈熼棿锛岃烦杩囪繖杞閲忥紝閬垮厤浜掔浉骞叉壈
+ if (m_rebuilding) return;
+
+ const int colCount = m_listCtrl.GetHeaderCtrl() ? m_listCtrl.GetHeaderCtrl()->GetItemCount() : 0;
+ if (colCount <= 0) return;
+
+ // 1) 鏀堕泦褰撳墠鍙閲岀殑鈥淲IP 琛屸�濓紙绗�1鍒� id 涓虹┖锛�
+ // a) wipRowById锛歝lassId -> (row, node*)锛屾敹闆嗘牴+瀛愶紝渚夸簬鍒ゆ柇鈥渂uddy 鏄惁宸插湪鍙琛ㄤ腑鈥�
+ // b) wipRootById锛歝lassId -> node*锛屼粎鏀堕泦鏍硅妭鐐癸紝渚夸簬鍙鈥滄牴鈥濊ˉ瀛愰」
+ std::unordered_map<std::string, std::pair<int, CExpandableListCtrl::Node*>> wipRowById;
+ std::unordered_map<std::string, CExpandableListCtrl::Node*> wipRootById;
+ for (int row = 0; row < m_listCtrl.GetItemCount(); ++row) {
+ CString idDb = m_listCtrl.GetItemText(row, 1); // 绗�1鍒楁槸 DB id
+ if (!idDb.IsEmpty()) continue; // 鏈� id 鐨勬槸 DB 琛岋紝璺宠繃
+
+ auto* node = m_listCtrl.GetNodeByVisibleIndex(row);
+ CString cls = m_listCtrl.GetItemText(row, 4); // 绗�4鍒� Class ID
+#ifdef _UNICODE
+ std::string key = CT2A(cls);
+#else
+ std::string key = cls.GetString();
+#endif
+ wipRowById[key] = { row, node };
+ if (node && node->parent == nullptr) {
+ wipRootById[key] = node; // 浠呮牴鑺傜偣杩涘叆杩欎釜琛�
+ }
+ }
+
+ // 2) 鎷夊綋鍓� WIP 鍒楄〃
+ std::vector<SERVO::CGlass*> wipGlasses;
+ theApp.m_model.m_master.getWipGlasses(wipGlasses);
+ std::vector<SERVO::CGlass*> tempRetain = wipGlasses; // 绋嶅悗缁熶竴 release
+
+ auto makeColsFromWip = [&](SERVO::CGlass* g) {
+ std::vector<CString> cols(colCount);
+ cols[1] = _T(""); // WIP 娌� DB id
+ cols[2] = std::to_string(g->getCassetteSequenceNo()).c_str();
+ cols[3] = std::to_string(g->getJobSequenceNo()).c_str();
+ cols[4] = g->getID().c_str();
+ cols[5] = SERVO::CServoUtilsTool::getMaterialsTypeText(g->getType()).c_str();
+ cols[6] = SERVO::CServoUtilsTool::getGlassStateText(g->state()).c_str();
+ cols[7] = CToolUnits::TimePointToLocalString(g->tStart()).c_str();
+ cols[8] = CToolUnits::TimePointToLocalString(g->tEnd()).c_str();
+ cols[9] = g->getBuddyId().c_str();
+ cols[10] = SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)g->getAOIInspResult()).c_str();
+ cols[11] = g->getPathDescription().c_str();
+ cols[12] = g->getParamsDescription().c_str();
+ return cols;
+ };
+
+ // 2.1 鏋勫缓鈥滄渶鏂� WIP 閿泦鈥濓紙鍚� buddy锛屼笖鍛戒腑杩囨护锛夛紝鐢ㄤ簬妫�娴嬧�滅己澶�/鍒犻櫎鈥�
+ std::unordered_set<std::string> newWipKeys;
+ for (auto* g : wipGlasses) {
+ if (!GlassMatchesFilters(*g, m_filters)) continue;
+#ifdef _UNICODE
+ newWipKeys.insert(CT2A(CString(g->getID().c_str())));
+#else
+ newWipKeys.insert(g->getID());
+#endif
+ if (auto* b = g->getBuddy()) {
+ if (GlassMatchesFilters(*b, m_filters)) {
+#ifdef _UNICODE
+ newWipKeys.insert(CT2A(CString(b->getID().c_str())));
+#else
+ newWipKeys.insert(b->getID());
+#endif
+ }
+ }
+ }
+
+ bool needRebuildRemoval = false; // WIP 鍙樺皯/娓呯┖锛氶渶瑕佹暣椤甸噸寤�
+ bool needRebuildChildren = false; // 缁撴瀯鍙樺寲锛氭柊澧炲瓙
+ bool needRebuildAllForNewRoot = false; // 鏂板鏍癸紙淇濊瘉 WIP 浠嶅湪椤堕儴锛�
+ std::vector<int> rowsToRedraw; // 浠呮枃鏈彉鍖�
+
+ // 鍙闆嗕腑鏈変絾鏂版暟鎹噷娌℃湁 -> 瑙﹀彂鈥滃垹闄�/鍑忓皯鈥濈殑鏁撮〉閲嶅缓
+ for (const auto& kv : wipRowById) {
+ if (newWipKeys.find(kv.first) == newWipKeys.end()) { needRebuildRemoval = true; break; }
+ }
+
+ // UI 鐘舵�侊紙褰撻渶瑕侀噸寤烘椂浣跨敤锛�
+ std::vector<CExpandableListCtrl::Node*> savedSel;
+ CExpandableListCtrl::Node* savedTop = nullptr;
+
+ // 3) 閫愪釜澶勭悊 WIP锛氬凡瀛樺湪 -> 灏卞湴鏇存柊锛涘繀瑕佹椂鈥滃彧瀵规牴琛ュ瓙椤光��
+ // 涓嶅瓨鍦� -> 鎸傚埌 buddy 瀹瑰櫒锛涜嫢 buddy 涓嶅湪鍙琛紝瑙﹀彂鍏ㄩ噺閲嶅缓锛堜繚璇� WIP 椤堕儴锛�
+ for (auto* g : wipGlasses) {
+ if (!GlassMatchesFilters(*g, m_filters)) continue;
+
+#ifdef _UNICODE
+ std::string cid = CT2A(CString(g->getID().c_str()));
+#else
+ std::string cid = g->getID();
+#endif
+
+ auto itAny = wipRowById.find(cid);
+ if (itAny != wipRowById.end()) {
+ // (A) 宸插瓨鍦細浠呮洿鏂版枃妗� & 閲嶇粯璇ヨ
+ int row = itAny->second.first;
+ m_listCtrl.SetItemText(row, 2, std::to_string(g->getCassetteSequenceNo()).c_str());
+ m_listCtrl.SetItemText(row, 3, std::to_string(g->getJobSequenceNo()).c_str());
+ m_listCtrl.SetItemText(row, 4, g->getID().c_str());
+ m_listCtrl.SetItemText(row, 5, SERVO::CServoUtilsTool::getMaterialsTypeText(g->getType()).c_str());
+ m_listCtrl.SetItemText(row, 6, SERVO::CServoUtilsTool::getGlassStateText(g->state()).c_str());
+ m_listCtrl.SetItemText(row, 7, CToolUnits::TimePointToLocalString(g->tStart()).c_str());
+ m_listCtrl.SetItemText(row, 8, CToolUnits::TimePointToLocalString(g->tEnd()).c_str());
+ m_listCtrl.SetItemText(row, 9, g->getBuddyId().c_str());
+ m_listCtrl.SetItemText(row, 10, SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)g->getAOIInspResult()).c_str());
+ m_listCtrl.SetItemText(row, 11, g->getPathDescription().c_str());
+ m_listCtrl.SetItemText(row, 12, g->getParamsDescription().c_str());
+ rowsToRedraw.push_back(row);
+
+ // 鈥斺�� 椤哄甫鍒锋柊 buddy 瀛愯锛堝鏋滃畠宸插湪鍙琛ㄩ噷锛夆�斺��
+ if (SERVO::CGlass* b = g->getBuddy()) {
+#ifdef _UNICODE
+ std::string bid = CT2A(CString(b->getID().c_str()));
+#else
+ std::string bid = b->getID();
+#endif
+ auto itChildAny = wipRowById.find(bid);
+ if (itChildAny != wipRowById.end()) {
+ int crow = itChildAny->second.first;
+ auto bcols = makeColsFromWip(b);
+ ApplyColsToRow(m_listCtrl, crow, bcols);
+ rowsToRedraw.push_back(crow);
+ }
+ }
+
+ // 鈥斺�� 鍙鈥滄牴鑺傜偣鈥濊ˉ瀛愰」 鈥斺��
+ SERVO::CGlass* b = g->getBuddy();
+ if (b) {
+ auto itRoot = wipRootById.find(cid);
+ if (itRoot != wipRootById.end()) {
+ CExpandableListCtrl::Node* container = itRoot->second;
+
+ CString newBuddyCid = b->getID().c_str();
+#ifdef _UNICODE
+ std::string newBid = CT2A(newBuddyCid);
+#else
+ std::string newBid = newBuddyCid.GetString();
+#endif
+
+ // 鐜版湁瀹瑰櫒涓嬬殑鈥滅涓�涓瓙 classId鈥濓紙濡傛灉鏈夌殑璇濓級
+ CString oldChildCid;
+ if (!container->children.empty() && container->children[0] && container->children[0]->cols.size() > 4)
+ oldChildCid = container->children[0]->cols[4];
+
+ bool buddyExistsAnywhere = (wipRowById.find(newBid) != wipRowById.end());
+ bool hasChildAlready = NodeHasChildWithClassId(container, newBuddyCid);
+
+ // 鍏崇郴鏄惁鍙戠敓鍙樺寲锛�
+ bool relationChanged =
+ (!oldChildCid.IsEmpty() && newBuddyCid.IsEmpty()) ||
+ (oldChildCid.IsEmpty() && !newBuddyCid.IsEmpty()) ||
+ (!oldChildCid.IsEmpty() && !newBuddyCid.IsEmpty() &&
+ oldChildCid.CompareNoCase(newBuddyCid) != 0);
+
+ if (relationChanged) {
+ needRebuildAllForNewRoot = true; // 閬垮厤閲嶅鎴栧弽鍚戞寕杞�
+ }
+ else {
+ // 鍏崇郴鏈彉锛氳嫢 buddy 涓嶅湪鍙琛ㄤ笖瀹瑰櫒涓嬩篃娌℃湁锛屽垯琛ュ瓙
+ if (!buddyExistsAnywhere && !hasChildAlready) {
+ if (!needRebuildChildren) { CaptureUiState(m_listCtrl, savedSel, savedTop); }
+ needRebuildChildren = true;
+ auto cols = makeColsFromWip(b);
+ auto* ch = m_listCtrl.InsertChild(container, cols);
+ m_listCtrl.SetNodeColor(ch, kWipText, kWipChildBk); // 瀛愶細娴呰壊
+ m_listCtrl.SetNodeColor(container, kWipText, kWipParentBk); // 鐖讹細鍩虹缁�
+ }
+ // 鑻ュ凡鏈夊瓙锛氬悓姝ュ埛鏂板瓙琛屾枃鏈笌棰滆壊
+ else if (hasChildAlready) {
+ for (auto& ch : container->children) {
+ if (ch && ch->cols.size() > 4 && ch->cols[4].CompareNoCase(newBuddyCid) == 0) {
+ auto cols = makeColsFromWip(b);
+ ch->cols = cols; // 鏇存柊搴曞眰鏁版嵁
+ // 鍙琛屽埛鏂�
+ for (int r = 0; r < m_listCtrl.GetItemCount(); ++r) {
+ if (m_listCtrl.GetNodeByVisibleIndex(r) == ch.get()) {
+ for (int c = 1; c < (int)cols.size(); ++c)
+ m_listCtrl.SetItemText(r, c, cols[c]);
+ rowsToRedraw.push_back(r);
+ break;
+ }
+ }
+ m_listCtrl.SetNodeColor(ch.get(), kWipText, kWipChildBk);
+ m_listCtrl.SetNodeColor(container, kWipText, kWipParentBk);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ // 娌� buddy 浣嗗鍣ㄤ笅鏈夊瓙 -> 鍏崇郴鍙樺寲锛岃Е鍙戝叏閲忛噸寤�
+ auto itRoot = wipRootById.find(cid);
+ if (itRoot != wipRootById.end()) {
+ CExpandableListCtrl::Node* container = itRoot->second;
+ if (!container->children.empty())
+ needRebuildAllForNewRoot = true;
+ }
+ }
+ }
+ else {
+ // (B) 涓嶅瓨鍦細鏂板
+ SERVO::CGlass* b = g->getBuddy();
+ CExpandableListCtrl::Node* container = nullptr;
+
+ if (b) {
+#ifdef _UNICODE
+ std::string bid = CT2A(CString(b->getID().c_str()));
+#else
+ std::string bid = b->getID();
+#endif
+ auto itB = wipRowById.find(bid);
+ if (itB != wipRowById.end()) {
+ CExpandableListCtrl::Node* buddyNode = itB->second.second;
+ container = buddyNode ? (buddyNode->parent ? buddyNode->parent : buddyNode) : nullptr;
+ }
+ }
+
+ if (container) {
+ CString cidCs = g->getID().c_str();
+ if (!NodeHasChildWithClassId(container, cidCs)) {
+ if (!needRebuildChildren) { CaptureUiState(m_listCtrl, savedSel, savedTop); }
+ needRebuildChildren = true;
+
+ auto cols = makeColsFromWip(g);
+ auto* ch = m_listCtrl.InsertChild(container, cols);
+ // 瀛愶細鏇存祬锛涚埗锛氬熀纭�缁匡紙鍏滃簳锛�
+ m_listCtrl.SetNodeColor(ch, kWipText, kWipChildBk);
+ m_listCtrl.SetNodeColor(container, kWipText, kWipParentBk);
+ }
+ }
+ else {
+ // buddy 涓嶅湪鍙琛細涓轰簡淇濇寔鈥淲IP 姘歌繙鍦ㄩ《閮ㄢ�濓紝瑙﹀彂涓�娆″叏閲忛噸寤�
+ needRebuildAllForNewRoot = true;
+ }
+ }
+ }
+
+ // 4) 搴旂敤 UI 鏇存柊 鈥斺�� 鎶娾�滃垹闄�/鍑忓皯鈥濈殑鎯呭喌骞跺叆鍏ㄩ噺閲嶅缓鍒嗘敮
+ if (needRebuildAllForNewRoot || needRebuildRemoval) {
+ auto selKeys = SnapshotSelectedKeys(m_listCtrl);
+ auto topKey = SnapshotTopKey(m_listCtrl);
+ UpdatePageData(); // 鍏ㄩ噺閲嶅缓锛圵IP 椤堕儴 & 鍒犻櫎鏃犳晥椤癸級
+ RestoreSelectionByKeys(m_listCtrl, selKeys);
+ RestoreTopByKey(m_listCtrl, topKey);
+ }
+ else if (needRebuildChildren) {
+ auto selKeys = SnapshotSelectedKeys(m_listCtrl);
+ auto topKey = SnapshotTopKey(m_listCtrl);
+ m_listCtrl.RebuildVisible(); // 浠呯粨鏋勫彉鍖栵紙鍔犲瓙锛�
+ RestoreSelectionByKeys(m_listCtrl, selKeys);
+ RestoreTopByKey(m_listCtrl, topKey);
+ }
+ else {
+ for (int row : rowsToRedraw) // 浠呮枃鏈彉鍖�
+ m_listCtrl.RedrawItems(row, row);
+ }
+
+ // 5) 閲婃斁 retain
+ for (auto* g : tempRetain) g->release();
+}
+
+void CPageGlassList::InsertWipRow(SERVO::CGlass* /*pGlass*/)
+{
+ // 涓嶅啀浣跨敤
+}
+
+void CPageGlassList::UpdateWipRow(unsigned int /*index*/, SERVO::CGlass* /*pGlass*/)
+{
+ // 涓嶅啀浣跨敤
+}
+
+bool CPageGlassList::eraseGlassInVector(SERVO::CGlass* /*pGlass*/, std::vector<SERVO::CGlass*>& /*glasses*/)
+{
+ return false;
+}
+
+// ===== 杩囨护閫昏緫锛堝師鏍蜂繚鐣欙級 =====
// 鏍稿績锛歐IP 鐨� CGlass 鏄惁鍛戒腑褰撳墠 Filters
// useEndTime=true 鏃剁敤 tEnd 鍒ゆ椂闂达紙姣斿鈥滃畬鎴愬垪琛ㄢ�濈敤 t_end锛夛紝榛樿鎸� tStart銆�
bool CPageGlassList::GlassMatchesFilters(const SERVO::CGlass& g,
- const GlassLogDb::Filters& f,
- bool useEndTime/* = false*/)
+ const GlassLogDb::Filters& f,
+ bool useEndTime/* = false*/)
{
- // 1) 绮剧‘瀛楁
- if (f.classId && g.getID() != *f.classId) return false;
- if (f.cassetteSeqNo && g.getCassetteSequenceNo() != *f.cassetteSeqNo)return false;
- if (f.jobSeqNo && g.getJobSequenceNo() != *f.jobSeqNo) return false;
+ // 1) 绮剧‘瀛楁
+ if (f.classId && g.getID() != *f.classId) return false;
+ if (f.cassetteSeqNo && g.getCassetteSequenceNo() != *f.cassetteSeqNo) return false;
+ if (f.jobSeqNo && g.getJobSequenceNo() != *f.jobSeqNo) return false;
- // 2) 鍏抽敭瀛楋紙涓� DB 淇濇寔涓�鑷达細class_id / buddy_id / path / params / pretty锛�
- if (f.keyword) {
- const std::string& kw = *f.keyword;
- if (!(CToolUnits::containsCI(g.getID(), kw)
- || CToolUnits::containsCI(g.getBuddyId(), kw)
- || CToolUnits::containsCI(g.getPathDescription(), kw)
- || CToolUnits::containsCI(g.getParamsDescription(), kw)))
- return false;
- }
+ // 2) 鍏抽敭瀛楋紙涓� DB 淇濇寔涓�鑷达細class_id / buddy_id / path / params / pretty锛�
+ if (f.keyword) {
+ const std::string& kw = *f.keyword;
+ if (!(CToolUnits::containsCI(g.getID(), kw)
+ || CToolUnits::containsCI(g.getBuddyId(), kw)
+ || CToolUnits::containsCI(g.getPathDescription(), kw)
+ || CToolUnits::containsCI(g.getParamsDescription(), kw)))
+ return false;
+ }
- // 3) 鏃堕棿锛堜笌 DB 淇濇寔涓�鑷达細榛樿鎸� t_start 杩囨护锛涢渶瑕佸彲鍒囧埌 t_end锛�
- if (f.tStartFrom || f.tStartTo) {
- std::optional<std::chrono::system_clock::time_point> tp = useEndTime ? g.tEnd() : g.tStart();
- // 绾﹀畾锛氳嫢娌℃湁瀵瑰簲鏃堕棿鎴筹紝鍒欒涓轰笉鍛戒腑锛堜笌 DB 鐩稿悓锛歂ULL 涓嶄細鍛戒腑鑼冨洿锛�
- if (!tp) return false;
- if (f.tStartFrom && *tp < *f.tStartFrom) return false;
- if (f.tStartTo && *tp > *f.tStartTo) return false;
- }
+ // 3) 鏃堕棿锛堜笌 DB 淇濇寔涓�鑷达細榛樿鎸� t_start 杩囨护锛涢渶瑕佸彲鍒囧埌 t_end锛�
+ if (f.tStartFrom || f.tStartTo) {
+ std::optional<std::chrono::system_clock::time_point> tp = useEndTime ? g.tEnd() : g.tStart();
+ // 绾﹀畾锛氳嫢娌℃湁瀵瑰簲鏃堕棿鎴筹紝鍒欒涓轰笉鍛戒腑锛堜笌 DB 鐩稿悓锛歂ULL 涓嶄細鍛戒腑鑼冨洿锛�
+ if (!tp) return false;
+ if (f.tStartFrom && *tp < *f.tStartFrom) return false;
+ if (f.tStartTo && *tp > *f.tStartTo) return false;
+ }
- return true;
+ return true;
}
-void CPageGlassList::InsertWipRow(SERVO::CGlass* pGlass)
+BOOL CPageGlassList::PreTranslateMessage(MSG* pMsg)
{
- int index = m_listCtrl.InsertItem(0, "");
- m_listCtrl.SetItemColor(index, RGB(0, 0, 0), RGB(201, 228, 180));
- UpdateWipRow(index, pGlass);
+ if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE) {
+ return TRUE;
+ }
+
+ return CDialogEx::PreTranslateMessage(pMsg);
}
-void CPageGlassList::UpdateWipRow(unsigned int index, SERVO::CGlass* pGlass)
+// 鑾峰彇鏈哄櫒棰勫畾涔夌殑鍒楅『搴�
+std::vector<std::string> CPageGlassList::getMachineColumnOrder(int machineId,
+ const std::unordered_map<std::string, std::vector<SERVO::SVDataItem>>* actualData)
{
- ASSERT(index < m_listCtrl.GetItemCount());
- m_listCtrl.SetItemData(index, (DWORD_PTR)pGlass);
- m_listCtrl.SetItemText(index, 2, std::to_string(pGlass->getCassetteSequenceNo()).c_str());
- m_listCtrl.SetItemText(index, 3, std::to_string(pGlass->getJobSequenceNo()).c_str());
- m_listCtrl.SetItemText(index, 4, pGlass->getID().c_str());
- m_listCtrl.SetItemText(index, 5, SERVO::CServoUtilsTool::getMaterialsTypeText(pGlass->getType()).c_str());
- m_listCtrl.SetItemText(index, 6, SERVO::CServoUtilsTool::getGlassStateText(pGlass->state()).c_str());
- m_listCtrl.SetItemText(index, 7, CToolUnits::TimePointToLocalString(pGlass->tStart()).c_str());
- m_listCtrl.SetItemText(index, 8, CToolUnits::TimePointToLocalString(pGlass->tEnd()).c_str());
- m_listCtrl.SetItemText(index, 9, pGlass->getBuddyId().c_str());
- m_listCtrl.SetItemText(index, 10, SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)pGlass->getAOIInspResult()).c_str());
- m_listCtrl.SetItemText(index, 11, pGlass->getPathDescription().c_str());
- m_listCtrl.SetItemText(index, 12, pGlass->getParamsDescription().c_str());
+ 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;
}
-bool CPageGlassList::eraseGlassInVector(SERVO::CGlass* pGlass, std::vector<SERVO::CGlass*>& glasses)
+// 鏃堕棿鎴宠浆鎹负瀛楃涓�
+std::string CPageGlassList::timePointToString(const std::chrono::system_clock::time_point& tp)
{
- auto iter = std::find(glasses.begin(), glasses.end(), pGlass);
- if (iter != glasses.end()) {
- glasses.erase(iter);
- return true;
- }
+ 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;
+}
- return false;
-}
\ No newline at end of file
+// 鏃堕棿鎴宠浆鎹负姣
+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