chenluhua1980
2026-01-19 44360bc2cdeee16be72f9cc4bfb42e0ac26b5b44
SourceCode/Bond/Servo/RecipeDeviceBindDlg.cpp
@@ -14,12 +14,12 @@
// 绑定界面需要显示的设备
static const std::vector<DeviceMetaInfo> g_vecBindDevices = {
    { EQ_ID_VACUUMBAKE,      EQ_NAME_VACUUMBAKE },
    { EQ_ID_Bonder1,         EQ_NAME_BONDER1 },
    { EQ_ID_Bonder2,         EQ_NAME_BONDER2 },
    { EQ_ID_BAKE_COOLING,    EQ_NAME_BAKE_COOLING },
    { EQ_ID_MEASUREMENT,     EQ_NAME_MEASUREMENT },
    { EQ_ID_EFEM,            EQ_NAME_EFEM }
   { EQ_ID_VACUUMBAKE,      EQ_NAME_VACUUMBAKE },
   { EQ_ID_Bonder1,         EQ_NAME_BONDER1 },
   { EQ_ID_Bonder2,         EQ_NAME_BONDER2 },
   { EQ_ID_BAKE_COOLING,    EQ_NAME_BAKE_COOLING },
   { EQ_ID_MEASUREMENT,     EQ_NAME_MEASUREMENT },
   { EQ_ID_EFEM,            EQ_NAME_EFEM }
};
// CRecipeDeviceBindDlg 对话框
@@ -28,8 +28,8 @@
CRecipeDeviceBindDlg::CRecipeDeviceBindDlg(CWnd* pParent /*=nullptr*/)
   : CDialogEx(IDD_DIALOG_RECIPE_DEVICE_BIND, pParent)
    , m_strPPID(_T(""))
    , m_strDesc(_T(""))
   , m_strPPID(_T(""))
   , m_strDesc(_T(""))
{
}
@@ -39,122 +39,129 @@
}
const RecipeInfo& CRecipeDeviceBindDlg::GetRecipeInfo() const {
    return m_recipe;
   return m_recipe;
}
void CRecipeDeviceBindDlg::SetRecipeInfo(const RecipeInfo& info)
{
    m_recipe = info;
   m_recipe = info;
}
void CRecipeDeviceBindDlg::ReleaseDeviceControls()
{
    for (auto& ctrl : m_vecDevices) {
        delete ctrl.editDeviceID;    ctrl.editDeviceID = nullptr;
        delete ctrl.editDeviceName;  ctrl.editDeviceName = nullptr;
        delete ctrl.comboRecipeID;   ctrl.comboRecipeID = nullptr;
    }
    m_vecDevices.clear();
   for (auto& ctrl : m_vecDevices) {
      delete ctrl.editDeviceID;    ctrl.editDeviceID = nullptr;
      delete ctrl.editDeviceName;  ctrl.editDeviceName = nullptr;
      delete ctrl.comboRecipeID;   ctrl.comboRecipeID = nullptr;
   }
   m_vecDevices.clear();
}
void CRecipeDeviceBindDlg::CreateDeviceControls(int nXStart, int nYStart, int nTotalControlWidth, int nRowHeight)
{
    for (size_t i = 0; i < g_vecBindDevices.size(); ++i) {
        int y = nYStart + static_cast<int>(i) * nRowHeight;
        auto* pEditID = new CEdit;
        pEditID->Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_CENTER, CRect(nXStart, y, nXStart + 100, y + 25), this, (UINT)(IDC_EDIT_DEVICEID_BASE + i));
        pEditID->SetFont(&m_font);
   for (size_t i = 0; i < g_vecBindDevices.size(); ++i) {
      int y = nYStart + static_cast<int>(i) * nRowHeight;
      auto* pEditID = new CEdit;
      pEditID->Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_CENTER, CRect(nXStart, y, nXStart + 100, y + 25), this, (UINT)(IDC_EDIT_DEVICEID_BASE + i));
      pEditID->SetFont(&m_font);
        auto* pEditName = new CEdit;
        pEditName->Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_CENTER, CRect(nXStart + 110, y, nXStart + 210, y + 25), this, (UINT)(IDC_EDIT_DEVICENAME_BASE + i));
        pEditName->SetFont(&m_font);
      auto* pEditName = new CEdit;
      pEditName->Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_CENTER, CRect(nXStart + 110, y, nXStart + 210, y + 25), this, (UINT)(IDC_EDIT_DEVICENAME_BASE + i));
      pEditName->SetFont(&m_font);
        auto* pCombo = new CComboBox;
        pCombo->Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, CRect(nXStart + 220, y, nXStart + nTotalControlWidth, y + 25), this, (UINT)(IDC_COMBO_RECIPEID_BASE + i));
        pCombo->SetFont(&m_font);
      auto* pCombo = new CComboBox;
      pCombo->Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, CRect(nXStart + 220, y, nXStart + nTotalControlWidth, y + 25), this, (UINT)(IDC_COMBO_RECIPEID_BASE + i));
      pCombo->SetFont(&m_font);
        m_vecDevices.push_back({ pEditID, pEditName, pCombo });
    }
      m_vecDevices.push_back({ pEditID, pEditName, pCombo });
   }
}
bool CRecipeDeviceBindDlg::FillComboRecipeList(CComboBox* pCombo, int nDeviceID, int nSelectedRecipeID)
{
    auto& master = theApp.m_model.getMaster();
    auto* pEq = master.getEquipment(nDeviceID);
    if (!pEq) {
        return false;
    }
   auto& master = theApp.m_model.getMaster();
   auto* pEq = master.getEquipment(nDeviceID);
   if (!pEq) {
      return false;
   }
    auto* pRecipeList = pEq->getRecipeList(0);
    if (!pRecipeList) {
        return false;
    }
   auto* pRecipeList = pEq->getRecipeList(0);
   if (!pRecipeList) {
      return false;
   }
    auto& mapRecipeIds = pRecipeList->getIds();
    bool bFound = false;
    pCombo->ResetContent();
    for (const auto& pair : mapRecipeIds) {
        int nRecipeID = pair.second;
   auto& mapRecipeIds = pRecipeList->getIds();
   bool bFound = false;
   pCombo->ResetContent();
   for (const auto& pair : mapRecipeIds) {
      int nRecipeID = pair.second;
        std::string strRecipeName = RecipeManager::getInstance().getDeviceRecipeName(pEq->getName(), nRecipeID);
        if (strRecipeName.empty()) {
            strRecipeName = std::to_string(nRecipeID);
        }
      std::string strDeviceName;
      for (const auto& dev : g_vecBindDevices) {
         if (dev.nDeviceID == pEq->getID()) {
            strDeviceName = dev.strDeviceName;
         }
      }
        CString str;
        str.Format(_T("%s"), strRecipeName.c_str());
        int idx = pCombo->AddString(str);
        pCombo->SetItemData(idx, nRecipeID);
        if (nSelectedRecipeID == nRecipeID) {
            pCombo->SetCurSel(idx);
            bFound = true;
        }
    }
      std::string strRecipeName = RecipeManager::getInstance().getDeviceRecipeName(strDeviceName, nRecipeID);
      if (strRecipeName.empty()) {
         strRecipeName = std::to_string(nRecipeID);
      }
    if (nSelectedRecipeID != -1 && !bFound) {
        pCombo->SetCurSel(CB_ERR);
    }
    else if (pCombo->GetCount() > 0 && nSelectedRecipeID == -1) {
        pCombo->SetCurSel(0);
    }
      CString str;
      str.Format(_T("%s"), strRecipeName.c_str());
      int idx = pCombo->AddString(str);
      pCombo->SetItemData(idx, nRecipeID);
      if (nSelectedRecipeID == nRecipeID) {
         pCombo->SetCurSel(idx);
         bFound = true;
      }
   }
    return true;
   if (nSelectedRecipeID != -1 && !bFound) {
      pCombo->SetCurSel(CB_ERR);
   }
   else if (pCombo->GetCount() > 0 && nSelectedRecipeID == -1) {
      pCombo->SetCurSel(0);
   }
   return true;
}
bool CRecipeDeviceBindDlg::FillDeviceInfo(int idx, int nDeviceID, const CString& strDeviceName, int nSelectedRecipeID)
{
    if (idx < 0 || idx >= (int)m_vecDevices.size()) {
        return false;
    }
   if (idx < 0 || idx >= (int)m_vecDevices.size()) {
      return false;
   }
    auto& ctrl = m_vecDevices[idx];
    CString strID;
    strID.Format(_T("%d"), nDeviceID);
    ctrl.editDeviceID->SetWindowText(strID);
    ctrl.editDeviceID->SetReadOnly(TRUE);
    ctrl.editDeviceName->SetWindowText(strDeviceName);
    ctrl.editDeviceName->SetReadOnly(TRUE);
   auto& ctrl = m_vecDevices[idx];
   CString strID;
   strID.Format(_T("%d"), nDeviceID);
   ctrl.editDeviceID->SetWindowText(strID);
   ctrl.editDeviceID->SetReadOnly(TRUE);
   ctrl.editDeviceName->SetWindowText(strDeviceName);
   ctrl.editDeviceName->SetReadOnly(TRUE);
    if (!FillComboRecipeList(ctrl.comboRecipeID, nDeviceID, nSelectedRecipeID)) {
        CString str;
        str.Format(_T("设备 [%s] 或其配方列表未找到,请检查设备配置"), strDeviceName.GetString());
        AfxMessageBox(str);
        return false;
    }
    return true;
   if (!FillComboRecipeList(ctrl.comboRecipeID, nDeviceID, nSelectedRecipeID)) {
      CString str;
      str.Format(_T("设备 [%s] 或其配方列表未找到,请检查设备配置"), strDeviceName.GetString());
      AfxMessageBox(str);
      return false;
   }
   return true;
}
void CRecipeDeviceBindDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_EDIT_PPID, m_strPPID);
    DDX_Text(pDX, IDC_EDIT_DESC, m_strDesc);
   CDialogEx::DoDataExchange(pDX);
   DDX_Text(pDX, IDC_EDIT_PPID, m_strPPID);
   DDX_Text(pDX, IDC_EDIT_DESC, m_strDesc);
}
BEGIN_MESSAGE_MAP(CRecipeDeviceBindDlg, CDialogEx)
    ON_WM_CLOSE()
    ON_WM_SIZE()
    ON_BN_CLICKED(IDOK, &CRecipeDeviceBindDlg::OnBnClickedOk)
   ON_WM_CLOSE()
   ON_WM_SIZE()
   ON_BN_CLICKED(IDOK, &CRecipeDeviceBindDlg::OnBnClickedOk)
