mrDarker
6 天以前 829fe6c6bc33d53fda9c31fd45a37e1df87befff
SourceCode/Bond/Servo/ServoDlg.cpp
@@ -1,5 +1,5 @@
// ServoDlg.cpp : 实现文件

// ServoDlg.cpp : 实现文件
//
#include "stdafx.h"
@@ -16,6 +16,7 @@
#include "CRobotCmdContainerDlg.h"
#include "CRobotCmdTestDlg.h"
#include "LoginDlg.h"
#include "LoginDlg2.h"
#include "ChangePasswordDlg.h"
#include "UserManagerDlg.h"
#include "SystemLogManagerDlg.h"
@@ -28,6 +29,12 @@
#include "CPageCollectionEvent.h"
#include "CControlJobDlg.h"
#include "InputDialog.h"
#include "ClientListDlg.h"
#include "CControlJobManagerDlg.h"
#include "AlarmManager.h"
#include "CUserManager2.h"
#include "CUserManager2Dlg.h"
#include "CUserXLogDlg.h"
#ifdef _DEBUG
@@ -35,32 +42,32 @@
#endif
/* 创建终端的定时器 */
/* 创建终端的定时器 */
#define TIMER_ID_CREATE_TERMINAL      1
/* 运行时间定时器 */
/* 运行时间定时器 */
#define TIMER_ID_UPDATE_RUMTIME         2
/* Test */
#define TIMER_ID_TEST               3
#define TIMER_ID_LOGIN               3
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
   CAboutDlg();
// 对话框数据
// 对话框数据
#ifdef AFX_DESIGN_TIME
   enum { IDD = IDD_ABOUTBOX };
#endif
   protected:
   virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
   virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
// 实现
// 实现
protected:
   DECLARE_MESSAGE_MAP()
};
@@ -78,7 +85,7 @@
END_MESSAGE_MAP()
// CServoDlg 对话框
// CServoDlg 对话框
CServoDlg::CServoDlg(CWnd* pParent /*=NULL*/)
@@ -87,9 +94,11 @@
   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;
   m_pPanelProduction = nullptr;
   m_pPanelEquipment = nullptr;
   m_pPanelAttributes = nullptr;
   m_pPageGraph1 = nullptr;
@@ -102,6 +111,8 @@
   m_pTopToolbar = nullptr;
   m_pMyStatusbar = nullptr;
   m_pRobotTaskDlg = nullptr;
   m_pTab = nullptr;
   m_pAlarmPopupDlg = nullptr;
}
void CServoDlg::DoDataExchange(CDataExchange* pDX)
@@ -129,10 +140,24 @@
   ON_UPDATE_COMMAND_UI(ID_MENU_FILE_SECSTEST, &CServoDlg::OnUpdateMenuFileSecsTest)
   ON_COMMAND(ID_MENU_PROJECT_VARIABLE_LIST, &CServoDlg::OnMenuProjectVarialbleList)
   ON_UPDATE_COMMAND_UI(ID_MENU_PROJECT_VARIABLE_LIST, &CServoDlg::OnUpdateMenuProjectVarialbleList)
   ON_COMMAND(ID_MENU_TEST_ALARM_ON, &CServoDlg::OnMenuTestAlarmOn)
   ON_UPDATE_COMMAND_UI(ID_MENU_TEST_ALARM_ON, &CServoDlg::OnUpdateMenuTestAlarmOn)
   ON_COMMAND(ID_MENU_TEST_ALARM_OFF, &CServoDlg::OnMenuTestAlarmOff)
   ON_UPDATE_COMMAND_UI(ID_MENU_TEST_ALARM_OFF, &CServoDlg::OnUpdateMenuTestAlarmOff)
   ON_COMMAND(ID_MENU_TEST_MESSAGE_SET, &CServoDlg::OnMenuTestMessageSet)
   ON_UPDATE_COMMAND_UI(ID_MENU_TEST_MESSAGE_SET, &CServoDlg::OnUpdateMenuTestMessageSet)
   ON_COMMAND(ID_MENU_TEST_MESSAGE_CLEAR, &CServoDlg::OnMenuTestMessageClear)
   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_TOOLS_CURVE_EMPTY, &CServoDlg::OnMenuToolsCurveEmptyMode)
   ON_UPDATE_COMMAND_UI(ID_MENU_TOOLS_CURVE_EMPTY, &CServoDlg::OnUpdateMenuToolsCurveEmptyMode)
   ON_COMMAND(ID_MENU_TOOLS_CURVE_PRODUCTION, &CServoDlg::OnMenuToolsCurveProductionMode)
   ON_UPDATE_COMMAND_UI(ID_MENU_TOOLS_CURVE_PRODUCTION, &CServoDlg::OnUpdateMenuToolsCurveProductionMode)
   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()
