chenluhua1980
2026-01-21 bfffbdb8a6d7a3b4805c45583f8bf2101e7b2ad4
SourceCode/Bond/Servo/ServoDlg.cpp
@@ -31,6 +31,7 @@
#include "InputDialog.h"
#include "ClientListDlg.h"
#include "CControlJobManagerDlg.h"
#include "AlarmManager.h"
#include "CUserManager2.h"
#include "CUserManager2Dlg.h"
#include "CUserXLogDlg.h"
@@ -93,6 +94,7 @@
   m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
   m_crBkgnd = APPDLG_BACKGROUND_COLOR;
   m_hbrBkgnd = nullptr;
   m_nLeftPanelType = 2;
   m_pTerminalDisplayDlg = nullptr;
   m_pObserver = nullptr;
   m_pPanelMaster = nullptr;
@@ -109,6 +111,8 @@
   m_pTopToolbar = nullptr;
   m_pMyStatusbar = nullptr;
   m_pRobotTaskDlg = nullptr;
   m_pTab = nullptr;
   m_pAlarmPopupDlg = nullptr;
}
void CServoDlg::DoDataExchange(CDataExchange* pDX)
@@ -142,6 +146,10 @@
   ON_UPDATE_COMMAND_UI(ID_MENU_TEST_MESSAGE_CLEAR, &CServoDlg::OnUpdateMenuTestMessageClear)
   ON_COMMAND(ID_MENU_TOOLS_CLIENT_LIST, &CServoDlg::OnMenuToolsClientList)
   ON_UPDATE_COMMAND_UI(ID_MENU_TOOLS_CLIENT_LIST, &CServoDlg::OnUpdateMenuToolsClientList)
   ON_COMMAND(ID_MENU_WND_TEST_PANEL, &CServoDlg::OnMenuWndTestPanel)
   ON_UPDATE_COMMAND_UI(ID_MENU_WND_TEST_PANEL, &CServoDlg::OnUpdateMenuWndTestPanel)
   ON_COMMAND(ID_MENU_WND_PRO_PANEL, &CServoDlg::OnMenuWndProPanel)
   ON_UPDATE_COMMAND_UI(ID_MENU_WND_PRO_PANEL, &CServoDlg::OnUpdateMenuWndProPanel)
   ON_COMMAND(ID_MENU_HELP_ABOUT, &CServoDlg::OnMenuHelpAbout)
   ON_WM_INITMENUPOPUP()
   ON_WM_TIMER()
