chenluhua1980
3 天以前 415ad67bb66ca2d99fb21a8eeb32f942ad2cd7b0
SourceCode/Bond/Servo/CPageGlassList.cpp
@@ -24,6 +24,86 @@
static const COLORREF kWipParentBk = RGB(201, 228, 180); // 基础绿
static const COLORREF kWipChildBk = RGB(221, 241, 208); // 更浅一点
namespace {
   CString FormatPathTime(ULONGLONG ts)
   {
      if (ts == 0) return _T("");
      return CString(CToolUnits::timeToString2(ts).c_str());
   }
   void BuildPathRowsFromGlass(SERVO::CGlass& glass, std::vector<CProcessDataListDlg::PathRow>& rows)
   {
      rows.clear();
      SERVO::CPath* pHead = glass.getPath();
      if (pHead == nullptr) return;
      SERVO::CPath* p = pHead->getHeadPath();
      int step = 1;
      while (p != nullptr) {
         CProcessDataListDlg::PathRow r;
         r.step.Format(_T("%d"), step++);
         std::string eqName = SERVO::CServoUtilsTool::getEqUnitName(
            (int)p->getEqID(), (int)p->getUnit(), (int)p->getSlot());
         if (eqName.empty()) {
            CString tmp;
            tmp.Format(_T("Eq:%u Unit:%u Slot:%u"), p->getEqID(), p->getUnit(), p->getSlot());
            r.chamber = tmp;
         }
         else {
            r.chamber = eqName.c_str();
         }
         r.enterTime = FormatPathTime(p->getInTime());
         r.leaveTime = FormatPathTime(p->getOutTime());
         r.isArmStep = (p->getEqID() == EQ_ID_ARM
            || p->getEqID() == EQ_ID_ARM_TRAY1
            || p->getEqID() == EQ_ID_ARM_TRAY2);
         rows.push_back(r);
         p = p->getNext();
      }
   }
   void ParseNameValuePairs(const CString& text, std::vector<std::pair<CString, CString>>& outRows)
   {
      outRows.clear();
      int idx = 0;
      CString token;
      while (AfxExtractSubString(token, text, idx, ',')) {
         ++idx;
         const int pos = token.Find(_T(':'));
         if (pos < 0) continue;
         CString name = token.Left(pos);
         CString value = token.Mid(pos + 1);
         name.Trim();
         value.Trim();
         if (!name.IsEmpty()) {
            outRows.emplace_back(name, value);
         }
      }
   }
   void BuildBasicRowsFromList(CListCtrl& list, int row, std::vector<std::pair<CString, CString>>& rows)
   {
      rows.clear();
      CHeaderCtrl* pHdr = list.GetHeaderCtrl();
      const int colCount = pHdr ? pHdr->GetItemCount() : 0;
      for (int col = 1; col < colCount; ++col) {
         if (col == 11 || col == 12) continue; // 这两列单独作为其他页
         TCHAR buf[256] = { 0 };
         LVCOLUMN lvc = {};
         lvc.mask = LVCF_TEXT;
         lvc.pszText = buf;
         lvc.cchTextMax = _countof(buf);
         CString header;
         if (list.GetColumn(col, &lvc)) header = lvc.pszText;
         header.Trim();
         if (header.IsEmpty()) continue;
         CString val = list.GetItemText(row, col);
         rows.emplace_back(header, val);
      }
   }
}
// ===== 放在 CPageGlassList.cpp 顶部的匿名工具(文件内静态) =====
// 把当前“已展开”的父行,用它们的 classId(第4列文本)做 key 记录下来
static std::unordered_set<std::string> SnapshotExpandedKeys(CExpandableListCtrl& lv) {
@@ -479,6 +559,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_NOTIFY(NM_DBLCLK, IDC_LIST_ALARM, &CPageGlassList::OnNMDblclkListAlarm)
    ON_BN_CLICKED(IDC_BUTTON_EXPORT_ROW, &CPageGlassList::OnBnClickedButtonExportRow)
END_MESSAGE_MAP()
@@ -1578,16 +1659,192 @@
{
    auto* p = reinterpret_cast<NMC_ELC_SHOWFULLTEXT*>(pNMHDR);
    // 对话框显示工艺参数
    if (p->iSubItem == 12) {
        CProcessDataListDlg dlg;
        dlg.setRawText(p->text);
        dlg.DoModal();
    }
    else {
   if (p->iSubItem != 11 && p->iSubItem != 12) {
        AfxMessageBox(p->text);
        *pResult = 0;
        return;
    }
    const int row = p->iItem;
    std::vector<std::pair<CString, CString>> basicRows;
    std::vector<std::pair<CString, CString>> processRows;
    std::vector<CProcessDataListDlg::PathRow> pathRows;
    bool pathOk = false;
    BuildBasicRowsFromList(m_listCtrl, row, basicRows);
    CString paramsText = m_listCtrl.GetItemText(row, 12);
    ParseNameValuePairs(paramsText, processRows);
    CString strId = m_listCtrl.GetItemText(row, 1); // DB id,WIP为空
    if (!strId.IsEmpty()) {
        try {
            auto rec = GlassLogDb::Instance().queryById(_ttoi64(strId));
            if (rec.has_value() && !rec->pretty.empty()) {
                SERVO::CGlass tempGlass;
                if (GlassJson::FromString(rec->pretty, tempGlass)) {
                    BuildPathRowsFromGlass(tempGlass, pathRows);
                    pathOk = !pathRows.empty();
                }
            }
        }
        catch (...) {
            pathOk = false;
        }
    }
    if (!pathOk) {
        CString cls = m_listCtrl.GetItemText(row, 4); // Class ID
#ifdef _UNICODE
        std::string classId = CT2A(cls);
#else
        std::string classId = cls.GetString();
#endif
        if (!classId.empty()) {
            std::vector<SERVO::CGlass*> wipGlasses;
            theApp.m_model.m_master.getWipGlasses(wipGlasses);
            std::vector<SERVO::CGlass*> tempRetain = wipGlasses;
            SERVO::CGlass* found = nullptr;
            for (auto* g : wipGlasses) {
                if (g == nullptr) continue;
                if (g->getID() == classId) { found = g; break; }
                SERVO::CGlass* b = g->getBuddy();
                if (b != nullptr && b->getID() == classId) { found = b; break; }
            }
            if (found != nullptr) {
                BuildPathRowsFromGlass(*found, pathRows);
                pathOk = !pathRows.empty();
            }
            for (auto* item : tempRetain) {
                if (item != nullptr) item->release();
            }
        }
    }
    if (!pathOk) {
        CString pathText = m_listCtrl.GetItemText(row, 11);
        if (!pathText.IsEmpty()) {
            int cur = 0;
            CString token = pathText.Tokenize(_T("->"), cur);
            int step = 1;
            while (!token.IsEmpty()) {
                token.Trim();
                if (!token.IsEmpty()) {
                    CProcessDataListDlg::PathRow r;
                    r.step.Format(_T("%d"), step++);
                    r.chamber = token;
                    r.enterTime = _T("");
                    r.leaveTime = _T("");
                    CString upper = token;
                    upper.MakeUpper();
                    r.isArmStep = (upper.Find(_T("ARM")) >= 0 || upper.Find(_T("TRAY")) >= 0);
                    pathRows.push_back(r);
                }
                token = pathText.Tokenize(_T("->"), cur);
            }
        }
    }
    CProcessDataListDlg dlg;
    dlg.setUnifiedData(basicRows, pathRows, processRows);
    dlg.setInitialTab((p->iSubItem == 11) ? 1 : 2);
    dlg.DoModal();
    *pResult = 0;
}
void CPageGlassList::OnNMDblclkListAlarm(NMHDR* pNMHDR, LRESULT* pResult)
{
    LPNMITEMACTIVATE pItem = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    if (pItem == nullptr || pItem->iItem < 0) {
        *pResult = 0;
        return;
    }
    const int row = pItem->iItem;
    std::vector<std::pair<CString, CString>> basicRows;
    std::vector<std::pair<CString, CString>> processRows;
    std::vector<CProcessDataListDlg::PathRow> pathRows;
    bool pathOk = false;
    BuildBasicRowsFromList(m_listCtrl, row, basicRows);
    CString paramsText = m_listCtrl.GetItemText(row, 12);
    ParseNameValuePairs(paramsText, processRows);
    CString strId = m_listCtrl.GetItemText(row, 1); // DB id,WIP为空
    if (!strId.IsEmpty()) {
        try {
            auto rec = GlassLogDb::Instance().queryById(_ttoi64(strId));
            if (rec.has_value() && !rec->pretty.empty()) {
                SERVO::CGlass tempGlass;
                if (GlassJson::FromString(rec->pretty, tempGlass)) {
                    BuildPathRowsFromGlass(tempGlass, pathRows);
                    pathOk = !pathRows.empty();
                }
            }
        }
        catch (...) {
            pathOk = false;
        }
    }
    if (!pathOk) {
        CString cls = m_listCtrl.GetItemText(row, 4); // Class ID
#ifdef _UNICODE
        std::string classId = CT2A(cls);
#else
        std::string classId = cls.GetString();
#endif
        if (!classId.empty()) {
            std::vector<SERVO::CGlass*> wipGlasses;
            theApp.m_model.m_master.getWipGlasses(wipGlasses);
            std::vector<SERVO::CGlass*> tempRetain = wipGlasses;
            SERVO::CGlass* found = nullptr;
            for (auto* g : wipGlasses) {
                if (g == nullptr) continue;
                if (g->getID() == classId) { found = g; break; }
                SERVO::CGlass* b = g->getBuddy();
                if (b != nullptr && b->getID() == classId) { found = b; break; }
            }
            if (found != nullptr) {
                BuildPathRowsFromGlass(*found, pathRows);
                pathOk = !pathRows.empty();
            }
            for (auto* item : tempRetain) {
                if (item != nullptr) item->release();
            }
        }
    }
    if (!pathOk) {
        CString pathText = m_listCtrl.GetItemText(row, 11);
        if (!pathText.IsEmpty()) {
            int cur = 0;
            CString token = pathText.Tokenize(_T("->"), cur);
            int step = 1;
            while (!token.IsEmpty()) {
                token.Trim();
                if (!token.IsEmpty()) {
                    CProcessDataListDlg::PathRow r;
                    r.step.Format(_T("%d"), step++);
                    r.chamber = token;
                    r.enterTime = _T("");
                    r.leaveTime = _T("");
                    CString upper = token;
                    upper.MakeUpper();
                    r.isArmStep = (upper.Find(_T("ARM")) >= 0 || upper.Find(_T("TRAY")) >= 0);
                    pathRows.push_back(r);
                }
                token = pathText.Tokenize(_T("->"), cur);
            }
        }
    }
    CProcessDataListDlg dlg;
    dlg.setUnifiedData(basicRows, pathRows, processRows);
    dlg.DoModal();
    *pResult = 0;
}