// CPageGlassList.cpp: 实现文件 // #include "stdafx.h" #include "Servo.h" #include "CPageGlassList.h" #include "afxdialogex.h" #include "GlassJson.h" #define PAGE_SIZE 100 #define PAGE_BACKGROUND_COLOR RGB(252, 252, 255) // CPageGlassList 对话框 IMPLEMENT_DYNAMIC(CPageGlassList, CDialogEx) CPageGlassList::CPageGlassList(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_PAGE_GLASS_LIST, pParent) { m_crBkgnd = PAGE_BACKGROUND_COLOR; m_hbrBkgnd = nullptr; m_pObserver = nullptr; m_strStatus = ""; m_strKeyword = ""; m_nCurPage = 0; m_nTotalPages = 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; } } 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); } 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) END_MESSAGE_MAP() // CPageGlassList 消息处理程序 void CPageGlassList::InitRxWindow() { /* 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(); if (RX_CODE_EQ_ROBOT_TASK == code) { UpdatePageData(); } pAny->release(); }, [&]() -> void { // onComplete }, [&](IThrowable* pThrowable) -> void { // onErrorm pThrowable->printf(); }); theApp.m_model.getObservable()->observeOn(pRxWindows->mainThread())->subscribe(m_pObserver); } } void CPageGlassList::Resize() { 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; // ===== 分页控件布局 ===== 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); 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; // 设置按钮和标签位置 pBtnNext->MoveWindow(xRight - nButtonWidth, yBottom, nButtonWidth, nButtonHeight); xRight -= nButtonWidth + nSpacing; pLabelPage->MoveWindow(xRight - nLabelWidth, yBottom, nLabelWidth, nButtonHeight); xRight -= nLabelWidth + nSpacing; 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); } } 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); } } 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); } } 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); } void CPageGlassList::LoadTransfers() { m_nCurPage = 1; UpdatePageData(); } void CPageGlassList::UpdatePageData() { /* TransferData filter; filter.strStatus = m_strStatus; filter.strDescription = m_strKeyword; filter.strCreateTime = m_szTimeStart; filter.strEndTime = m_szTimeEnd; auto vecData = TransferManager::getInstance().getTransfers(filter, m_nCurPage, PAGE_SIZE); FillDataToListCtrl(vecData); int nTotalRecords = TransferManager::getInstance().getFilteredTransferCount(filter); m_nTotalPages = (nTotalRecords + PAGE_SIZE - 1) / PAGE_SIZE; UpdatePageControls(); */ } 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); Resize(); } void CPageGlassList::UpdateDateFilter() { CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_DATETIME); if (nullptr != pComboBox) { int nIndex = pComboBox->GetCurSel(); if (nIndex == 0) { memset(m_szTimeStart, 0, sizeof(m_szTimeStart)); memset(m_szTimeEnd, 0, sizeof(m_szTimeEnd)); m_szTimeStart[0] = '\0'; m_szTimeEnd[0] = '\0'; } else { CTime time = CTime::GetCurrentTime(); if (nIndex == 1) { sprintf_s(m_szTimeStart, 64, "%d-%02d-%02d 00:00:00", time.GetYear(), time.GetMonth(), time.GetDay()); sprintf_s(m_szTimeEnd, 64, "%d-%02d-%02d 23:59:59", time.GetYear(), time.GetMonth(), time.GetDay()); } else if (nIndex == 2) { CTime time2 = time - CTimeSpan(7, 0, 0, 0); sprintf_s(m_szTimeStart, 64, "%d-%02d-%02d 00:00:00", time2.GetYear(), time2.GetMonth(), time2.GetDay()); sprintf_s(m_szTimeEnd, 64, "%d-%02d-%02d 23:59:59", time.GetYear(), time.GetMonth(), time.GetDay()); } else if (nIndex == 3) { sprintf_s(m_szTimeStart, 64, "%d-%02d-01 00:00:00", time.GetYear(), time.GetMonth()); sprintf_s(m_szTimeEnd, 64, "%d-%02d-%02d 23:59:59", time.GetYear(), time.GetMonth(), time.GetDay()); } else if (nIndex == 4) { sprintf_s(m_szTimeStart, 64, "%d-01-01 00:00:00", time.GetYear()); sprintf_s(m_szTimeEnd, 64, "%d-12-31 23:59:59", time.GetYear()); } else if (nIndex == 5) { SYSTEMTIME t1, t2; m_dateTimeStart.GetTime(&t1); m_dateTimeEnd.GetTime(&t2); //sprintf_s(m_szTimeStart, 64, "%d-%02d-%02d %02d:%02d:%02d", t1.wYear, t1.wMonth, t1.wDay, t1.wHour, t1.wMinute, t1.wSecond); //sprintf_s(m_szTimeEnd, 64, "%d-%02d-%02d %02d:%02d:%02d", t2.wYear, t2.wMonth, t2.wDay, t2.wHour, t2.wMinute, t2.wSecond); sprintf_s(m_szTimeStart, 64, "%d-%02d-%02d 00:00:00", t1.wYear, t1.wMonth, t1.wDay); sprintf_s(m_szTimeEnd, 64, "%d-%02d-%02d 23:59:59", t2.wYear, t2.wMonth, t2.wDay); } } } } /* void CPageGlassList::FillDataToListCtrl(const std::vector& vecData) { if (m_listCtrl.m_hWnd == nullptr) { return; } m_listCtrl.DeleteAllItems(); for (const auto& item : vecData) { InsertTransferData(item); } } void CPageGlassList::InsertTransferData(const TransferData& data) { if (m_listCtrl.m_hWnd == nullptr) { return; } int nIndex = m_listCtrl.GetItemCount(); if (nIndex < 0) { return; } int nItem = m_listCtrl.InsertItem(nIndex, _T("")); CString str; str.Format(_T("%d"), data.nRecordId); m_listCtrl.SetItemText(nItem, 1, str); m_listCtrl.SetItemText(nItem, 2, CString(data.strStatus.c_str())); m_listCtrl.SetItemText(nItem, 3, CString(data.strClassID.c_str())); m_listCtrl.SetItemText(nItem, 4, CString(data.strCreateTime.c_str())); m_listCtrl.SetItemText(nItem, 5, CString(data.strPickTime.c_str())); m_listCtrl.SetItemText(nItem, 6, CString(data.strPlaceTime.c_str())); m_listCtrl.SetItemText(nItem, 7, CString(data.strEndTime.c_str())); m_listCtrl.SetItemText(nItem, 8, CString(data.strDescription.c_str())); } */ // CPageTransferLog 消息处理程序 BOOL CPageGlassList::OnInitDialog() { CDialogEx::OnInitDialog(); // TODO: 在此添加额外的初始化 SetTimer(1, 3000, nullptr); // 下拉框控件 InitStatusCombo(); InitTimeRangeCombo(); // 日期控件 InitDateTimeControls(); // 报表控件 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); HIMAGELIST imageList = ImageList_Create(24, 24, ILC_COLOR24, 1, 1); ListView_SetImageList(m_listCtrl.GetSafeHwnd(), imageList, LVSIL_SMALL); CString headers[] = { _T(""), _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, 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], LVCFMT_LEFT, widths[i]); } m_listCtrl.SetColumnWidth(10, LVSCW_AUTOSIZE_USEHEADER); // 计算总页数 /* int nTotalRecords = TransferManager::getInstance().getTotalTransferCountAll(); m_nTotalPages = (nTotalRecords + PAGE_SIZE - 1) / PAGE_SIZE; m_nCurPage = 1; */ Resize(); LoadTransfers(); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } 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; } 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; } // 保存列宽 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); } } void CPageGlassList::OnSize(UINT nType, int cx, int cy) { CDialogEx::OnSize(nType, cx, cy); Resize(); } void CPageGlassList::OnTimer(UINT_PTR nIDEvent) { if (nIDEvent == 1) { KillTimer(1); InitRxWindow(); } 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(); } 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(); } void CPageGlassList::OnBnClickedButtonSearch() { // 获取关键字输入框内容 CString strKeyword; GetDlgItemText(IDC_EDIT_KEYWORD, strKeyword); m_strKeyword = CT2A(strKeyword); // 更新日期过滤器和页面数据 UpdateDateFilter(); LoadTransfers(); } void CPageGlassList::OnBnClickedButtonExport() { CFileDialog fileDialog(FALSE, _T("csv"), NULL, OFN_HIDEREADONLY, _T("CSV Files (*.csv)|*.csv||")); if (fileDialog.DoModal() != IDOK) { return; } CStdioFile file; if (!file.Open(fileDialog.GetPathName(), CFile::modeCreate | CFile::modeWrite | CFile::typeText)) { AfxMessageBox(_T("创建文件失败!")); return; } CString strHeader = _T("任务ID,状态,ClassID,创建时间,取片时间,放片时间,结束时间,描述\n"); file.WriteString(strHeader); for (int i = 0; i < m_listCtrl.GetItemCount(); ++i) { CString row; for (int j = 1; j <= 8; ++j) { row += m_listCtrl.GetItemText(i, j); if (j != 8) { row += ","; } } row += "\n"; file.WriteString(row); } file.Close(); } void CPageGlassList::OnBnClickedButtonPrevPage() { SERVO::CGlass g; g.setID("GLS-001"); g.setType(SERVO::MaterialsType::G1); g.setOriginPort(1, 5); g.setScheduledForProcessing(TRUE); g.m_failReason = "none"; g.markQueued(); g.markStart(); // 添加参数 CParam p1("校正对位延时", "P001", "ms", 123); CParam p2("温度", "P002", "degC", 25.5); g.getParams().push_back(p1); g.getParams().push_back(p2); // 设置 JobDataS SERVO::CJobDataS* js = g.getJobDataS(); js->setCassetteSequenceNo(10); js->setJobSequenceNo(20); js->setLotId("LOT-ABC"); js->setGlass1Id("GLS-001"); // 添加 Path g.addPath(100, 1); SERVO::CPath* tail = g.getPath()->getTailPath(); tail->setInTime(111111); tail->setOutTime(222222); tail->setInspResult(SERVO::InspResult::Pass); tail->processEnd(); return; // 2. 转为 JSON std::string jsonText = GlassJson::ToPrettyString(g); TRACE("序列化结果:\n%s\n\n", jsonText.c_str()); // 3. 反序列化 SERVO::CGlass g2; std::string err; if (!GlassJson::FromString(jsonText, g2, &err)) { TRACE("解析失败: %s\n", err.c_str()); return; } // 4. 打印验证 TRACE("反序列化后的ID: %s\n", g2.getID().c_str()); TRACE("反序列化后的参数数量: %d\n", (int)g2.getParams().size()); if (!g2.getParams().empty()) { TRACE("第一个参数名: %s 值=%d\n", g2.getParams()[0].getName().c_str(), g2.getParams()[0].getIntValue()); } if (m_nCurPage > 1) { m_nCurPage--; UpdatePageData(); } } void CPageGlassList::OnBnClickedButtonNextPage() { if (m_nCurPage < m_nTotalPages) { m_nCurPage++; UpdatePageData(); } }