@@ -254,6 +262,27 @@
               SetTimer(TIMER_ID_UPDATE_RUMTIME, 500, nullptr);
            }
         }
         else if (RX_CODE_CONTROLJOB_CHANGED == code) {
            auto* cj = theApp.m_model.getMaster().getControlJob();
            CString text;
            if (cj != nullptr) {
               std::string st = cj->getStateText();
               text.Format(_T("ControlJob: %s (%s)"), cj->id().c_str(), st.c_str());
               if (cj->state() == SERVO::CJState::Paused) {
                  text += _T(" [Paused]");
               }
            }
            else {
               text = _T("ControlJob: None");
            }
            if (m_pMyStatusbar != nullptr) {
               m_pMyStatusbar->setRunTimeText((LPTSTR)(LPCTSTR)text);
               if (cj != nullptr && cj->state() == SERVO::CJState::Paused) {
                  m_pMyStatusbar->setBackgroundColor(STATUSBAR_BK_ALARM);
                  m_pMyStatusbar->setForegroundColor(RGB(0, 0, 0));
               }
            }
         }
         else if (RX_CODE_EQ_ROBOT_TASK == code) {
            int exCode;
            if (pAny->getIntValue("exCode", exCode)) {
@@ -300,6 +329,9 @@
               //dlg.DoModal();
            }
         }
         else if (RX_CODE_ALARM_SET == code || RX_CODE_ALARM_CLEAR == code) {
            RefreshAlarmBadge();
         }
         if (RX_CODE_PASSIVE_STATUS_CHANGED == code) {
            int state = 0;
@@ -334,9 +366,82 @@
   }
}
void CServoDlg::RefreshAlarmBadge()
{
   if (m_pTopToolbar == nullptr) return;
   auto activeAlarms = AlarmManager::getInstance().getActiveAlarms();
   // 维护未读列表:当前活跃且未在已读集合中的报警
   std::unordered_set<int> activeIds;
   m_unreadAlarms.clear();
   for (const auto& alarm : activeAlarms) {
      activeIds.insert(alarm.nId);
      if (m_ackAlarms.find(alarm.nId) == m_ackAlarms.end()) {
         m_unreadAlarms.push_back(alarm);
      }
   }
   // 移除已读集合中已不再活跃的告警
   for (auto it = m_ackAlarms.begin(); it != m_ackAlarms.end(); ) {
      if (activeIds.find(*it) == activeIds.end()) {
         it = m_ackAlarms.erase(it);
      }
      else {
         ++it;
      }
   }
   int count = static_cast<int>(m_unreadAlarms.size());
   auto* pBtn = dynamic_cast<CBlButton*>(m_pTopToolbar->GetBtn(IDC_BUTTON_ALARM));
   if (pBtn != nullptr) {
      if (count <= 0) {
         pBtn->SetBadgeNumber(0);
         pBtn->ShowDotBadge(FALSE, RGB(255, 0, 0));
         pBtn->StopFlash();
      }
      else if (count <= 9) {
         pBtn->ShowDotBadge(FALSE, RGB(255, 0, 0));
         pBtn->SetBadgeNumber(count);
         if (!pBtn->IsFlash()) pBtn->Flash(600);
      }
      else {
         pBtn->SetBadgeNumber(0);
         pBtn->ShowDotBadge(TRUE, RGB(255, 0, 0));
         if (!pBtn->IsFlash()) pBtn->Flash(600);
      }
      pBtn->EnableWindow(TRUE);
   }
}
void CServoDlg::RaiseTestAlarm()
{
   theApp.m_model.raiseSoftAlarm(ALID_SOFTWARE_TEST_ALARM, "Test Alarm (Ctrl+Alt+T)");
}
void CServoDlg::ClearTestAlarm()
{
   theApp.m_model.clearSoftAlarm(ALID_SOFTWARE_TEST_ALARM);
}
void CServoDlg::MarkAlarmsRead()
{
   auto* pBtn = dynamic_cast<CBlButton*>(m_pTopToolbar ? m_pTopToolbar->GetBtn(IDC_BUTTON_ALARM) : nullptr);
   for (const auto& alarm : m_unreadAlarms) {
      m_ackAlarms.insert(alarm.nId);
   }
   m_unreadAlarms.clear();
   if (pBtn != nullptr) {
      pBtn->SetBadgeNumber(0);
      pBtn->ShowDotBadge(FALSE, RGB(255, 0, 0));
      pBtn->StopFlash();
   }
}
BOOL CServoDlg::OnInitDialog()
{
   CDialogEx::OnInitDialog();
   const ULONGLONG boot_ui_begin = GetTickCount64();
   CWaitCursor wait; // 整个初始化期显示等待光标,避免用户误以为卡死
   // 将“关于...”菜单项添加到系统菜单中。
@@ -372,13 +477,19 @@
   // model init
   const ULONGLONG boot_model_begin = GetTickCount64();
   theApp.m_model.init();
   LOGI("[BOOT][UI] m_model.init finished, cost=%llu ms (since OnInit start %llu ms)",
      (unsigned long long)(GetTickCount64() - boot_model_begin),
      (unsigned long long)(GetTickCount64() - boot_ui_begin));
   SetTimer(TIMER_ID_LOGIN, 1500, nullptr);
   LOGI("[BOOT][UI] after model.init, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
   // 菜单
   CMenu menu;
   menu.LoadMenu(IDR_MENU_APP);
   SetMenu(&menu);
   LOGI("[BOOT][UI] menu loaded, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
   // toolbar
@@ -391,25 +502,48 @@
   ASSERT(hMenu);
   ::EnableMenuItem(hMenu, ID_OPEATOR_SWITCH, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
   m_pTopToolbar->GetBtn(IDC_BUTTON_JOBS)->EnableWindow(TRUE);
   LOGI("[BOOT][UI] toolbar created, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
   // Tab
   const ULONGLONG boot_pages_begin = GetTickCount64();
   m_pPageGraph1 = new CPageGraph1();
   m_pPageGraph1->Create(IDD_PAGE_GRAPH1, this);
   LOGI("[BOOT][UI] page Graph1 created, cost=%llu ms (elapsed=%llu ms)",
      (unsigned long long)(GetTickCount64() - boot_pages_begin),
      (unsigned long long)(GetTickCount64() - boot_ui_begin));
   m_pPageGraph2 = new CPageGraph2();
   m_pPageGraph2->Create(IDD_PAGE_GRAPH2, this);
   LOGI("[BOOT][UI] page Graph2 created, cost=%llu ms (elapsed=%llu ms)",
      (unsigned long long)(GetTickCount64() - boot_pages_begin),
      (unsigned long long)(GetTickCount64() - boot_ui_begin));
   m_pPageGlassList = new CPageGlassList();
   m_pPageGlassList->Create(IDD_PAGE_GLASS_LIST, this);
   LOGI("[BOOT][UI] page GlassList created, cost=%llu ms (elapsed=%llu ms)",
      (unsigned long long)(GetTickCount64() - boot_pages_begin),
      (unsigned long long)(GetTickCount64() - boot_ui_begin));
   m_pPageRecipe = new CPageRecipe();
   m_pPageRecipe->Create(IDD_PAGE_RECIPE, this);
   LOGI("[BOOT][UI] page Recipe created, cost=%llu ms (elapsed=%llu ms)",
      (unsigned long long)(GetTickCount64() - boot_pages_begin),
      (unsigned long long)(GetTickCount64() - boot_ui_begin));
   m_pPageAlarm = new CPageAlarm();
   m_pPageAlarm->Create(IDD_DIALOG_ALARM, this);
   LOGI("[BOOT][UI] page Alarm created, cost=%llu ms (elapsed=%llu ms)",
      (unsigned long long)(GetTickCount64() - boot_pages_begin),
      (unsigned long long)(GetTickCount64() - boot_ui_begin));
   m_pPageLog = new CPageLog();
   m_pPageLog->Create(IDD_DIALOG_LOG, this);
   LOGI("[BOOT][UI] page Log created, cost=%llu ms (elapsed=%llu ms)",
      (unsigned long long)(GetTickCount64() - boot_pages_begin),
      (unsigned long long)(GetTickCount64() - boot_ui_begin));
   m_pPageTransferLog = new CPageTransferLog();
   m_pPageTransferLog->Create(IDD_PAGE_TRANSFER_LOG, this);
   LOGI("[BOOT][UI] page TransferLog created, cost=%llu ms (elapsed=%llu ms)",
      (unsigned long long)(GetTickCount64() - boot_pages_begin),
      (unsigned long long)(GetTickCount64() - boot_ui_begin));
   CHmTab* m_pTab = CHmTab::Hook(GetDlgItem(IDC_TAB1)->m_hWnd);
   m_pTab = CHmTab::Hook(GetDlgItem(IDC_TAB1)->m_hWnd);
   m_pTab->SetPaddingLeft(20);
   m_pTab->SetItemMarginLeft(18);
   m_pTab->AddItem("状态图", FALSE);
@@ -422,6 +556,7 @@
   m_pTab->SetCurSel(0);
   m_pTab->SetBkgndColor(RGB(222, 222, 222));
   ShowChildPage(0);
   LOGI("[BOOT][UI] pages/tabs created, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
   // 读取面板宽
   CString strIniFile;
@@ -435,17 +570,19 @@
   m_pPanelProduction = new CPanelProduction();
   m_pPanelProduction->setPanelWidth(nPanelWidth);
   m_pPanelProduction->Create(IDD_PANEL_PRODUCTION, this);
   m_pPanelProduction->ShowWindow(SW_SHOW);
   SetLeftPanelType(m_nLeftPanelType, false);
   m_pPanelEquipment = new CPanelEquipment();
   m_pPanelEquipment->Create(IDD_PANEL_EQUIPMENT, this);
   m_pPanelAttributes = new CPanelAttributes();
   m_pPanelAttributes->Create(IDD_PANEL_ATTRIBUTES, this);
   
   LOGI("[BOOT][UI] panels created, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
   // statusbar
   m_pMyStatusbar = new CMyStatusbar();
   m_pMyStatusbar->Create(IDD_STATUSBAR, this);
   m_pMyStatusbar->ShowWindow(SW_SHOW);
   LOGI("[BOOT][UI] statusbar created, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
@@ -462,10 +599,23 @@
   InitRxWindows();
   Resize();
   // 加载历史缓存提示
   {
      CWaitCursor wait;
      if (m_pMyStatusbar != nullptr) {
         m_pMyStatusbar->setRunTimeText(_T("正在加载历史缓存..."));
         m_pMyStatusbar->UpdateWindow();
      }
      LOGI("[BOOT][UI] before master.init, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
   // 相当于延时调用master的初始化
   theApp.m_model.m_master.init();
   theApp.m_model.loadPortParams();
      // 相当于延时调用master的初始化
      const ULONGLONG boot_master_begin = GetTickCount64();
      theApp.m_model.m_master.init();
      LOGI("[BOOT][UI] m_master.init finished, cost=%llu ms (since OnInit start %llu ms)",
         (unsigned long long)(GetTickCount64() - boot_master_begin),
         (unsigned long long)(GetTickCount64() - boot_ui_begin));
      theApp.m_model.loadPortParams();
   }
   // 初始化master以后需要控件绑定数据
@@ -474,9 +624,14 @@
   // 更新登录状态
   UpdateLoginStatus();
   // 初始化报警角标
   RefreshAlarmBadge();
   //SystemLogManager::getInstance.log(SystemLogManager::LogType::Info, _T("BondEq启动..."));
   //SystemLogManager::getInstance.
   LOGI("[BOOT][UI] OnInitDialog finished, total cost=%llu ms",
      (unsigned long long)(GetTickCount64() - boot_ui_begin));
   return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
@@ -648,6 +803,10 @@
   pPage3->Create(IDD_PAGE_VARIABLE);
   dlg.addPage(pPage3, "Variable");
   CPageDataVarialbles* pPage4 = new CPageDataVarialbles();
   pPage4->Create(IDD_PAGE_VARIABLE);
   dlg.addPage(pPage4, "DataVariable");
   dlg.DoModal();
}
@@ -693,6 +852,28 @@
void CServoDlg::OnUpdateMenuToolsClientList(CCmdUI* pCmdUI)
{
   pCmdUI->Enable(TRUE);
}
void CServoDlg::OnMenuWndTestPanel()
{
   SetLeftPanelType(1);
}
void CServoDlg::OnUpdateMenuWndTestPanel(CCmdUI* pCmdUI)
{
   pCmdUI->Enable(TRUE);
   pCmdUI->SetCheck(m_nLeftPanelType == 1);
}
void CServoDlg::OnMenuWndProPanel()
{
   SetLeftPanelType(2);
}
void CServoDlg::OnUpdateMenuWndProPanel(CCmdUI* pCmdUI)
{
   pCmdUI->Enable(TRUE);
   pCmdUI->SetCheck(m_nLeftPanelType == 2);
}
void CServoDlg::OnMenuHelpAbout()
@@ -746,6 +927,12 @@
      m_pMyStatusbar->DestroyWindow();
      delete m_pMyStatusbar;
      m_pMyStatusbar = nullptr;
   }
   if (m_pAlarmPopupDlg != nullptr) {
      m_pAlarmPopupDlg->DestroyWindow();
      delete m_pAlarmPopupDlg;
      m_pAlarmPopupDlg = nullptr;
   }
   if (m_pRobotTaskDlg != nullptr) {
@@ -914,6 +1101,32 @@
   m_pMyStatusbar->MoveWindow(0, y2, rcClient.Width(), STATUSBAR_HEIGHT);
}
void CServoDlg::SetLeftPanelType(int type, bool resize)
{
   if (type != 1 && type != 2) {
      type = 1;
   }
   m_nLeftPanelType = type;
   if (m_pPanelMaster != nullptr) {
      m_pPanelMaster->ShowWindow(SW_HIDE);
   }
   if (m_pPanelProduction != nullptr) {
      m_pPanelProduction->ShowWindow(SW_HIDE);
   }
   if (type == 1 && m_pPanelMaster != nullptr) {
      m_pPanelMaster->ShowWindow(SW_SHOW);
   }
   else if (type == 2 && m_pPanelProduction != nullptr) {
      m_pPanelProduction->ShowWindow(SW_SHOW);
   }
   if (resize && ::IsWindow(m_hWnd)) {
      Resize();
      DrawMenuBar();
   }
}
void CServoDlg::OnClose()
@@ -1128,6 +1341,16 @@
      dlg.SetEFEM(pEFEM);
      dlg.DoModal();
   }
   else if (id == IDC_BUTTON_ALARM) {
      if (m_pAlarmPopupDlg == nullptr) {
         m_pAlarmPopupDlg = new CAlarmPopupDlg();
         m_pAlarmPopupDlg->Create(IDD_DIALOG_POPUP_ALARM, this);
         m_pAlarmPopupDlg->CenterWindow();
      }
      m_pAlarmPopupDlg->RefreshContent();
      m_pAlarmPopupDlg->ShowWindow(SW_SHOW);
      MarkAlarmsRead();
   }
   else if (id == IDC_BUTTON_SETTINGS) {
      SERVO::CEquipment* pEq = theApp.m_model.m_master.getEquipment(EQ_ID_EFEM);
      ((SERVO::CEFEM*)pEq)->printDebugRobotState();
@@ -1239,6 +1462,23 @@
   return 0;
}
BOOL CServoDlg::PreTranslateMessage(MSG* pMsg)
{
   if (pMsg->message == WM_KEYDOWN) {
      const bool ctrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
      const bool alt = (GetKeyState(VK_MENU) & 0x8000) != 0;
      if (ctrl && alt && pMsg->wParam == 'T') {
         RaiseTestAlarm();
         return TRUE;
      }
      if (ctrl && alt && pMsg->wParam == 'Y') {
         ClearTestAlarm();
         return TRUE;
      }
   }
   return CDialogEx::PreTranslateMessage(pMsg);
}
CString& CServoDlg::GetRuntimeFormatText(CString& strText, const char* pszSuffix)
{
   ULONGLONG ullRunTime = (ULONGLONG)(theApp.m_model.getMaster().getRunTime() * 0.001);