@@ -143,12 +168,12 @@
END_MESSAGE_MAP()
// CServoDlg 消息处理程序
// CServoDlg 消息处理程序
void CServoDlg::InitRxWindows()
{
   /* code */
   // 订阅数据
   // 订阅数据
   IRxWindows* pRxWindows = RX_GetRxWindows();
   pRxWindows->enableLog(5);
   if (m_pObserver == NULL) {
@@ -170,7 +195,7 @@
               ASSERT(m_pPanelAttributes);
               m_pPanelEquipment->loadDataFromEquipment(pEquipment);
               m_pPanelAttributes->ShowWindow(SW_HIDE);
               if (!m_pPanelEquipment->IsWindowVisible()) {
               if (!m_pPanelEquipment->IsWindowVisible() && m_nLeftPanelType == 1) {
                  m_pPanelEquipment->ShowWindow(SW_SHOW);
                  Resize();
               }
@@ -193,7 +218,7 @@
         else if (RX_CODE_MASTER_STATE_CHANGED == code) {
            SERVO::MASTERSTATE state = theApp.m_model.getMaster().getState();
            if (state == SERVO::MASTERSTATE::READY) {
               m_pTopToolbar->GetBtn(IDC_BUTTON_RUN)->EnableWindow(TRUE);
               m_pTopToolbar ->GetBtn(IDC_BUTTON_RUN)->EnableWindow(TRUE);
               m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_BATCH)->EnableWindow(TRUE);
               m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_CT)->EnableWindow(TRUE);
               m_pTopToolbar->GetBtn(IDC_BUTTON_STOP)->EnableWindow(FALSE);
@@ -207,7 +232,7 @@
            else if (state == SERVO::MASTERSTATE::STARTING) {
               m_pMyStatusbar->setBackgroundColor(STATUSBAR_BK_STARTING);
               m_pMyStatusbar->setForegroundColor(RGB(0, 0, 0));
               m_pMyStatusbar->setRunTimeText("正在启动...");
               m_pMyStatusbar->setRunTimeText("正在启动...");
            }
            else if (state == SERVO::MASTERSTATE::MSERROR) {
               m_pTopToolbar->GetBtn(IDC_BUTTON_RUN)->EnableWindow(TRUE);
@@ -216,8 +241,9 @@
               m_pTopToolbar->GetBtn(IDC_BUTTON_STOP)->EnableWindow(FALSE);
               m_pMyStatusbar->setBackgroundColor(STATUSBAR_BK_ALARM);
               m_pMyStatusbar->setForegroundColor(RGB(0, 0, 0));
               m_pMyStatusbar->setRunTimeText("启动失败.");
               m_pMyStatusbar->setRunTimeText("启动失败.");
               m_pTopToolbar->GetBtn(IDC_BUTTON_ALARM)->EnableWindow(TRUE);
               KillTimer(TIMER_ID_UPDATE_RUMTIME);
            }
            else if (state == SERVO::MASTERSTATE::ATHERERROR) {
               m_pTopToolbar->GetBtn(IDC_BUTTON_RUN)->EnableWindow(TRUE);
@@ -228,9 +254,10 @@
               m_pMyStatusbar->setForegroundColor(RGB(0, 0, 0));
               m_pMyStatusbar->setRunTimeText(theApp.m_model.getMaster().getLastErrorText().c_str());
               if (theApp.m_model.getMaster().getLastError() == ER_CODE_AOI_NG) {
                  AfxMessageBox(_T("AOI检测失败,请操作员介入解决问题!"));
                  AfxMessageBox(_T("AOI检测失败,请操作员介入解决问题!"));
               }
               m_pTopToolbar->GetBtn(IDC_BUTTON_ALARM)->EnableWindow(TRUE);
               KillTimer(TIMER_ID_UPDATE_RUMTIME);
            }
            else if (state == SERVO::MASTERSTATE::RUNNING || state == SERVO::MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER
               || state == SERVO::MASTERSTATE::RUNNING_BATCH) {
@@ -241,6 +268,27 @@
               m_pMyStatusbar->setBackgroundColor(STATUSBAR_BK_RUNNING);
               m_pMyStatusbar->setForegroundColor(RGB(255, 255, 255));
               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->setJobText((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) {
@@ -271,13 +319,13 @@
                  }
               }
               else if (exCode == ROBOT_EVENT_FINISH) {
                  m_pMyStatusbar->setCurTaskBtnText("无");
                  m_pMyStatusbar->setCurTaskBtnText("无");
               }
               else if (exCode == ROBOT_EVENT_ABORT) {
                  m_pMyStatusbar->setCurTaskBtnText("无");
                  m_pMyStatusbar->setCurTaskBtnText("无");
               }
               else if (exCode == ROBOT_EVENT_RESTORE) {
                  m_pMyStatusbar->setCurTaskBtnText("无");
                  m_pMyStatusbar->setCurTaskBtnText("无");
               }
            }
         }
@@ -289,6 +337,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;
@@ -296,18 +347,18 @@
            if (STATE::NOT_CONNECTED == state) {
               m_pMyStatusbar->setCimBtnText("Disconnected");
               //m_labelPassiveState.setBackground(DISCONNECTED_BACKGROUND);
               //m_labelPassiveState.setForeground(DISCONNECTED_FOREGROUND, TRUE);
               m_pMyStatusbar->setCimBtnColors(
                  CIM_STATUS_BK_DISCONNECTED, CIM_STATUS_BK_DISCONNECTED, RGB(0, 0, 0));
            }
            else if (STATE::NOT_SELECTED == state) {
               m_pMyStatusbar->setCimBtnText("Not Selected");
               //m_labelPassiveState.setBackground(NOT_SELECTED_BACKGROUND);
               //m_labelPassiveState.setForeground(NOT_SELECTED_FOREGROUND, TRUE);
               m_pMyStatusbar->setCimBtnColors(
                  CIM_STATUS_BK_DISCONNECTED, CIM_STATUS_BK_DISCONNECTED, RGB(0, 0, 0));
            }
            else if (STATE::SELECTED == state) {
               m_pMyStatusbar->setCimBtnText("Selected");
               //m_labelPassiveState.setBackground(SELECTED_BACKGROUND);
               //m_labelPassiveState.setForeground(SELECTED_FOREGROUND, TRUE);
               m_pMyStatusbar->setCimBtnColors(
                  CIM_STATUS_BK_SELECTED, CIM_STATUS_BK_SELECTED, RGB(0, 0, 0));
            }
         }
         pAny->release();
@@ -323,13 +374,92 @@
   }
}
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::AckAlarm(int alarmId)
{
   m_ackAlarms.insert(alarmId);
   RefreshAlarmBadge();
}
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; // 整个初始化期显示等待光标,避免用户误以为卡死
   // 将“关于...”菜单项添加到系统菜单中。
   // 将“关于...”菜单项添加到系统菜单中。
   // IDM_ABOUTBOX 必须在系统命令范围内。
   // IDM_ABOUTBOX 必须在系统命令范围内。
   ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
   ASSERT(IDM_ABOUTBOX < 0xF000);
