mrDarker
2025-07-22 b25d01dd43f27e34940de13a4efb54033f3007df
SourceCode/Bond/Servo/RecipeDeviceBindDlg.cpp
@@ -5,7 +5,22 @@
#include "Servo.h"
#include "afxdialogex.h"
#include "RecipeDeviceBindDlg.h"
#include "RecipeManager.h"
#include "Common.h"
#define IDC_EDIT_DEVICEID_BASE     3000
#define IDC_EDIT_DEVICENAME_BASE   3050
#define IDC_COMBO_RECIPEID_BASE    3100
// 绑定界面需要显示的设备
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 }
};
// CRecipeDeviceBindDlg 对话框
@@ -13,6 +28,8 @@
CRecipeDeviceBindDlg::CRecipeDeviceBindDlg(CWnd* pParent /*=nullptr*/)
   : CDialogEx(IDD_DIALOG_RECIPE_DEVICE_BIND, pParent)
    , m_strPPID(_T(""))
    , m_strDesc(_T(""))
{
}
@@ -21,14 +38,234 @@
{
}
void CRecipeDeviceBindDlg::DoDataExchange(CDataExchange* pDX)
{
   CDialogEx::DoDataExchange(pDX);
const RecipeInfo& CRecipeDeviceBindDlg::GetRecipeInfo() const {
    return m_recipe;
}
void CRecipeDeviceBindDlg::SetRecipeInfo(const RecipeInfo& info)
{
    m_recipe = info;
}
void CRecipeDeviceBindDlg::DoDataExchange(CDataExchange* pDX)
{
    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)
END_MESSAGE_MAP()
// CRecipeDeviceBindDlg 消息处理程序
BOOL CRecipeDeviceBindDlg::OnInitDialog()
{
   CDialogEx::OnInitDialog();
   // 设置对话框标题
    SetWindowText(m_recipe.vecDeviceList.empty() ? _T("新建配方") : _T("编辑配方"));
    if (m_font.m_hObject == NULL) {
        // 获取对话框的字体
        CFont* pDlgFont = GetFont();
        LOGFONT lf;
        if (pDlgFont && pDlgFont->GetLogFont(&lf)) {
            m_font.CreateFontIndirect(&lf);
        }
    }
    // 计算x起始坐标
    CWnd* pWndDesc = GetDlgItem(IDC_STATIC_DESC);
    CRect rDesc;
    int nYStart = 0;
    int nXStart = 0;
    int nTotalControlWidth = 340; // 默认兜底
    if (pWndDesc) {
        pWndDesc->GetWindowRect(&rDesc);
        ScreenToClient(&rDesc);
        nXStart = rDesc.left;
    }
    else {
        nXStart = 30;
    }
    // 计算x起始坐标
    pWndDesc = GetDlgItem(IDC_EDIT_DESC);
    if (pWndDesc) {
        pWndDesc->GetWindowRect(&rDesc);
        ScreenToClient(&rDesc);
        nYStart = rDesc.bottom + 20;
    }
    else {
        nYStart = 30;
    }
    // 保证每次进来都清空
    for (auto& ctrl : m_vecDevices) {
        if (ctrl.editDeviceID) {
            delete ctrl.editDeviceID;
         ctrl.editDeviceID = nullptr;
        }
        if (ctrl.editDeviceName) {
            delete ctrl.editDeviceName;
         ctrl.editDeviceName = nullptr;
        }
        if (ctrl.comboRecipeID) {
            delete ctrl.comboRecipeID;
         ctrl.comboRecipeID = nullptr;
        }
    }
    m_vecDevices.clear();
    // 创建控件(不管新建还是编辑,都先创建好)
    CRect rClient;
    GetClientRect(&rClient);
    nTotalControlWidth = (rClient.Width() - nXStart * 2);
    const int nRowHeight = 30;
    const int nRowCount = static_cast<int>(g_vecBindDevices.size());
    for (int i = 0; i < nRowCount; ++i) {
        int y = nYStart + i * nRowHeight;
        const auto& meta = g_vecBindDevices[i];
        CEdit* pEditID = new CEdit();
        pEditID->Create(WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(nXStart, y, nXStart + 100, y + 25), this, IDC_EDIT_DEVICEID_BASE + i);
        CEdit* pEditName = new CEdit();
        pEditName->Create(WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(nXStart + 110, y, nXStart + 210, y + 25), this, IDC_EDIT_DEVICENAME_BASE + i);
        CComboBox* pCombo = new CComboBox();
        pCombo->Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, CRect(nXStart + 220, y, nXStart + nTotalControlWidth, y + 25), this, IDC_COMBO_RECIPEID_BASE + i);
        pEditID->SetFont(&m_font);
        pEditName->SetFont(&m_font);
        pCombo->SetFont(&m_font);
        m_vecDevices.push_back({ pEditID, pEditName, pCombo });
    }
    // 填充内容
    if (m_recipe.vecDeviceList.empty()) {
        // 新建模式
        for (int i = 0; i < nRowCount; ++i) {
            const auto& meta = g_vecBindDevices[i];
            CString strID;
            strID.Format(_T("%d"), meta.nDeviceID);
            m_vecDevices[i].editDeviceID->SetWindowText(strID);
            m_vecDevices[i].editDeviceID->SetReadOnly(TRUE);
            m_vecDevices[i].editDeviceName->SetWindowText(CA2T(meta.strDeviceName));
            m_vecDevices[i].editDeviceName->SetReadOnly(TRUE);
            // 这里你可以初始化 ComboBox 选项,例如:
            // for (const auto& r : GetRecipeListForDevice(meta.nDeviceID)) {
            //     int idx = m_vecDevices[i].comboRecipeID->AddString(CA2T(r.strRecipeName));
            //     m_vecDevices[i].comboRecipeID->SetItemData(idx, r.nRecipeID);
            // }
        }
    }
    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 DeviceRecipe& d = m_recipe.vecDeviceList[i];
            CString str;
            // 设备ID
            str.Format(_T("%d"), d.nDeviceID);
            m_vecDevices[i].editDeviceID->SetWindowText(str);
            m_vecDevices[i].editDeviceID->SetReadOnly(TRUE);
            // 设备名称
            m_vecDevices[i].editDeviceName->SetWindowText(CA2T(d.strDeviceName.c_str()));
            m_vecDevices[i].editDeviceName->SetReadOnly(TRUE);
            // ComboBox 选项填充
            // for (const auto& r : GetRecipeListForDevice(d.nDeviceID)) {
            //     int idx = m_vecDevices[i].comboRecipeID->AddString(CA2T(r.strRecipeName));
            //     m_vecDevices[i].comboRecipeID->SetItemData(idx, r.nRecipeID);
            //     // 默认选中对应配方ID
            //     if (r.nRecipeID == d.nRecipeID)
            //         m_vecDevices[i].comboRecipeID->SetCurSel(idx);
            // }
        }
    }
   return TRUE;  // return TRUE unless you set the focus to a control
   // 异常: OCX 属性页应返回 FALSE
}
void CRecipeDeviceBindDlg::OnClose()
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    CDialogEx::OnClose();
    // 清理控件
    for (auto& device : m_vecDevices) {
        if (device.editDeviceID) {
            device.editDeviceID->DestroyWindow();
            delete device.editDeviceID;
        }
        if (device.editDeviceName) {
            device.editDeviceName->DestroyWindow();
            delete device.editDeviceName;
        }
        if (device.comboRecipeID) {
            device.comboRecipeID->DestroyWindow();
            delete device.comboRecipeID;
        }
    }
    m_vecDevices.clear();
}
void CRecipeDeviceBindDlg::OnSize(UINT nType, int cx, int cy)
{
    CDialogEx::OnSize(nType, cx, cy);
    // TODO: 在此处添加消息处理程序代码
}
void CRecipeDeviceBindDlg::OnBnClickedOk()
{
    // 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);
        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);
    }
    // 检查 PPID 是否为空
    if (m_strPPID.IsEmpty()) {
        AfxMessageBox(_T("配方 PPID 不能为空"));
        return;
    }
    // PPID和描述
    m_recipe.strPPID = CT2A(m_strPPID);
    m_recipe.strDescription = CT2A(m_strDesc);
    CDialogEx::OnOK();
}