END_MESSAGE_MAP()
@@ -165,62 +172,62 @@
   CDialogEx::OnInitDialog();
   // 设置对话框标题
    SetWindowText(m_recipe.vecDeviceList.empty() ? _T("新建配方") : _T("编辑配方"));
   SetWindowText(m_recipe.vecDeviceList.empty() ? _T("新建配方") : _T("编辑配方"));
   // 创建动态控件字体
    if (!m_font.m_hObject) {
        CFont* pDlgFont = GetFont();
        LOGFONT lf;
        if (pDlgFont && pDlgFont->GetLogFont(&lf)) {
            lf.lfHeight = -16;
            m_font.CreateFontIndirect(&lf);
        }
    }
   if (!m_font.m_hObject) {
      CFont* pDlgFont = GetFont();
      LOGFONT lf;
      if (pDlgFont && pDlgFont->GetLogFont(&lf)) {
         lf.lfHeight = -16;
         m_font.CreateFontIndirect(&lf);
      }
   }
    // 计算坐标
    CRect rDesc;
    int nXStart = 30, nYStart = 30, nTotalControlWidth = 340;
    if (auto* pWndDesc = GetDlgItem(IDC_STATIC_DESC)) {
        pWndDesc->GetWindowRect(&rDesc); ScreenToClient(&rDesc);
        nXStart = rDesc.left;
    }
    if (auto* pWndEdit = GetDlgItem(IDC_EDIT_DESC)) {
        pWndEdit->GetWindowRect(&rDesc); ScreenToClient(&rDesc);
        nYStart = rDesc.bottom + 20;
    }
    CRect rClient; GetClientRect(&rClient);
    nTotalControlWidth = rClient.Width() - nXStart * 2;
    const int nRowHeight = 30;
   // 计算坐标
   CRect rDesc;
   int nXStart = 30, nYStart = 30, nTotalControlWidth = 340;
   if (auto* pWndDesc = GetDlgItem(IDC_STATIC_DESC)) {
      pWndDesc->GetWindowRect(&rDesc); ScreenToClient(&rDesc);
      nXStart = rDesc.left;
   }
   if (auto* pWndEdit = GetDlgItem(IDC_EDIT_DESC)) {
      pWndEdit->GetWindowRect(&rDesc); ScreenToClient(&rDesc);
      nYStart = rDesc.bottom + 20;
   }
   CRect rClient; GetClientRect(&rClient);
   nTotalControlWidth = rClient.Width() - nXStart * 2;
   const int nRowHeight = 30;
    // 清空旧控件
    ReleaseDeviceControls();
   // 清空旧控件
   ReleaseDeviceControls();
    // 创建新控件
    CreateDeviceControls(nXStart, nYStart, nTotalControlWidth, nRowHeight);
   // 创建新控件
   CreateDeviceControls(nXStart, nYStart, nTotalControlWidth, nRowHeight);
    auto& master = theApp.m_model.getMaster();
   auto& master = theApp.m_model.getMaster();
    // 填充内容
    if (m_recipe.vecDeviceList.empty()) {
        // 新建
        for (size_t i = 0; i < g_vecBindDevices.size(); ++i) {
            const auto& meta = g_vecBindDevices[i];
            FillDeviceInfo((int)i, meta.nDeviceID, meta.strDeviceName);
        }
    }
    else {
        // 编辑
        m_strPPID = CA2T(m_recipe.strPPID.c_str());
        m_strDesc = CA2T(m_recipe.strDescription.c_str());
        UpdateData(FALSE);
   // 填充内容
   if (m_recipe.vecDeviceList.empty()) {
      // 新建
      for (size_t i = 0; i < g_vecBindDevices.size(); ++i) {
         const auto& meta = g_vecBindDevices[i];
         FillDeviceInfo((int)i, meta.nDeviceID, meta.strDeviceName);
      }
   }
   else {
      // 编辑
      m_strPPID = CA2T(m_recipe.strPPID.c_str());
      m_strDesc = CA2T(m_recipe.strDescription.c_str());
      UpdateData(FALSE);
        for (size_t i = 0; i < m_recipe.vecDeviceList.size() && i < m_vecDevices.size(); ++i) {
            const auto& d = m_recipe.vecDeviceList[i];
            FillDeviceInfo((int)i, d.nDeviceID, d.strDeviceName.c_str(), d.nRecipeID);
        }
    }
      for (size_t i = 0; i < m_recipe.vecDeviceList.size() && i < m_vecDevices.size(); ++i) {
         const auto& d = m_recipe.vecDeviceList[i];
         FillDeviceInfo((int)i, d.nDeviceID, d.strDeviceName.c_str(), d.nRecipeID);
      }
   }
    CenterWindow();
   CenterWindow();
   return TRUE;  // return TRUE unless you set the focus to a control
   // 异常: OCX 属性页应返回 FALSE