@@ -347,20 +477,33 @@
      }
   }
   // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
   //  执行此操作
   SetIcon(m_hIcon, TRUE);         // 设置大图标
   SetIcon(m_hIcon, FALSE);      // 设置小图标
   // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
   //  执行此操作
   SetIcon(m_hIcon, TRUE);         // 设置大图标
   SetIcon(m_hIcon, FALSE);      // 设置小图标
   // 最大化/窗口标题/版本号
   ShowWindow(SW_MAXIMIZE);
   CString strTitle;
   strTitle.Format(_T("Bond Master -- V%s(%d)"), theApp.m_strVersionName, theApp.m_nVersionNumber);
   SetWindowText(strTitle);
   // model init
   const ULONGLONG boot_model_begin = GetTickCount64();
   theApp.m_model.init();
   SetTimer(TIMER_ID_TEST, 1000, nullptr);
   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
@@ -373,56 +516,92 @@
   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);
   m_pTab->AddItem("连接图", TRUE);
   m_pTab->AddItem("状态图", FALSE);
   m_pTab->AddItem("连接图", TRUE);
   m_pTab->AddItem("Glass", TRUE);
   m_pTab->AddItem("配方", TRUE);
   m_pTab->AddItem("报警", TRUE);
   m_pTab->AddItem("日志", TRUE);
   m_pTab->AddItem("搬运任务", TRUE);
   m_pTab->AddItem("配方", TRUE);
   m_pTab->AddItem("报警", TRUE);
   m_pTab->AddItem("日志", TRUE);
   m_pTab->AddItem("搬运任务", TRUE);
   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;
   strIniFile.Format(_T("%s\\%s.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir, (LPTSTR)(LPCTSTR)theApp.m_strAppFile);
   int nPanelWidth = GetPrivateProfileInt(_T("App"), _T("MasterPanelWidth"),
      int((double)GetSystemMetrics(SM_CXSCREEN) * 0.25), (LPTSTR)(LPCTSTR)strIniFile);
   m_pPanelMaster = new CPanelMaster();
   m_pPanelMaster->setPanelWidth(nPanelWidth);
   m_pPanelMaster->Create(IDD_PANEL_MASTER, this);
   m_pPanelMaster->ShowWindow(SW_SHOW);
   m_pPanelProduction = new CPanelProduction();
   m_pPanelProduction->setPanelWidth(nPanelWidth);
   m_pPanelProduction->Create(IDD_PANEL_PRODUCTION, this);
   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);
   m_pMyStatusbar->setJobText("ControlJob: None");
   LOGI("[BOOT][UI] statusbar created, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
   // 调整初始窗口位置
   // 调整初始窗口位置
   CRect rcWnd;
   GetWindowRect(&rcWnd);
   int width = GetSystemMetrics(SM_CXSCREEN);
@@ -435,23 +614,48 @@
   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();
   }
   // 还原状态栏运行时间显示(避免一直停留在“正在加载历史缓存...”)
   if (m_pMyStatusbar != nullptr) {
      CString strText;
      GetRuntimeFormatText(strText, "");
      m_pMyStatusbar->setRunTimeText((LPTSTR)(LPCTSTR)strText);
   }
   // 初始化master以后需要控件绑定数据
   // 初始化master以后需要控件绑定数据
   m_pPageGraph1->BindEquipmentToGraph();
   // 更新登录状态
   // 更新登录状态
   UpdateLoginStatus();
   //SystemLogManager::getInstance.log(SystemLogManager::LogType::Info, _T("BondEq启动..."));
   // 初始化报警角标
   RefreshAlarmBadge();
   //SystemLogManager::getInstance.log(SystemLogManager::LogType::Info, _T("BondEq启动..."));
   //SystemLogManager::getInstance.
   return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
   LOGI("[BOOT][UI] OnInitDialog finished, total cost=%llu ms",
      (unsigned long long)(GetTickCount64() - boot_ui_begin));
   return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
void CServoDlg::OnSysCommand(UINT nID, LPARAM lParam)
@@ -467,19 +671,19 @@
   }
}
// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。
// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。
void CServoDlg::OnPaint()
{
   if (IsIconic())
   {
      CPaintDC dc(this); // 用于绘制的设备上下文
      CPaintDC dc(this); // 用于绘制的设备上下文
      SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
      // 使图标在工作区矩形中居中
      // 使图标在工作区矩形中居中
      int cxIcon = GetSystemMetrics(SM_CXICON);
      int cyIcon = GetSystemMetrics(SM_CYICON);
      CRect rect;
@@ -487,7 +691,7 @@
      int x = (rect.Width() - cxIcon + 1) / 2;
      int y = (rect.Height() - cyIcon + 1) / 2;
      // 绘制图标
      // 绘制图标
      dc.DrawIcon(x, y, m_hIcon);
   }
   else
@@ -496,8 +700,8 @@
   }
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CServoDlg::OnQueryDragIcon()
{
   return static_cast<HCURSOR>(m_hIcon);
@@ -621,10 +825,34 @@
   pPage3->Create(IDD_PAGE_VARIABLE);
   dlg.addPage(pPage3, "Variable");
   CPageDataVarialbles* pPage4 = new CPageDataVarialbles();
   pPage4->Create(IDD_PAGE_VARIABLE);
   dlg.addPage(pPage4, "DataVariable");
   dlg.DoModal();
}
void CServoDlg::OnUpdateMenuProjectVarialbleList(CCmdUI* pCmdUI)
{
   pCmdUI->Enable(TRUE);
}
void CServoDlg::OnMenuTestAlarmOn()
{
   RaiseTestAlarm();
}
void CServoDlg::OnUpdateMenuTestAlarmOn(CCmdUI* pCmdUI)
{
   pCmdUI->Enable(TRUE);
}
void CServoDlg::OnMenuTestAlarmOff()
{
   ClearTestAlarm();
}
void CServoDlg::OnUpdateMenuTestAlarmOff(CCmdUI* pCmdUI)
{
   pCmdUI->Enable(TRUE);
}
@@ -657,6 +885,61 @@
   pCmdUI->Enable(TRUE);
}
void CServoDlg::OnMenuToolsClientList()
{
   CClientListDlg dlg;
   dlg.DoModal();
}
void CServoDlg::OnUpdateMenuToolsClientList(CCmdUI* pCmdUI)
{
   pCmdUI->Enable(TRUE);
}
void CServoDlg::OnMenuToolsCurveEmptyMode()
{
   theApp.m_model.getMaster().setCurveMode(SERVO::CurveMode::EmptyChamber);
}
void CServoDlg::OnUpdateMenuToolsCurveEmptyMode(CCmdUI* pCmdUI)
{
   pCmdUI->Enable(TRUE);
   pCmdUI->SetCheck(theApp.m_model.getMaster().getCurveMode() == SERVO::CurveMode::EmptyChamber);
}
void CServoDlg::OnMenuToolsCurveProductionMode()
{
   theApp.m_model.getMaster().setCurveMode(SERVO::CurveMode::Production);
}
void CServoDlg::OnUpdateMenuToolsCurveProductionMode(CCmdUI* pCmdUI)
{
   pCmdUI->Enable(TRUE);
   pCmdUI->SetCheck(theApp.m_model.getMaster().getCurveMode() == SERVO::CurveMode::Production);
}
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()
{
   theApp.m_model.getMaster().test();
@@ -666,14 +949,14 @@
void CServoDlg::OnBnClickedOk()
{
   // TODO: 在此添加控件通知处理程序代码
   // TODO: 在此添加控件通知处理程序代码
   CDialogEx::OnOK();
}
void CServoDlg::OnBnClickedCancel()
{
   // TODO: 在此添加控件通知处理程序代码
   // TODO: 在此添加控件通知处理程序代码
   CDialogEx::OnCancel();
}
@@ -710,6 +993,12 @@
      m_pMyStatusbar = nullptr;
   }
   if (m_pAlarmPopupDlg != nullptr) {
      m_pAlarmPopupDlg->DestroyWindow();
      delete m_pAlarmPopupDlg;
      m_pAlarmPopupDlg = nullptr;
   }
   if (m_pRobotTaskDlg != nullptr) {
      m_pRobotTaskDlg->DestroyWindow();
      delete m_pRobotTaskDlg;
@@ -726,6 +1015,12 @@
      m_pPanelMaster->DestroyWindow();
      delete m_pPanelMaster;
      m_pPanelMaster = nullptr;
   }
   if (m_pPanelProduction != nullptr) {
      m_pPanelProduction->DestroyWindow();
      delete m_pPanelProduction;
      m_pPanelProduction = nullptr;
   }
   if (m_pPanelEquipment != nullptr) {
@@ -828,9 +1123,16 @@
   
   int nPanelWidth = 0;
   if (m_pPanelMaster != nullptr) {
   if (m_pPanelMaster != nullptr && ::IsWindow(m_pPanelMaster->GetSafeHwnd())
      && m_pPanelMaster->IsWindowVisible()) {
      nPanelWidth = m_pPanelMaster->getPanelWidth();
      m_pPanelMaster->MoveWindow(x, y, nPanelWidth, y2 - y);
      x += nPanelWidth;
   }
   if (m_pPanelProduction != nullptr && m_pPanelProduction->IsWindowVisible()) {
      nPanelWidth = m_pPanelProduction->getPanelWidth();
      m_pPanelProduction->MoveWindow(x, y, nPanelWidth, y2 - y);
      x += nPanelWidth;
   }
@@ -865,9 +1167,35 @@
   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()
{
   // TODO: 在此添加消息处理程序代码和/或调用默认值
   // TODO: 在此添加消息处理程序代码和/或调用默认值
   CDialogEx::OnClose();
}
@@ -892,7 +1220,7 @@
void CServoDlg::OnTimer(UINT_PTR nIDEvent)
{
   if (TIMER_ID_CREATE_TERMINAL == nIDEvent) {
      // 预先创建终端窗口
      // 预先创建终端窗口
      KillTimer(TIMER_ID_CREATE_TERMINAL);
      char szBuffer[MAX_PATH];
      sprintf_s(szBuffer, MAX_PATH, "%s\\RES\\TeminalMsg.html", (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
@@ -911,11 +1239,23 @@
      m_pMyStatusbar->setRunTimeText((LPTSTR)(LPCTSTR)strText);
   }
   else if(TIMER_ID_TEST == nIDEvent){
      static __int64 tttt = 0;
      tttt++;
      theApp.m_model.m_hsmsPassive.setVariableValue("CJobSpace", tttt % 10);
      theApp.m_model.m_hsmsPassive.setVariableValue("PJobSpace", tttt % 5);
   else if(TIMER_ID_LOGIN == nIDEvent){
      KillTimer(TIMER_ID_LOGIN);
      if (!CUserManager2::getInstance().isLoggedIn()) {
         CLoginDlg2 dlg;
         if (dlg.DoModal() != IDOK) {
            PostMessage(WM_CLOSE);
         }
         else {
            bool bRet = CUserManager2::getInstance().login((LPTSTR)(LPCTSTR)dlg.m_strUsername,
               (LPTSTR)(LPCTSTR)dlg.m_strPassword);
            if (!bRet) {
               AfxMessageBox("登录失败,请检查用户名或密码是否正确!");
               PostMessage(WM_CLOSE);
            }
            UpdateLoginStatus();
         }
      }
   }
@@ -925,7 +1265,20 @@
LRESULT CServoDlg::OnPanelResize(WPARAM wParam, LPARAM lParam)
{
   int width = (int)wParam;
   // m_pPanel->SetPanelWidth(width);
   if (m_pPanelMaster != nullptr) {
      m_pPanelMaster->setPanelWidth(width);
   }
   if (m_pPanelProduction != nullptr) {
      m_pPanelProduction->setPanelWidth(width);
   }
   CString strIniFile, strValue;
   strIniFile.Format(_T("%s\\%s.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir, (LPTSTR)(LPCTSTR)theApp.m_strAppFile);
   strValue.Format(_T("%d"), width);
   WritePrivateProfileString(_T("App"), _T("MasterPanelWidth"),
      (LPTSTR)(LPCTSTR)strValue, (LPTSTR)(LPCTSTR)strIniFile);
   Resize();
   return 0;
@@ -953,64 +1306,41 @@
void CServoDlg::UpdateLoginStatus()
{
   HMENU hMenu = m_pTopToolbar->GetOperatorMenu();
   UserManager& userManager = UserManager::getInstance();
   if (userManager.isLoggedIn())
   {
      ::EnableMenuItem(hMenu, ID_OPEATOR_LOGIN, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
      ::EnableMenuItem(hMenu, ID_OPERATOR_CHANGE_PASSWORD, MF_BYCOMMAND | MF_ENABLED);
   CUserManager2& userManager = CUserManager2::getInstance();
   if (userManager.isLoggedIn()) {
      ::EnableMenuItem(hMenu, ID_OPERATOR_SYSTEM_LOG, MF_BYCOMMAND | MF_ENABLED);
      ::EnableMenuItem(hMenu, ID_OPEATOR_SWITCH, MF_BYCOMMAND | MF_ENABLED);
      ::EnableMenuItem(hMenu, ID_OPERATOR_LOGOUT, MF_BYCOMMAND | MF_ENABLED);
      if (userManager.getCurrentUserRole() == UserRole::SuperAdmin) {
      if (userManager.IsAdminCurrent()) {
         ::EnableMenuItem(hMenu, ID_OPEATOR_USER_MANAGER, MF_BYCOMMAND | MF_ENABLED);
      }
      else {
         ::EnableMenuItem(hMenu, ID_OPEATOR_USER_MANAGER, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
      }
      m_pTopToolbar->SetOperatorBtnText(userManager.getCurrentUser().c_str());
      m_pTopToolbar->SetOperatorBtnText(userManager.getCurrentUserName().c_str());
   }
   else {
      ::EnableMenuItem(hMenu, ID_OPEATOR_LOGIN, MF_BYCOMMAND | MF_ENABLED);
      ::EnableMenuItem(hMenu, ID_OPERATOR_CHANGE_PASSWORD, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
      ::EnableMenuItem(hMenu, ID_OPEATOR_USER_MANAGER, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
      ::EnableMenuItem(hMenu, ID_OPERATOR_SYSTEM_LOG, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
      ::EnableMenuItem(hMenu, ID_OPEATOR_SWITCH, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
      ::EnableMenuItem(hMenu, ID_OPERATOR_LOGOUT, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
      m_pTopToolbar->SetOperatorBtnText(_T("未登录"));
      m_pTopToolbar->SetOperatorBtnText(_T("未登录"));
   }
}
LRESULT CServoDlg::OnToolbarBtnClicked(WPARAM wParam, LPARAM lParam)
{
   int id = (int)lParam;
   if (id == IDC_BUTTON_RUN || id == IDC_BUTTON_STOP) {
      //CInputDialog inputDialog(_T("验证用户"), _T("请输入用户密码:"));
      //if (inputDialog.DoModal() != IDOK) {
      //   AfxMessageBox(_T("取消验证!"));
      //   return 0;
      //}
      //CString inputText = inputDialog.GetInputText();
      //std::string strPass = UserManager::getInstance().getCurrentPass();
      //if (inputText.Compare(strPass.c_str()) != 0) {
      //   AfxMessageBox(_T("密码错误!"));
      //   SystemLogManager::getInstance().log(SystemLogManager::LogType::Info, _T("验证时,密码错误!"));
      //   return 0;
      //}
      UserRole emRole = UserManager::getInstance().getCurrentUserRole();
      if (emRole != UserRole::SuperAdmin) {
         AfxMessageBox(_T("当前用户并非管理员!!!"));
         return 1;
      }
   }
   if (id == IDC_BUTTON_RUN) {
      int rc = UX_CanExecute(L"start");
      if (rc != 1) {
         AfxMessageBox("操作权限不足,请联系管理人员!");
         return 0;
      }
      UX_RecordAction(L"start");
      if (theApp.m_model.getMaster().getState() == SERVO::MASTERSTATE::MSERROR) {
         AfxMessageBox("当前有机台发生错误,不能启动,请确认解决问题后再尝试重新启动!");
         AfxMessageBox("当前有机台发生错误,不能启动,请确认解决问题后再尝试重新启动!");
      }
      else {
         if (theApp.m_model.getMaster().start() == 0) {
@@ -1022,7 +1352,7 @@
   }
   else if (id == IDC_BUTTON_RUN_BATCH) {
      if (theApp.m_model.getMaster().getState() == SERVO::MASTERSTATE::MSERROR) {
         AfxMessageBox("当前有机台发生错误,不能启动,请确认解决问题后再尝试重新启动!");
         AfxMessageBox("当前有机台发生错误,不能启动,请确认解决问题后再尝试重新启动!");
      }
      else {
         if (theApp.m_model.getMaster().startBatch() == 0) {
@@ -1034,7 +1364,7 @@
   }
   else if (id == IDC_BUTTON_RUN_CT) {
      if (theApp.m_model.getMaster().getState() == SERVO::MASTERSTATE::MSERROR) {
         AfxMessageBox("当前有机台发生错误,不能启动,请确认解决问题后再尝试重新启动!");
         AfxMessageBox("当前有机台发生错误,不能启动,请确认解决问题后再尝试重新启动!");
      }
      else {
         if (theApp.m_model.getMaster().startContinuousTransfer() == 0) {
@@ -1045,17 +1375,27 @@
      }
   }
   else if (id == IDC_BUTTON_STOP) {
      int rc = UX_CanExecute(L"stop");
      if (rc != 1) {
         AfxMessageBox("操作权限不足,请联系管理人员!");
         return 0;
      }
      UX_RecordAction(L"stop");
      if (theApp.m_model.getMaster().stop() == 0) {
         m_pTopToolbar->GetBtn(IDC_BUTTON_STOP)->EnableWindow(FALSE);
      }
   }
   else if (id == IDC_BUTTON_JOBS) {
      CControlJobDlg dlg;
      dlg.SetControlJob(theApp.m_model.m_master.getControlJob());
      dlg.DoModal();
   }
   else if (id == IDC_BUTTON_PORT_CONFIG) {
      CPortConfigurationDlg dlg;
      dlg.DoModal();
   }
   else if (id == IDC_BUTTON_CASSETTE) {
      CControlJobManagerDlg dlg;
      dlg.DoModal();
   }
   else if (id == IDC_BUTTON_ROBOT) {
@@ -1064,6 +1404,16 @@
      CRobotCmdTestDlg dlg;
      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);
@@ -1077,6 +1427,27 @@
   }
   else if (id == IDC_BUTTON_OPERATOR) {
      int menuId = (int)wParam;
      if (menuId == 0) {
         CUserManager2Dlg dlg;
         dlg.DoModal();
      }
      else if (menuId == 1) {
         CUserXLogDlg dlg;
         dlg.DoModal();
      }
      else if (menuId == 2) {
         CLoginDlg2 dlg;
         if (dlg.DoModal() == IDOK) {
            bool bRet = CUserManager2::getInstance().login((LPTSTR)(LPCTSTR)dlg.m_strUsername,
               (LPTSTR)(LPCTSTR)dlg.m_strPassword);
            if (!bRet) {
               AfxMessageBox("登录失败,请检查用户名或密码是否正确!");
            }
            UpdateLoginStatus();
         }
      }
      /*
      SystemLogManager& logManager = SystemLogManager::getInstance();
      UserManager& userManager = UserManager::getInstance();
      if (menuId == 0) {
@@ -1090,7 +1461,7 @@
      else if (2 == menuId) {
         CUserManagerDlg dlg;
         if (dlg.DoModal() != IDOK) {
            logManager.log(SystemLogManager::LogType::Operation, _T("用户管理的预操作被取消!"));
            logManager.log(SystemLogManager::LogType::Operation, _T("用户管理的预操作被取消!"));
         }
      }
      else if (3 == menuId) {
@@ -1098,14 +1469,14 @@
         dlg.DoModal();
      }
      else if (4 == menuId) {
         int ret = AfxMessageBox(_T("是否切换用户?切换用户会退出当前账号!"), MB_OKCANCEL | MB_ICONEXCLAMATION);
         int ret = AfxMessageBox(_T("是否切换用户?切换用户会退出当前账号!"), MB_OKCANCEL | MB_ICONEXCLAMATION);
         if (ret != IDOK) {
            return 0;
         }
         logManager.log(SystemLogManager::LogType::Operation, _T("确认切换角色!"));
         logManager.log(SystemLogManager::LogType::Operation, _T("确认切换角色!"));
         if (userManager.isLoggedIn()) {
            logManager.log(SystemLogManager::LogType::Info, _T("退出登录!"));
            logManager.log(SystemLogManager::LogType::Info, _T("退出登录!"));
            userManager.logout();
         }
@@ -1114,17 +1485,18 @@
      }
      else {
         CString cstrMessage;
         cstrMessage.Format(_T("是否退出用户 [%s]?"), userManager.getCurrentUser().c_str());
         cstrMessage.Format(_T("是否退出用户 [%s]?"), userManager.getCurrentUser().c_str());
         int ret = AfxMessageBox(_T(cstrMessage), MB_OKCANCEL | MB_ICONEXCLAMATION);
         if (ret != IDOK) {
            return 0;
         }
         logManager.log(SystemLogManager::LogType::Info, _T("退出登录!"));
         logManager.log(SystemLogManager::LogType::Info, _T("退出登录!"));
         userManager.logout();
      }
      UpdateLoginStatus();
      */
   }
   return 0;
@@ -1154,6 +1526,11 @@
   return 0;
}
BOOL CServoDlg::PreTranslateMessage(MSG* pMsg)
{
   return CDialogEx::PreTranslateMessage(pMsg);
}
CString& CServoDlg::GetRuntimeFormatText(CString& strText, const char* pszSuffix)
{
   ULONGLONG ullRunTime = (ULONGLONG)(theApp.m_model.getMaster().getRunTime() * 0.001);
@@ -1164,17 +1541,17 @@
   SERVO::MASTERSTATE state = theApp.m_model.getMaster().getState();
   if (state == SERVO::MASTERSTATE::RUNNING) {
      strText.Format(_T("正在运行:%02d:%02d:%02d   %s"), h, m, s, pszSuffix);
      strText.Format(_T("正在运行:%02d:%02d:%02d   %s"), h, m, s, pszSuffix);
   }
   else if (state == SERVO::MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER) {
      strText.Format(_T("千传模式:%02d:%02d:%02d   %s"), h, m, s, pszSuffix);
      strText.Format(_T("千传模式:%02d:%02d:%02d   %s"), h, m, s, pszSuffix);
   }
   else if (state == SERVO::MASTERSTATE::RUNNING_BATCH) {
      strText.Format(_T("JOB模式:%02d:%02d:%02d   %s"), h, m, s, pszSuffix);
      strText.Format(_T("JOB模式:%02d:%02d:%02d   %s"), h, m, s, pszSuffix);
   }
   else {
      strText.Format(_T("已运行:%02d:%02d:%02d   %s"), h, m, s, pszSuffix);
      strText.Format(_T("已运行:%02d:%02d:%02d   %s"), h, m, s, pszSuffix);
   }
   return strText;
}
}