@@ -228,53 +235,53 @@
void CRecipeDeviceBindDlg::OnClose()
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    CDialogEx::OnClose();
   // TODO: 在此添加消息处理程序代码和/或调用默认值
   CDialogEx::OnClose();
    // 清理控件
    ReleaseDeviceControls();
   // 清理控件
   ReleaseDeviceControls();
}
void CRecipeDeviceBindDlg::OnSize(UINT nType, int cx, int cy)
{
    CDialogEx::OnSize(nType, cx, cy);
   CDialogEx::OnSize(nType, cx, cy);
    // TODO: 在此处添加消息处理程序代码
   // TODO: 在此处添加消息处理程序代码
}
void CRecipeDeviceBindDlg::OnBnClickedOk()
{
    // TODO: 在此添加控件通知处理程序代码
    UpdateData(TRUE);
   // TODO: 在此添加控件通知处理程序代码
   UpdateData(TRUE);
    // 收集所有设备映射
    m_recipe.vecDeviceList.clear();
    for (const auto& dev : m_vecDevices) {
        DeviceRecipe info;
        CString strID, strName;
        dev.editDeviceID->GetWindowText(strID);
        dev.editDeviceName->GetWindowText(strName);
   // 收集所有设备映射
   m_recipe.vecDeviceList.clear();
   for (const auto& dev : m_vecDevices) {
      DeviceRecipe info;
      CString strID, strName;
      dev.editDeviceID->GetWindowText(strID);
      dev.editDeviceName->GetWindowText(strName);
        int sel = dev.comboRecipeID->GetCurSel();
        info.nRecipeID = -1;
        if (sel != CB_ERR) {
            info.nRecipeID = (int)dev.comboRecipeID->GetItemData(sel);
        }
        info.nDeviceID = _ttoi(strID);
        info.strDeviceName = CT2A(strName);
      int sel = dev.comboRecipeID->GetCurSel();
      info.nRecipeID = -1;
      if (sel != CB_ERR) {
         info.nRecipeID = (int)dev.comboRecipeID->GetItemData(sel);
      }
      info.nDeviceID = _ttoi(strID);
      info.strDeviceName = CT2A(strName);
        m_recipe.vecDeviceList.push_back(info);
    }
      m_recipe.vecDeviceList.push_back(info);
   }
    // 检查 PPID 是否为空
    if (m_strPPID.IsEmpty()) {
        AfxMessageBox(_T("配方 PPID 不能为空"));
        return;
    }
   // 检查 PPID 是否为空
   if (m_strPPID.IsEmpty()) {
      AfxMessageBox(_T("配方 PPID 不能为空"));
      return;
   }
    // PPID和描述
    m_recipe.strPPID = CT2A(m_strPPID);
    m_recipe.strDescription = CT2A(m_strDesc);
   // PPID和描述
   m_recipe.strPPID = CT2A(m_strPPID);
   m_recipe.strDescription = CT2A(m_strDesc);
    CDialogEx::OnOK();
   CDialogEx::OnOK();
}