Merge branch 'liuyang' into clh
| | |
| | | #include "Servo.h" |
| | | #include "afxdialogex.h" |
| | | #include "PageRecipe.h" |
| | | #include "MsgDlg.h" |
| | | #include "InputDialog.h" |
| | | #include "RecipeDeviceBindDlg.h" |
| | | |
| | | |
| | |
| | | |
| | | CString strIniFile, strItem; |
| | | strIniFile.Format(_T("%s\\configuration.ini"), (LPCTSTR)theApp.m_strAppDir); |
| | | int width[] = { 0, 60, 150, 150 }; |
| | | int width[] = { 0, 60, 100, 100, 150 }; |
| | | |
| | | for (int i = 0; i < 4; i++) { |
| | | for (int i = 0; i < 5; i++) { |
| | | strItem.Format(_T("Col_Device_%d_Width"), i); |
| | | width[i] = GetPrivateProfileInt(_T("PageRecipeListCtrl"), strItem, width[i], strIniFile); |
| | | } |
| | |
| | | m_listPPID.InsertColumn(1, _T("No."), LVCFMT_CENTER, width[1]); |
| | | m_listPPID.InsertColumn(2, _T("Recipe ID"), LVCFMT_CENTER, width[2]); |
| | | m_listPPID.InsertColumn(3, _T("Recipe 名称"), LVCFMT_CENTER, width[3]); |
| | | m_listPPID.InsertColumn(4, _T("Recipe 参数"), LVCFMT_CENTER, width[4]); |
| | | } |
| | | |
| | | void CPageRecipe::UpdateRecipeByPPID(const CString& strPPID) |
| | |
| | | m_listPPID.SetItemText(i, 2, CA2T(recipe.strPPID.c_str())); |
| | | |
| | | for (int j = 0; j < recipe.vecDeviceList.size(); j++){ |
| | | int nRecipeID = recipe.vecDeviceList.at(j).nRecipeID; |
| | | std::string strDeviceName = recipe.vecDeviceList.at(j).strDeviceName; |
| | | std::string strRecipeName = RecipeManager::getInstance().getDeviceRecipeName(strDeviceName, nRecipeID); |
| | | |
| | | CString str; |
| | | str.Format(_T("%d"), recipe.vecDeviceList.at(j).nRecipeID); |
| | | if (strRecipeName.empty()) { |
| | | str.Format(_T("%d"), recipe.vecDeviceList.at(j).nRecipeID); |
| | | } |
| | | else { |
| | | str.Format(_T("%s"), CA2T(strRecipeName.c_str())); |
| | | } |
| | | |
| | | m_listPPID.SetItemText(i, j + 3, str); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | // 遍历数据并插入到CListCtrl中 |
| | | auto& mgr = RecipeManager::getInstance(); |
| | | std::map<int, short>& ids = pRecipeList->getIds(); |
| | | auto rawDatas = pRecipeList->getParamsRawData(); |
| | | for (auto item : ids) { |
| | |
| | | m_listPPID.SetItemText(index, 1, std::to_string(item.first).c_str()); |
| | | m_listPPID.SetItemText(index, 2, std::to_string(item.second).c_str()); |
| | | |
| | | std::string strRecipeName = mgr.getDeviceRecipeName(pEq->getName(), item.second); |
| | | m_listPPID.SetItemText(index, 3, strRecipeName.c_str()); |
| | | |
| | | std::string strDescription; |
| | | auto iter = rawDatas.find(item.second); |
| | | if (iter != rawDatas.end()) { |
| | | std::string strDescription; |
| | | pEq->parsingParams((const char*)iter->second.data(), iter->second.size(), strDescription); |
| | | m_listPPID.SetItemText(index, 4, strDescription.c_str()); |
| | | } |
| | | |
| | | if (strRecipeName.empty()) { |
| | | strRecipeName = std::to_string(item.second); |
| | | mgr.addDeviceRecipe(pEq->getName(), item.second, strRecipeName, strDescription); |
| | | } |
| | | } |
| | | |
| | |
| | | ON_BN_CLICKED(IDC_BUTTON_DELETE, &CPageRecipe::OnBnClickedButtonDelete) |
| | | ON_BN_CLICKED(IDC_BUTTON_DELETE_ALL, &CPageRecipe::OnBnClickedButtonDeleteAll) |
| | | ON_BN_CLICKED(IDC_BUTTON_REFRESH, &CPageRecipe::OnBnClickedButtonRefresh) |
| | | ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_PPID, &CPageRecipe::OnLvnItemChangedListPPID) |
| | | ON_NOTIFY(NM_CLICK, IDC_LIST_PPID, &CPageRecipe::OnClickListPPID) |
| | | ON_NOTIFY(NM_DBLCLK, IDC_LIST_PPID, &CPageRecipe::OnDblclkListPPID) |
| | | ON_CBN_SELCHANGE(IDC_COMBO_EQUIPMENT, &CPageRecipe::OnCbnSelchangeComboEquipment) |
| | | END_MESSAGE_MAP() |
| | | |
| | |
| | | void CPageRecipe::OnBnClickedButtonModify() |
| | | { |
| | | // TODO: 在此添加控件通知处理程序代码 |
| | | CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT); |
| | | if (pComboBox == nullptr || !::IsWindow(pComboBox->m_hWnd)) { |
| | | return; |
| | | } |
| | | |
| | | POSITION pos = m_listPPID.GetFirstSelectedItemPosition(); |
| | | if (!pos) { |
| | | AfxMessageBox(_T("请先选择一条配方记录进行修改!")); |
| | | return; |
| | | } |
| | | |
| | | int nSel = m_listPPID.GetNextSelectedItem(pos); |
| | | CString strPPID = m_listPPID.GetItemText(nSel, 2); |
| | | UpdateRecipeByPPID(strPPID); |
| | | int nLine = m_listPPID.GetNextSelectedItem(pos); |
| | | CString strID = m_listPPID.GetItemText(nLine, 2); |
| | | |
| | | int nSel = pComboBox->GetCurSel(); |
| | | SERVO::CEquipment* pEq = (SERVO::CEquipment*)pComboBox->GetItemDataPtr(nSel); |
| | | if (pEq == nullptr) { |
| | | UpdateRecipeByPPID(strID); |
| | | } |
| | | else { |
| | | CInputDialog dlg(_T("修改配方名称"), _T("请输入配方名称:")); |
| | | if (dlg.DoModal() != IDOK) { |
| | | return; |
| | | } |
| | | |
| | | CString strText = dlg.GetInputText(); |
| | | if (strText.IsEmpty()) { |
| | | AfxMessageBox(_T("配方名称不能为空!")); |
| | | return; |
| | | } |
| | | |
| | | if (RecipeManager::getInstance().updateDeviceRecipeName(pEq->getName(), _ttoi(strID), std::string(CT2A(strText)))) { |
| | | m_listPPID.SetItemText(nLine, 3, strText); |
| | | } |
| | | } |
| | | } |
| | | |
| | | void CPageRecipe::OnBnClickedButtonDelete() |
| | |
| | | } |
| | | } |
| | | |
| | | void CPageRecipe::OnLvnItemChangedListPPID(NMHDR* pNMHDR, LRESULT* pResult) |
| | | void CPageRecipe::OnClickListPPID(NMHDR* pNMHDR, LRESULT* pResult) |
| | | { |
| | | LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR); |
| | | LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR); |
| | | // TODO: 在此添加控件通知处理程序代码 |
| | | *pResult = 0; |
| | | |
| | | CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT); |
| | | int nEqSel = pComboBox->GetCurSel(); |
| | | int selectedCount = ListView_GetSelectedCount(m_listPPID.GetSafeHwnd()); |
| | | if (pComboBox == nullptr) { |
| | | return; |
| | | } |
| | | |
| | | GetDlgItem(IDC_BUTTON_NEW)->EnableWindow(nEqSel == 0 && selectedCount > 0); |
| | | GetDlgItem(IDC_BUTTON_MODIFY)->EnableWindow(nEqSel == 0 && selectedCount > 0); |
| | | GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(nEqSel == 0 && selectedCount > 0); |
| | | GetDlgItem(IDC_BUTTON_DELETE_ALL)->EnableWindow(nEqSel == 0 && selectedCount > 0); |
| | | int nItem = pNMItemActivate->iItem; |
| | | int nEqSel = pComboBox->GetCurSel(); |
| | | |
| | | GetDlgItem(IDC_BUTTON_NEW)->EnableWindow(nEqSel == 0); |
| | | GetDlgItem(IDC_BUTTON_MODIFY)->EnableWindow(nItem != -1); |
| | | GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(nEqSel == 0 && nItem != -1); |
| | | GetDlgItem(IDC_BUTTON_DELETE_ALL)->EnableWindow(nEqSel == 0 && nItem != -1); |
| | | } |
| | | |
| | | void CPageRecipe::OnDblclkListPPID(NMHDR* pNMHDR, LRESULT* pResult) |
| | | { |
| | | LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR); |
| | | // TODO: 在此添加控件通知处理程序代码 |
| | | *pResult = 0; |
| | | |
| | | int nItem = pNMItemActivate->iItem; |
| | | if (nItem < 0) { |
| | | return; |
| | | } |
| | | |
| | | CString strText = m_listPPID.GetItemText(nItem, 2); |
| | | CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT); |
| | | int nEqSel = pComboBox->GetCurSel(); |
| | | if (nEqSel == CB_ERR) { |
| | | return; |
| | | } |
| | | |
| | | SERVO::CEquipment* pEq = (SERVO::CEquipment*)pComboBox->GetItemDataPtr(nEqSel); |
| | | if (pEq == nullptr) { |
| | | return; |
| | | } |
| | | } |
| | | |
| | | void CPageRecipe::OnCbnSelchangeComboEquipment() |
| | | { |
| | | CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT); |
| | | int nEqSel = pComboBox->GetCurSel(); |
| | | int selectedCount = ListView_GetSelectedCount(m_listPPID.GetSafeHwnd()); |
| | | int nItem = ListView_GetSelectedCount(m_listPPID.GetSafeHwnd()); |
| | | |
| | | GetDlgItem(IDC_BUTTON_NEW)->EnableWindow(nEqSel == 0 && selectedCount > 0); |
| | | GetDlgItem(IDC_BUTTON_MODIFY)->EnableWindow(nEqSel == 0 && selectedCount > 0); |
| | | GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(nEqSel == 0 && selectedCount > 0); |
| | | GetDlgItem(IDC_BUTTON_DELETE_ALL)->EnableWindow(nEqSel == 0 && selectedCount > 0); |
| | | GetDlgItem(IDC_BUTTON_NEW)->EnableWindow(nEqSel == 0); |
| | | GetDlgItem(IDC_BUTTON_MODIFY)->EnableWindow(nEqSel == 0 && nItem != -1); |
| | | GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(nEqSel == 0 && nItem != -1); |
| | | GetDlgItem(IDC_BUTTON_DELETE_ALL)->EnableWindow(nEqSel == 0 && nItem != -1); |
| | | GetDlgItem(IDC_EDIT_KEYWORD)->EnableWindow(nEqSel == 0); |
| | | GetDlgItem(IDC_BUTTON_SEARCH)->EnableWindow(nEqSel == 0); |
| | | |
| | |
| | | ResetEvent(hEvent); |
| | | } |
| | | |
| | | |
| | | |
| | | pEq->saveRecipeList(0, strFilepath); |
| | | pMsgDlg->SetIcon(MSG_BOX_SUCCEED); |
| | | pMsgDlg->SetTitle(_T("操作完成")); |
| | |
| | | |
| | | FillRecipeListToListCtrl(pEq); |
| | | CloseHandle(hEvent); |
| | | |
| | | |
| | | |
| | | // 在此打印配方参数以便核对数据 |
| | |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | return 0; |
| | | } |
| | |
| | | afx_msg void OnBnClickedButtonDelete(); |
| | | afx_msg void OnBnClickedButtonDeleteAll(); |
| | | afx_msg void OnBnClickedButtonRefresh(); |
| | | afx_msg void OnLvnItemChangedListPPID(NMHDR* pNMHDR, LRESULT* pResult); |
| | | afx_msg void OnClickListPPID(NMHDR* pNMHDR, LRESULT* pResult); |
| | | afx_msg void OnDblclkListPPID(NMHDR* pNMHDR, LRESULT* pResult); |
| | | afx_msg void OnCbnSelchangeComboEquipment(); |
| | | DECLARE_MESSAGE_MAP() |
| | | |
| | | private: |
| | | CListCtrlEx m_listPPID; |
| | | }; |
| | | }; |
| | |
| | | #include "RecipeManager.h" |
| | | #include "ServoCommo.h" |
| | | |
| | | |
| | | |
| | | #define CHECKBOX_ALL_ID 0x1234 |
| | | |
| | | // CPortConfigurationDlg 对话框 |
| | |
| | | // 回填 Job 信息(只取第一个有效 Glass) |
| | | if (!bJobInfoSet && pGlass) { |
| | | SERVO::CJobDataS* pJS = pGlass->getJobDataS(); |
| | | if (pJS) { |
| | | if (pJS) { |
| | | int nRecipeID = pJobDataS->getMasterRecipe(); |
| | | std::string strRecipeName = RecipeManager::getInstance().getPPIDById(nRecipeID); |
| | | SetDlgItemText(IDC_EDIT_LOTID, CString(pJS->getLotId().c_str())); |
| | | SetDlgItemText(IDC_EDIT_PRODUCTID, CString(pJS->getProductId().c_str())); |
| | | SetDlgItemText(IDC_EDIT_OPERATIONID, CString(pJS->getOperationId().c_str())); |
| | | m_comboMaterialsType.SetCurSel(pJS->getMaterialsType() - 1); |
| | | |
| | | if (!strRecipeName.empty()) { |
| | | CString csRecipeName(strRecipeName.c_str()); |
| | | int nIndex = m_comboRecipe.FindStringExact(-1, csRecipeName); |
| | | if (nIndex != CB_ERR) { |
| | | m_comboRecipe.SetCurSel(nIndex); |
| | | } |
| | | else { |
| | | AfxMessageBox(_T("当前配方在系统中不存在,请重新选择!"), MB_ICONWARNING); |
| | | m_comboRecipe.SetCurSel(0); |
| | | } |
| | | } |
| | | |
| | | bJobInfoSet = true; |
| | | } |
| | | } |
| | |
| | | SetWindowText(_T("Port Configuration")); |
| | | } |
| | | |
| | | |
| | | // Porcess Start / Process Cancel 按钮状态 |
| | | GetDlgItem(IDC_BUTTON_PROCESS_START)->EnableWindow(FALSE); |
| | | GetDlgItem(IDC_BUTTON_PROCESS_CANCEL)->EnableWindow(FALSE); |
| | |
| | | m_comboRecipe.GetLBText(selRecipe, str); |
| | | config.strRecipe = CT2A(str.GetString()); |
| | | } |
| | | int nRecipeID = RecipeManager::getInstance().getIdByPPID(config.strRecipe); |
| | | RecipeInfo stRecipeInfo = RecipeManager::getInstance().getRecipeByPPID(config.strRecipe); |
| | | std::vector<DeviceRecipe> vecRecipeInfo = stRecipeInfo.vecDeviceList; |
| | | |
| | | // 获取 Material Type 索引(索引从 0 开始,对应枚举从 1 开始) |
| | | //int selMaterial = m_comboMaterialsType.GetCurSel(); |
| | |
| | | pJobDataS->setProductId(config.strProductID.c_str()); |
| | | pJobDataS->setOperationId(config.strOperationID.c_str()); |
| | | pJobDataS->setMaterialsType(nMaterialType); |
| | | |
| | | RecipeInfo stRecipeInfo = RecipeManager::getInstance().getRecipeByPPID(config.strRecipe); |
| | | std::vector<DeviceRecipe> vecRecipeInfo = stRecipeInfo.vecDeviceList; |
| | | pJobDataS->setMasterRecipe(nRecipeID); |
| | | |
| | | for (const auto& info : vecRecipeInfo) { |
| | | const std::string& name = info.strDeviceName; |
| | |
| | | |
| | | // 绑定界面需要显示的设备 |
| | | 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 对话框 |
| | |
| | | |
| | | CRecipeDeviceBindDlg::CRecipeDeviceBindDlg(CWnd* pParent /*=nullptr*/) |
| | | : CDialogEx(IDD_DIALOG_RECIPE_DEVICE_BIND, pParent) |
| | | , m_strPPID(_T("")) |
| | | , m_strDesc(_T("")) |
| | | , m_strPPID(_T("")) |
| | | , m_strDesc(_T("")) |
| | | { |
| | | |
| | | } |
| | |
| | | } |
| | | |
| | | 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; |
| | | CString strRecipeName; |
| | | strRecipeName.Format(_T("%d"), nRecipeID); |
| | | int idx = pCombo->AddString(strRecipeName); |
| | | pCombo->SetItemData(idx, nRecipeID); |
| | | if (nSelectedRecipeID == nRecipeID) { |
| | | pCombo->SetCurSel(idx); |
| | | bFound = true; |
| | | } |
| | | } |
| | | auto& mapRecipeIds = pRecipeList->getIds(); |
| | | bool bFound = false; |
| | | pCombo->ResetContent(); |
| | | for (const auto& pair : mapRecipeIds) { |
| | | int nRecipeID = pair.second; |
| | | |
| | | if (nSelectedRecipeID != -1 && !bFound) { |
| | | pCombo->SetCurSel(CB_ERR); |
| | | } |
| | | else if (pCombo->GetCount() > 0 && nSelectedRecipeID == -1) { |
| | | pCombo->SetCurSel(0); |
| | | } |
| | | std::string strRecipeName = RecipeManager::getInstance().getDeviceRecipeName(pEq->getName(), nRecipeID); |
| | | if (strRecipeName.empty()) { |
| | | strRecipeName = std::to_string(nRecipeID); |
| | | } |
| | | |
| | | return true; |
| | | 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; |
| | | } |
| | | } |
| | | |
| | | 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() |
| | | |
| | | |
| | |
| | | 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 |
| | |
| | | |
| | | 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(); |
| | | } |
| | |
| | | #include "stdafx.h" |
| | | #include "stdafx.h" |
| | | #include "RecipeManager.h" |
| | | #include <sstream> |
| | | #include <iomanip> |
| | |
| | | std::recursive_mutex RecipeManager::m_mutex; |
| | | |
| | | RecipeManager& RecipeManager::getInstance() { |
| | | static RecipeManager instance; |
| | | return instance; |
| | | static RecipeManager instance; |
| | | return instance; |
| | | } |
| | | |
| | | RecipeManager::RecipeManager() { |
| | | m_pDB = new BL::SQLiteDatabase(); |
| | | m_pDB = new BL::SQLiteDatabase(); |
| | | } |
| | | |
| | | RecipeManager::~RecipeManager() { |
| | | if (m_pDB) { |
| | | delete m_pDB; |
| | | m_pDB = nullptr; |
| | | } |
| | | if (m_pDB) { |
| | | delete m_pDB; |
| | | m_pDB = nullptr; |
| | | } |
| | | } |
| | | |
| | | bool RecipeManager::initRecipeTable() { |
| | | char szPath[MAX_PATH]; |
| | | GetModuleFileNameA(NULL, szPath, MAX_PATH); |
| | | std::string exePath(szPath); |
| | | std::string dbDir = exePath.substr(0, exePath.find_last_of("\\/")) + "\\DB"; |
| | | CreateDirectoryA(dbDir.c_str(), NULL); |
| | | char szPath[MAX_PATH]; |
| | | GetModuleFileNameA(NULL, szPath, MAX_PATH); |
| | | std::string exePath(szPath); |
| | | std::string dbDir = exePath.substr(0, exePath.find_last_of("\\/")) + "\\DB"; |
| | | CreateDirectoryA(dbDir.c_str(), NULL); |
| | | |
| | | std::string dbPath = dbDir + "\\RecipeManager.db"; |
| | | if (!m_pDB->connect(dbPath, true)) { |
| | | return false; |
| | | } |
| | | std::string dbPath = dbDir + "\\RecipeManager.db"; |
| | | if (!m_pDB->connect(dbPath, true)) { |
| | | return false; |
| | | } |
| | | |
| | | // 启用 SQLite 的外键约束支持 |
| | | if (!m_pDB->executeQuery("PRAGMA foreign_keys = ON;")) { |
| | | std::cerr << "Failed to enable foreign keys." << std::endl; |
| | | return false; |
| | | } |
| | | // 启用 SQLite 的外键约束支持 |
| | | if (!m_pDB->executeQuery("PRAGMA foreign_keys = ON;")) { |
| | | std::cerr << "Failed to enable foreign keys." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | const std::string createRecipeTable = R"( |
| | | CREATE TABLE IF NOT EXISTS recipes ( |
| | | ppid TEXT PRIMARY KEY NOT NULL, |
| | | description TEXT, |
| | | create_time TEXT DEFAULT (datetime('now', 'localtime')) |
| | | ); |
| | | )"; |
| | | const std::string createRecipeTable = R"( |
| | | CREATE TABLE IF NOT EXISTS recipes ( |
| | | id INTEGER PRIMARY KEY AUTOINCREMENT, |
| | | ppid TEXT NOT NULL UNIQUE, |
| | | description TEXT, |
| | | create_time TEXT DEFAULT (datetime('now', 'localtime')) |
| | | ); |
| | | )"; |
| | | |
| | | const std::string createDeviceTable = R"( |
| | | CREATE TABLE IF NOT EXISTS recipe_devices ( |
| | | id INTEGER PRIMARY KEY AUTOINCREMENT, |
| | | ppid TEXT NOT NULL, |
| | | device_id INTEGER NOT NULL, |
| | | device_name TEXT NOT NULL, |
| | | recipe_id INTEGER NOT NULL, |
| | | FOREIGN KEY(ppid) REFERENCES recipes(ppid) ON DELETE CASCADE ON UPDATE CASCADE, |
| | | UNIQUE (ppid, device_id), |
| | | UNIQUE (ppid, device_name) |
| | | ); |
| | | )"; |
| | | const std::string createDeviceTable = R"( |
| | | CREATE TABLE IF NOT EXISTS recipe_devices ( |
| | | id INTEGER PRIMARY KEY AUTOINCREMENT, |
| | | ppid TEXT NOT NULL, |
| | | device_id INTEGER NOT NULL, |
| | | device_name TEXT NOT NULL, |
| | | recipe_id INTEGER NOT NULL, |
| | | recipe_name TEXT NOT NULL, |
| | | FOREIGN KEY(ppid) REFERENCES recipes(ppid) ON DELETE CASCADE ON UPDATE CASCADE, |
| | | UNIQUE (ppid, device_id), |
| | | UNIQUE (ppid, device_name) |
| | | ); |
| | | )"; |
| | | |
| | | return m_pDB->executeQuery(createRecipeTable) && m_pDB->executeQuery(createDeviceTable); |
| | | return m_pDB->executeQuery(createRecipeTable) && m_pDB->executeQuery(createDeviceTable); |
| | | } |
| | | |
| | | void RecipeManager::termRecipeTable() { |
| | | if (!m_pDB) { |
| | | return; |
| | | } |
| | | if (!m_pDB) { |
| | | return; |
| | | } |
| | | |
| | | m_pDB->disconnect(); |
| | | m_pDB->disconnect(); |
| | | } |
| | | |
| | | bool RecipeManager::destroyRecipeTable() { |
| | | if (!m_pDB) { |
| | | if (!m_pDB) { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | return m_pDB->executeQuery("DROP TABLE IF EXISTS recipe_devices;") && m_pDB->executeQuery("DROP TABLE IF EXISTS recipes;"); |
| | | return m_pDB->executeQuery("DROP TABLE IF EXISTS recipe_devices;") && m_pDB->executeQuery("DROP TABLE IF EXISTS recipes;"); |
| | | } |
| | | |
| | | bool RecipeManager::ppidExists(const std::string& ppid) { |
| | | std::ostringstream oss; |
| | | oss << "SELECT COUNT(*) FROM recipes WHERE ppid = '" << ppid << "';"; |
| | | auto result = m_pDB->fetchResults(oss.str()); |
| | | return (!result.empty() && !result[0].empty() && result[0][0] != "0"); |
| | | std::ostringstream oss; |
| | | oss << "SELECT COUNT(*) FROM recipes WHERE ppid = '" << ppid << "';"; |
| | | auto result = m_pDB->fetchResults(oss.str()); |
| | | return (!result.empty() && !result[0].empty() && result[0][0] != "0"); |
| | | } |
| | | |
| | | bool RecipeManager::deviceExists(const std::string& ppid, int nDeviceID) { |
| | | std::ostringstream oss; |
| | | oss << "SELECT COUNT(*) FROM recipe_devices WHERE ppid = '" << ppid |
| | | << "' AND device_id = " << nDeviceID << ";"; |
| | | auto result = m_pDB->fetchResults(oss.str()); |
| | | return (!result.empty() && !result[0].empty() && result[0][0] != "0"); |
| | | std::ostringstream oss; |
| | | oss << "SELECT COUNT(*) FROM recipe_devices WHERE ppid = '" << ppid |
| | | << "' AND device_id = " << nDeviceID << ";"; |
| | | auto result = m_pDB->fetchResults(oss.str()); |
| | | return (!result.empty() && !result[0].empty() && result[0][0] != "0"); |
| | | } |
| | | |
| | | bool RecipeManager::addRecipe(const RecipeInfo& recipe) { |
| | | if (!m_pDB || recipe.strPPID.empty() || recipe.vecDeviceList.empty()) { |
| | | std::cerr << "[AddRecipe] Invalid input." << std::endl; |
| | | return false; |
| | | } |
| | | if (!m_pDB || recipe.strPPID.empty() || recipe.vecDeviceList.empty()) { |
| | | std::cerr << "[AddRecipe] Invalid input." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::string strTime = recipe.strCreateTime; |
| | | if (strTime.empty()) { |
| | | std::time_t now = std::time(nullptr); |
| | | std::tm tm_now = {}; |
| | | localtime_s(&tm_now, &now); |
| | | std::stringstream ss; |
| | | ss << std::put_time(&tm_now, "%Y-%m-%d %H:%M:%S"); |
| | | strTime = ss.str(); |
| | | } |
| | | std::string strTime = recipe.strCreateTime; |
| | | if (strTime.empty()) { |
| | | std::time_t now = std::time(nullptr); |
| | | std::tm tm_now = {}; |
| | | localtime_s(&tm_now, &now); |
| | | std::stringstream ss; |
| | | ss << std::put_time(&tm_now, "%Y-%m-%d %H:%M:%S"); |
| | | strTime = ss.str(); |
| | | } |
| | | |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | |
| | | // 开始事务 |
| | | m_pDB->executeQuery("BEGIN TRANSACTION;"); |
| | | // 开始事务 |
| | | m_pDB->executeQuery("BEGIN TRANSACTION;"); |
| | | |
| | | std::ostringstream oss; |
| | | oss << "INSERT OR REPLACE INTO recipes (ppid, description, create_time) VALUES ('" |
| | | << recipe.strPPID << "', '" |
| | | << recipe.strDescription << "', '" |
| | | << strTime << "');"; |
| | | std::ostringstream oss; |
| | | oss << "INSERT OR REPLACE INTO recipes (ppid, description, create_time) VALUES ('" |
| | | << recipe.strPPID << "', '" |
| | | << recipe.strDescription << "', '" |
| | | << strTime << "');"; |
| | | |
| | | if (!m_pDB->executeQuery(oss.str())) { |
| | | std::cerr << "[AddRecipe] Failed to insert recipe: " << recipe.strPPID << std::endl; |
| | | m_pDB->executeQuery("ROLLBACK;"); |
| | | return false; |
| | | } |
| | | if (!m_pDB->executeQuery(oss.str())) { |
| | | std::cerr << "[AddRecipe] Failed to insert recipe: " << recipe.strPPID << std::endl; |
| | | m_pDB->executeQuery("ROLLBACK;"); |
| | | return false; |
| | | } |
| | | |
| | | for (const auto& device : recipe.vecDeviceList) { |
| | | std::ostringstream devSql; |
| | | devSql << "INSERT OR REPLACE INTO recipe_devices (ppid, device_id, device_name, recipe_id) VALUES ('" |
| | | << recipe.strPPID << "', " |
| | | << device.nDeviceID << ", '" |
| | | << device.strDeviceName << "', " |
| | | << device.nRecipeID << ");"; |
| | | for (const auto& device : recipe.vecDeviceList) { |
| | | std::ostringstream devSql; |
| | | devSql << "INSERT OR REPLACE INTO recipe_devices (ppid, device_id, device_name, recipe_id, recipe_name) VALUES ('" |
| | | << recipe.strPPID << "', " |
| | | << device.nDeviceID << ", '" |
| | | << device.strDeviceName << "', " |
| | | << device.nRecipeID << ", '" |
| | | << device.strRecipeName << "');"; |
| | | |
| | | if (!m_pDB->executeQuery(devSql.str())) { |
| | | std::cerr << "[AddRecipe] Failed to insert device mapping: " << device.nDeviceID << std::endl; |
| | | m_pDB->executeQuery("ROLLBACK;"); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | // 提交事务 |
| | | m_pDB->executeQuery("COMMIT;"); |
| | | return true; |
| | | if (!m_pDB->executeQuery(devSql.str())) { |
| | | std::cerr << "[AddRecipe] Failed to insert device mapping: " << device.nDeviceID << std::endl; |
| | | m_pDB->executeQuery("ROLLBACK;"); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | // 提交事务 |
| | | m_pDB->executeQuery("COMMIT;"); |
| | | return true; |
| | | } |
| | | |
| | | bool RecipeManager::addRecipeDevice(const std::string& ppid, const DeviceRecipe& device) { |
| | | if (!m_pDB || ppid.empty() || device.nDeviceID <= 0 || device.nRecipeID <= 0) { |
| | | std::cerr << "[addRecipeDevice] Invalid input." << std::endl; |
| | | return false; |
| | | } |
| | | if (!m_pDB || ppid.empty() || device.nDeviceID <= 0 || device.nRecipeID <= 0) { |
| | | std::cerr << "[addRecipeDevice] Invalid input." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | // 检查 ppid 是否存在 |
| | | // 检查 ppid 是否存在 |
| | | if (!ppidExists(ppid)) { |
| | | std::cerr << "[addRecipeDevice] PPID does not exist: " << ppid << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | // 插入设备记录 |
| | | std::ostringstream oss; |
| | | oss << "INSERT OR REPLACE INTO recipe_devices (ppid, device_id, device_name, recipe_id) VALUES ('" |
| | | << ppid << "', " |
| | | << device.nDeviceID << ", '" |
| | | << device.strDeviceName << "', " |
| | | << device.nRecipeID << ");"; |
| | | // 插入设备记录 |
| | | std::ostringstream oss; |
| | | oss << "INSERT OR REPLACE INTO recipe_devices (ppid, device_id, device_name, recipe_id, recipe_name) VALUES ('" |
| | | << ppid << "', " |
| | | << device.nDeviceID << ", '" |
| | | << device.strDeviceName << "', " |
| | | << device.nRecipeID << ", '" |
| | | << device.strRecipeName << "');"; |
| | | |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | return m_pDB->executeQuery(oss.str()); |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | return m_pDB->executeQuery(oss.str()); |
| | | } |
| | | |
| | | bool RecipeManager::deleteRecipeDeviceByID(const std::string& ppid, int nDeviceID) { |
| | | if (!m_pDB || ppid.empty() || nDeviceID <= 0) { |
| | | std::cerr << "[deleteRecipeDeviceByID] Invalid input." << std::endl; |
| | | return false; |
| | | } |
| | | if (!m_pDB || ppid.empty() || nDeviceID <= 0) { |
| | | std::cerr << "[deleteRecipeDeviceByID] Invalid input." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::ostringstream oss; |
| | | oss << "DELETE FROM recipe_devices WHERE ppid = '" << ppid << "' AND device_id = " << nDeviceID << ";"; |
| | | std::ostringstream oss; |
| | | oss << "DELETE FROM recipe_devices WHERE ppid = '" << ppid << "' AND device_id = " << nDeviceID << ";"; |
| | | |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | return m_pDB->executeQuery(oss.str()); |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | return m_pDB->executeQuery(oss.str()); |
| | | } |
| | | |
| | | bool RecipeManager::deleteRecipeDeviceByName(const std::string& ppid, const std::string& strDeviceName) { |
| | | if (!m_pDB || ppid.empty() || strDeviceName.empty()) { |
| | | std::cerr << "[deleteRecipeDeviceByName] Invalid input." << std::endl; |
| | | return false; |
| | | } |
| | | if (!m_pDB || ppid.empty() || strDeviceName.empty()) { |
| | | std::cerr << "[deleteRecipeDeviceByName] Invalid input." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::ostringstream oss; |
| | | oss << "DELETE FROM recipe_devices WHERE ppid = '" << ppid << "' AND device_name = '" << strDeviceName << "';"; |
| | | std::ostringstream oss; |
| | | oss << "DELETE FROM recipe_devices WHERE ppid = '" << ppid << "' AND device_name = '" << strDeviceName << "';"; |
| | | |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | return m_pDB->executeQuery(oss.str()); |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | return m_pDB->executeQuery(oss.str()); |
| | | } |
| | | |
| | | std::vector<RecipeInfo> RecipeManager::getAllRecipes() { |
| | | if (!m_pDB) { |
| | | return {}; |
| | | } |
| | | if (!m_pDB) { |
| | | return {}; |
| | | } |
| | | |
| | | std::vector<RecipeInfo> recipes; |
| | | auto rows = m_pDB->fetchResults("SELECT ppid, description, create_time FROM recipes;"); |
| | | std::vector<RecipeInfo> recipes; |
| | | auto rows = m_pDB->fetchResults("SELECT ppid, description, create_time FROM recipes;"); |
| | | |
| | | for (const auto& row : rows) { |
| | | RecipeInfo info; |
| | | info.strPPID = row[0]; |
| | | info.strDescription = row[1]; |
| | | info.strCreateTime = row[2]; |
| | | for (const auto& row : rows) { |
| | | RecipeInfo info; |
| | | info.strPPID = row[0]; |
| | | info.strDescription = row[1]; |
| | | info.strCreateTime = row[2]; |
| | | |
| | | std::ostringstream devQuery; |
| | | devQuery << "SELECT device_id, device_name, recipe_id FROM recipe_devices WHERE ppid = '" << info.strPPID << "';"; |
| | | auto devs = m_pDB->fetchResults(devQuery.str()); |
| | | std::ostringstream devQuery; |
| | | devQuery << "SELECT device_id, device_name, recipe_id, recipe_name FROM recipe_devices WHERE ppid = '" << info.strPPID << "'ORDER BY id ASC;"; |
| | | auto devs = m_pDB->fetchResults(devQuery.str()); |
| | | |
| | | for (const auto& dev : devs) { |
| | | DeviceRecipe dr; |
| | | try { |
| | | dr.nDeviceID = std::stoi(dev[0]); |
| | | dr.strDeviceName = dev[1]; |
| | | dr.nRecipeID = std::stoi(dev[2]); |
| | | } |
| | | catch (...) { |
| | | std::cerr << "Invalid data in recipe_devices for PPID: " << info.strPPID << std::endl; |
| | | continue; |
| | | } |
| | | info.vecDeviceList.push_back(dr); |
| | | } |
| | | recipes.push_back(info); |
| | | } |
| | | for (const auto& dev : devs) { |
| | | DeviceRecipe dr; |
| | | try { |
| | | dr.nDeviceID = std::stoi(dev[0]); |
| | | dr.strDeviceName = dev[1]; |
| | | dr.nRecipeID = std::stoi(dev[2]); |
| | | dr.strRecipeName = dev[3]; |
| | | } |
| | | catch (...) { |
| | | std::cerr << "Invalid data in recipe_devices for PPID: " << info.strPPID << std::endl; |
| | | continue; |
| | | } |
| | | info.vecDeviceList.push_back(dr); |
| | | } |
| | | recipes.push_back(info); |
| | | } |
| | | |
| | | return recipes; |
| | | return recipes; |
| | | } |
| | | |
| | | std::vector<RecipeInfo> RecipeManager::getRecipesByKeyword(const std::string& keyword) { |
| | | std::vector<RecipeInfo> recipes; |
| | | if (!m_pDB || keyword.empty()) { |
| | | return recipes; |
| | | } |
| | | std::vector<RecipeInfo> recipes; |
| | | if (!m_pDB || keyword.empty()) { |
| | | return recipes; |
| | | } |
| | | |
| | | std::ostringstream query; |
| | | query << "SELECT ppid, description, create_time FROM recipes " |
| | | << "WHERE ppid LIKE '%" << keyword << "%' OR description LIKE '%" << keyword << "%';"; |
| | | std::ostringstream query; |
| | | query << "SELECT ppid, description, create_time FROM recipes " |
| | | << "WHERE ppid LIKE '%" << keyword << "%' OR description LIKE '%" << keyword << "%';"; |
| | | |
| | | auto rows = m_pDB->fetchResults(query.str()); |
| | | for (const auto& row : rows) { |
| | | if (row.size() >= 3) { |
| | | RecipeInfo info; |
| | | info.strPPID = row[0]; |
| | | info.strDescription = row[1]; |
| | | info.strCreateTime = row[2]; |
| | | recipes.push_back(info); |
| | | } |
| | | } |
| | | return recipes; |
| | | auto rows = m_pDB->fetchResults(query.str()); |
| | | for (const auto& row : rows) { |
| | | if (row.size() >= 3) { |
| | | RecipeInfo info; |
| | | info.strPPID = row[0]; |
| | | info.strDescription = row[1]; |
| | | info.strCreateTime = row[2]; |
| | | recipes.push_back(info); |
| | | } |
| | | } |
| | | return recipes; |
| | | } |
| | | |
| | | std::vector<std::string> RecipeManager::getAllPPID() const { |
| | | std::vector<std::string> vecPPID; |
| | | std::vector<std::string> vecPPID; |
| | | |
| | | if (!m_pDB) { |
| | | return vecPPID; |
| | | } |
| | | if (!m_pDB) { |
| | | return vecPPID; |
| | | } |
| | | |
| | | const std::string query = "SELECT ppid FROM recipes ORDER BY ppid;"; |
| | | auto result = m_pDB->fetchResults(query); |
| | | const std::string query = "SELECT ppid FROM recipes ORDER BY ppid;"; |
| | | auto result = m_pDB->fetchResults(query); |
| | | |
| | | for (const auto& row : result) { |
| | | if (!row.empty()) { |
| | | vecPPID.push_back(row[0]); |
| | | } |
| | | } |
| | | for (const auto& row : result) { |
| | | if (!row.empty()) { |
| | | vecPPID.push_back(row[0]); |
| | | } |
| | | } |
| | | |
| | | return vecPPID; |
| | | return vecPPID; |
| | | } |
| | | |
| | | std::string RecipeManager::getPPIDById(int nId) { |
| | | if (!m_pDB) { |
| | | return {}; |
| | | } |
| | | |
| | | std::ostringstream query; |
| | | query << "SELECT ppid FROM recipes WHERE id = " << nId << ";"; |
| | | |
| | | auto rows = m_pDB->fetchResults(query.str()); |
| | | if (rows.empty() || rows[0].empty()) { |
| | | return {}; |
| | | } |
| | | |
| | | return rows[0][0]; |
| | | } |
| | | |
| | | int RecipeManager::getIdByPPID(const std::string& ppid) { |
| | | if (!m_pDB) { |
| | | return -1; |
| | | } |
| | | |
| | | std::ostringstream query; |
| | | query << "SELECT id FROM recipes WHERE ppid = '" << ppid << "';"; |
| | | |
| | | auto rows = m_pDB->fetchResults(query.str()); |
| | | if (rows.empty() || rows[0].empty()) { |
| | | return -1; |
| | | } |
| | | |
| | | try { |
| | | return std::stoi(rows[0][0]); |
| | | } |
| | | catch (...) { |
| | | std::cerr << "Invalid id value for PPID: " << ppid << std::endl; |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | RecipeInfo RecipeManager::getRecipeByPPID(const std::string& ppid) { |
| | | RecipeInfo info; |
| | | auto rows = m_pDB->fetchResults("SELECT ppid, description, create_time FROM recipes WHERE ppid = '" + ppid + "';"); |
| | | if (rows.empty()) { |
| | | return info; |
| | | } |
| | | RecipeInfo info; |
| | | auto rows = m_pDB->fetchResults("SELECT ppid, description, create_time FROM recipes WHERE ppid = '" + ppid + "';"); |
| | | if (rows.empty()) { |
| | | return info; |
| | | } |
| | | |
| | | info.strPPID = rows[0][0]; |
| | | info.strDescription = rows[0][1]; |
| | | info.strCreateTime = rows[0][2]; |
| | | info.strPPID = rows[0][0]; |
| | | info.strDescription = rows[0][1]; |
| | | info.strCreateTime = rows[0][2]; |
| | | |
| | | auto devs = m_pDB->fetchResults("SELECT device_id, device_name, recipe_id FROM recipe_devices WHERE ppid = '" + ppid + "';"); |
| | | for (const auto& dev : devs) { |
| | | DeviceRecipe dr; |
| | | try { |
| | | dr.nDeviceID = std::stoi(dev[0]); |
| | | dr.strDeviceName = dev[1]; |
| | | dr.nRecipeID = std::stoi(dev[2]); |
| | | } |
| | | catch (...) { |
| | | std::cerr << "Invalid data in recipe_devices for PPID: " << ppid << std::endl; |
| | | continue; |
| | | } |
| | | info.vecDeviceList.push_back(dr); |
| | | } |
| | | return info; |
| | | auto devs = m_pDB->fetchResults("SELECT device_id, device_name, recipe_id, recipe_name FROM recipe_devices WHERE ppid = '" + ppid + "';"); |
| | | for (const auto& dev : devs) { |
| | | DeviceRecipe dr; |
| | | try { |
| | | dr.nDeviceID = std::stoi(dev[0]); |
| | | dr.strDeviceName = dev[1]; |
| | | dr.nRecipeID = std::stoi(dev[2]); |
| | | dr.strRecipeName = dev[3]; |
| | | } |
| | | catch (...) { |
| | | std::cerr << "Invalid data in recipe_devices for PPID: " << ppid << std::endl; |
| | | continue; |
| | | } |
| | | info.vecDeviceList.push_back(dr); |
| | | } |
| | | return info; |
| | | } |
| | | |
| | | int RecipeManager::getDeviceRecipeIDByID(const std::string& ppid, int nDeviceID) { |
| | | if (!m_pDB || ppid.empty() || nDeviceID <= 0) { |
| | | return -1; |
| | | } |
| | | if (!m_pDB || ppid.empty() || nDeviceID <= 0) { |
| | | return -1; |
| | | } |
| | | |
| | | std::ostringstream query; |
| | | query << "SELECT recipe_id FROM recipe_devices WHERE ppid = '" << ppid << "' AND device_id = " << nDeviceID << ";"; |
| | | std::ostringstream query; |
| | | query << "SELECT recipe_id FROM recipe_devices WHERE ppid = '" << ppid << "' AND device_id = " << nDeviceID << ";"; |
| | | |
| | | auto result = m_pDB->fetchResults(query.str()); |
| | | if (!result.empty() && !result[0].empty()) { |
| | | try { |
| | | return std::stoi(result[0][0]); |
| | | } |
| | | catch (...) { |
| | | return -1; |
| | | } |
| | | } |
| | | return -1; |
| | | auto result = m_pDB->fetchResults(query.str()); |
| | | if (!result.empty() && !result[0].empty()) { |
| | | try { |
| | | return std::stoi(result[0][0]); |
| | | } |
| | | catch (...) { |
| | | return -1; |
| | | } |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | int RecipeManager::getDeviceRecipeIDByName(const std::string& ppid, const std::string& strDeviceName) { |
| | | if (!m_pDB || ppid.empty() || strDeviceName.empty()) { |
| | | return -1; |
| | | } |
| | | if (!m_pDB || ppid.empty() || strDeviceName.empty()) { |
| | | return -1; |
| | | } |
| | | |
| | | std::ostringstream query; |
| | | query << "SELECT recipe_id FROM recipe_devices WHERE ppid = '" << ppid << "' AND device_name = '" << strDeviceName << "';"; |
| | | std::ostringstream query; |
| | | query << "SELECT recipe_id FROM recipe_devices WHERE ppid = '" << ppid << "' AND device_name = '" << strDeviceName << "';"; |
| | | |
| | | auto result = m_pDB->fetchResults(query.str()); |
| | | if (!result.empty() && !result[0].empty()) { |
| | | try { |
| | | return std::stoi(result[0][0]); |
| | | } |
| | | catch (...) { |
| | | return -1; |
| | | } |
| | | } |
| | | return -1; |
| | | auto result = m_pDB->fetchResults(query.str()); |
| | | if (!result.empty() && !result[0].empty()) { |
| | | try { |
| | | return std::stoi(result[0][0]); |
| | | } |
| | | catch (...) { |
| | | return -1; |
| | | } |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | bool RecipeManager::deleteRecipeByPPID(const std::string& ppid) { |
| | | if (!m_pDB) { |
| | | return false; |
| | | } |
| | | if (!m_pDB) { |
| | | return false; |
| | | } |
| | | |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | return m_pDB->executeQuery("DELETE FROM recipes WHERE ppid = '" + ppid + "';"); |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | return m_pDB->executeQuery("DELETE FROM recipes WHERE ppid = '" + ppid + "';"); |
| | | } |
| | | |
| | | bool RecipeManager::updateRecipe(const RecipeInfo& recipe) { |
| | | if (!m_pDB) { |
| | | return false; |
| | | } |
| | | if (!m_pDB) { |
| | | return false; |
| | | } |
| | | |
| | | if (recipe.strPPID.empty()) { |
| | | std::cerr << "Recipe PPID cannot be empty." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | deleteRecipeByPPID(recipe.strPPID); |
| | | return addRecipe(recipe); |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | deleteRecipeByPPID(recipe.strPPID); |
| | | return addRecipe(recipe); |
| | | } |
| | | |
| | | bool RecipeManager::updatePPID(const std::string& oldPPID, const std::string& newPPID) { |
| | | if (!m_pDB || oldPPID.empty() || newPPID.empty()) { |
| | | std::cerr << "[updatePPID] Invalid input." << std::endl; |
| | | return false; |
| | | } |
| | | if (!m_pDB || oldPPID.empty() || newPPID.empty()) { |
| | | std::cerr << "[updatePPID] Invalid input." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | |
| | | // 检查是否已经存在相同的 newPPID |
| | | auto check = m_pDB->fetchResults("SELECT COUNT(*) FROM recipes WHERE ppid = '" + newPPID + "';"); |
| | | if (!check.empty() && !check[0].empty() && check[0][0] != "0") { |
| | | std::cerr << "[updatePPID] New PPID already exists: " << newPPID << std::endl; |
| | | return false; |
| | | } |
| | | // 检查是否已经存在相同的 newPPID |
| | | auto check = m_pDB->fetchResults("SELECT COUNT(*) FROM recipes WHERE ppid = '" + newPPID + "';"); |
| | | if (!check.empty() && !check[0].empty() && check[0][0] != "0") { |
| | | std::cerr << "[updatePPID] New PPID already exists: " << newPPID << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | m_pDB->executeQuery("BEGIN TRANSACTION;"); |
| | | m_pDB->executeQuery("BEGIN TRANSACTION;"); |
| | | |
| | | std::ostringstream sql; |
| | | sql << "UPDATE recipes SET ppid = '" << newPPID << "' WHERE ppid = '" << oldPPID << "';"; |
| | | if (!m_pDB->executeQuery(sql.str())) { |
| | | std::cerr << "[updatePPID] Failed to update recipes table." << std::endl; |
| | | m_pDB->executeQuery("ROLLBACK;"); |
| | | return false; |
| | | } |
| | | std::ostringstream sql; |
| | | sql << "UPDATE recipes SET ppid = '" << newPPID << "' WHERE ppid = '" << oldPPID << "';"; |
| | | if (!m_pDB->executeQuery(sql.str())) { |
| | | std::cerr << "[updatePPID] Failed to update recipes table." << std::endl; |
| | | m_pDB->executeQuery("ROLLBACK;"); |
| | | return false; |
| | | } |
| | | |
| | | m_pDB->executeQuery("COMMIT;"); |
| | | return true; |
| | | m_pDB->executeQuery("COMMIT;"); |
| | | return true; |
| | | } |
| | | |
| | | bool RecipeManager::updateDescription(const std::string& ppid, const std::string& newDescription) { |
| | | if (!m_pDB || ppid.empty()) { |
| | | std::cerr << "[updateRecipeDescription] Invalid input." << std::endl; |
| | | return false; |
| | | } |
| | | if (!m_pDB || ppid.empty()) { |
| | | std::cerr << "[updateRecipeDescription] Invalid input." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::ostringstream oss; |
| | | oss << "UPDATE recipes SET description = '" << newDescription << "' WHERE ppid = '" << ppid << "';"; |
| | | std::ostringstream oss; |
| | | oss << "UPDATE recipes SET description = '" << newDescription << "' WHERE ppid = '" << ppid << "';"; |
| | | |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | return m_pDB->executeQuery(oss.str()); |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | return m_pDB->executeQuery(oss.str()); |
| | | } |
| | | |
| | | bool RecipeManager::updateDeviceRecipeIDByID(const std::string& ppid, int nDeviceID, int nNewRecipeID) { |
| | |
| | | } |
| | | |
| | | std::ostringstream query; |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | query << "UPDATE recipe_devices SET recipe_id = " << nNewRecipeID |
| | | << " WHERE ppid = '" << ppid << "' AND device_id = " << nDeviceID << ";"; |
| | | return m_pDB->executeQuery(query.str()); |
| | |
| | | return false; |
| | | } |
| | | std::ostringstream query; |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
| | | query << "UPDATE recipe_devices SET recipe_id = " << nNewRecipeID |
| | | << " WHERE ppid = '" << ppid << "' AND device_name = '" << strDeviceName << "';"; |
| | | return m_pDB->executeQuery(query.str()); |
| | | } |
| | | |
| | | bool RecipeManager::addDeviceRecipe(const std::string& strDeviceName, int nID, const std::string& strName, const std::string& strPara) { |
| | | if (!m_pDB || strDeviceName.empty() || nID <= 0 || strName.empty() || strPara.empty()) { |
| | | return false; |
| | | } |
| | | |
| | | std::ostringstream sql; |
| | | sql << "CREATE TABLE IF NOT EXISTS " << strDeviceName << "_Recipes (" |
| | | << "recipe_id INTEGER PRIMARY KEY," |
| | | << "recipe_name TEXT NOT NULL," |
| | | << "recipe_para TEXT NOT NULL" |
| | | << ");"; |
| | | m_pDB->executeQuery(sql.str()); |
| | | |
| | | std::ostringstream ins; |
| | | ins << "INSERT OR REPLACE INTO " << strDeviceName |
| | | << "_Recipes (recipe_id, recipe_name, recipe_para) VALUES (" |
| | | << nID << ", '" << strName << "', '" << strPara << "');"; |
| | | |
| | | std::lock_guard<std::recursive_mutex> lk(m_mutex); |
| | | return m_pDB->executeQuery(ins.str()); |
| | | } |
| | | |
| | | bool RecipeManager::updateDeviceRecipeName(const std::string& strDeviceName, int nID, const std::string& strNewName) { |
| | | if (!m_pDB || strDeviceName.empty() || nID <= 0 || strNewName.empty()) { |
| | | return false; |
| | | } |
| | | |
| | | std::ostringstream sql; |
| | | sql << "UPDATE " << strDeviceName << "_Recipes SET recipe_name='" << strNewName |
| | | << "' WHERE recipe_id=" << nID << ";"; |
| | | |
| | | std::lock_guard<std::recursive_mutex> lk(m_mutex); |
| | | return m_pDB->executeQuery(sql.str()); |
| | | } |
| | | |
| | | bool RecipeManager::updateDeviceRecipePara(const std::string& strDeviceName, int nID, const std::string& strNewPara) { |
| | | if (!m_pDB || strDeviceName.empty() || nID <= 0) { |
| | | return false; |
| | | } |
| | | |
| | | std::ostringstream sql; |
| | | sql << "UPDATE " << strDeviceName << "_Recipes SET recipe_para='" << strNewPara |
| | | << "' WHERE recipe_id=" << nID << ";"; |
| | | |
| | | std::lock_guard<std::recursive_mutex> lk(m_mutex); |
| | | return m_pDB->executeQuery(sql.str()); |
| | | } |
| | | |
| | | std::string RecipeManager::getDeviceRecipeName(const std::string& strDeviceName, int nID) { |
| | | if (!m_pDB || strDeviceName.empty() || nID <= 0) { |
| | | return ""; |
| | | } |
| | | |
| | | std::ostringstream sql; |
| | | sql << "SELECT recipe_name FROM " << strDeviceName << "_Recipes " |
| | | << "WHERE recipe_id=" << nID << " LIMIT 1;"; |
| | | |
| | | auto rows = m_pDB->fetchResults(sql.str()); |
| | | if (!rows.empty() && !rows[0].empty()) { |
| | | return rows[0][0]; |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | std::string RecipeManager::getDeviceRecipePara(const std::string& strDeviceName, int nID) { |
| | | if (!m_pDB || strDeviceName.empty() || nID <= 0) { |
| | | return ""; |
| | | } |
| | | |
| | | std::ostringstream sql; |
| | | sql << "SELECT recipe_para FROM " << strDeviceName << "_Recipes " |
| | | << "WHERE recipe_id=" << nID << " LIMIT 1;"; |
| | | |
| | | auto rows = m_pDB->fetchResults(sql.str()); |
| | | if (!rows.empty() && !rows[0].empty()) { |
| | | return rows[0][0]; |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | bool RecipeManager::deleteDeviceRecipe(const std::string& strDeviceName, int nID) { |
| | | if (!m_pDB || strDeviceName.empty() || nID <= 0) { |
| | | return false; |
| | | } |
| | | |
| | | std::ostringstream sql; |
| | | sql << "DELETE FROM " << strDeviceName << "_Recipes WHERE recipe_id=" << nID << ";"; |
| | | |
| | | std::lock_guard<std::recursive_mutex> lk(m_mutex); |
| | | return m_pDB->executeQuery(sql.str()); |
| | | } |
| | | |
| | | std::vector<std::pair<int, std::string>> RecipeManager::getDeviceRecipes(const std::string& strDeviceName) { |
| | | std::vector<std::pair<int, std::string>> out; |
| | | if (!m_pDB || strDeviceName.empty()) { |
| | | return out; |
| | | } |
| | | |
| | | std::ostringstream sql; |
| | | sql << "SELECT recipe_id, recipe_name FROM " << strDeviceName << "_Recipes ORDER BY recipe_id;"; |
| | | |
| | | auto rows = m_pDB->fetchResults(sql.str()); |
| | | for (const auto& r : rows) { |
| | | if (r.size() < 2) continue; |
| | | try { |
| | | int id = std::stoi(r[0]); |
| | | out.emplace_back(id, r[1]); |
| | | } |
| | | catch (...) {} |
| | | } |
| | | return out; |
| | | } |
| | | |
| | | void RecipeManager::insertMockData() { |
| | | if (!m_pDB) { |
| | | return; |
| | | } |
| | | if (!m_pDB) { |
| | | return; |
| | | } |
| | | |
| | | RecipeInfo recipe; |
| | | recipe.strPPID = "P1001"; |
| | | recipe.strDescription = "Main Board Burn-in"; |
| | | RecipeInfo recipe; |
| | | recipe.strPPID = "P1001"; |
| | | recipe.strDescription = "Main Board Burn-in"; |
| | | |
| | | recipe.vecDeviceList = { |
| | | {1, 101, "Burner A"}, |
| | | {2, 102, "Burner B"} |
| | | }; |
| | | recipe.vecDeviceList = { |
| | | {9, 101, "VacuumBake", "VacuumBake"}, |
| | | {10, 102, "Bonder1", "Bonder1"}, |
| | | {11, 103, "Bonder2", "Bonder2"} |
| | | }; |
| | | |
| | | addRecipe(recipe); |
| | | addRecipe(recipe); |
| | | |
| | | addDeviceRecipe("Bonder1", 101, "标准工艺", ""); |
| | | addDeviceRecipe("Bonder1", 102, "改良工艺", ""); |
| | | addDeviceRecipe("Bonder1", 103, "高速模式", ""); |
| | | |
| | | addDeviceRecipe("Bonder2", 101, "标准工艺", ""); |
| | | addDeviceRecipe("Bonder2", 102, "改良工艺", ""); |
| | | addDeviceRecipe("Bonder2", 103, "高速模式", ""); |
| | | } |
| | | |
| | | bool RecipeManager::readRecipeFile(const std::string& filename) { |
| | | if (!m_pDB) { |
| | | return false; |
| | | } |
| | | if (!m_pDB) { |
| | | return false; |
| | | } |
| | | |
| | | std::ifstream file(filename); |
| | | if (!file.is_open()) { |
| | | return false; |
| | | } |
| | | std::ifstream file(filename); |
| | | if (!file.is_open()) { |
| | | return false; |
| | | } |
| | | |
| | | std::unordered_map<std::string, RecipeInfo> recipeMap; |
| | | std::string line; |
| | | std::getline(file, line); // skip header |
| | | std::unordered_map<std::string, RecipeInfo> recipeMap; |
| | | std::string line; |
| | | std::getline(file, line); // skip header |
| | | |
| | | while (std::getline(file, line)) { |
| | | std::stringstream ss(line); |
| | | std::string cell; |
| | | std::string ppid, description, createTime; |
| | | DeviceRecipe dev; |
| | | while (std::getline(file, line)) { |
| | | std::stringstream ss(line); |
| | | std::string cell; |
| | | std::string ppid, description, createTime; |
| | | DeviceRecipe dev; |
| | | |
| | | std::getline(ss, ppid, ','); |
| | | std::getline(ss, cell, ','); |
| | | try { dev.nDeviceID = std::stoi(cell); } |
| | | catch (...) { continue; } |
| | | std::getline(ss, dev.strDeviceName, ','); |
| | | std::getline(ss, cell, ','); |
| | | try { dev.nRecipeID = std::stoi(cell); } |
| | | catch (...) { continue; } |
| | | std::getline(ss, description, ','); |
| | | std::getline(ss, createTime, ','); |
| | | std::getline(ss, ppid, ','); |
| | | std::getline(ss, cell, ','); |
| | | try { dev.nDeviceID = std::stoi(cell); } |
| | | catch (...) { continue; } |
| | | std::getline(ss, dev.strDeviceName, ','); |
| | | std::getline(ss, cell, ','); |
| | | try { dev.nRecipeID = std::stoi(cell); } |
| | | catch (...) { continue; } |
| | | std::getline(ss, dev.strRecipeName, ','); |
| | | std::getline(ss, description, ','); |
| | | std::getline(ss, createTime, ','); |
| | | |
| | | auto& recipe = recipeMap[ppid]; |
| | | recipe.strPPID = ppid; |
| | | recipe.strDescription = description; |
| | | recipe.strCreateTime = createTime; |
| | | recipe.vecDeviceList.push_back(dev); |
| | | } |
| | | auto& recipe = recipeMap[ppid]; |
| | | recipe.strPPID = ppid; |
| | | recipe.strDescription = description; |
| | | recipe.strCreateTime = createTime; |
| | | recipe.vecDeviceList.push_back(dev); |
| | | } |
| | | |
| | | for (const auto& pair : recipeMap) { |
| | | if (!updateRecipe(pair.second)) { |
| | | std::cerr << "Failed to update recipe from file: " << pair.first << std::endl; |
| | | } |
| | | } |
| | | for (const auto& pair : recipeMap) { |
| | | if (!updateRecipe(pair.second)) { |
| | | std::cerr << "Failed to update recipe from file: " << pair.first << std::endl; |
| | | } |
| | | } |
| | | |
| | | return true; |
| | | return true; |
| | | } |
| | | |
| | | bool RecipeManager::saveRecipeFile(const std::string& filename) { |
| | | if (!m_pDB) { |
| | | return false; |
| | | } |
| | | if (!m_pDB) { |
| | | return false; |
| | | } |
| | | |
| | | std::ofstream file(filename); |
| | | if (!file.is_open()) { |
| | | return false; |
| | | } |
| | | std::ofstream file(filename); |
| | | if (!file.is_open()) { |
| | | return false; |
| | | } |
| | | |
| | | file << "PPID,DeviceID,DeviceName,RecipeID,Description,CreateTime\n"; |
| | | auto recipes = getAllRecipes(); |
| | | for (const auto& recipe : recipes) { |
| | | for (const auto& dev : recipe.vecDeviceList) { |
| | | file << recipe.strPPID << "," |
| | | << dev.nDeviceID << "," |
| | | << dev.strDeviceName << "," |
| | | << dev.nRecipeID << "," |
| | | << recipe.strDescription << "," |
| | | << recipe.strCreateTime << "\n"; |
| | | } |
| | | } |
| | | file << "PPID,DeviceID,DeviceName,RecipeID,RecipeName,Description,CreateTime\n"; |
| | | auto recipes = getAllRecipes(); |
| | | for (const auto& recipe : recipes) { |
| | | for (const auto& dev : recipe.vecDeviceList) { |
| | | file << recipe.strPPID << "," |
| | | << dev.nDeviceID << "," |
| | | << dev.strDeviceName << "," |
| | | << dev.nRecipeID << "," |
| | | << dev.strRecipeName << "," |
| | | << recipe.strDescription << "," |
| | | << recipe.strCreateTime << "\n"; |
| | | } |
| | | } |
| | | |
| | | return true; |
| | | return true; |
| | | } |
| | |
| | | #ifndef RECIPE_MANAGER_H |
| | | #ifndef RECIPE_MANAGER_H |
| | | #define RECIPE_MANAGER_H |
| | | |
| | | #include <string> |
| | |
| | | #include "CParam.h" |
| | | |
| | | |
| | | // 单个设备配方映射信息 |
| | | // 单个设备配方映射信息 |
| | | struct DeviceRecipe { |
| | | int nDeviceID; // 设备ID |
| | | int nRecipeID; // 子配方ID |
| | | std::string strRecipeName; // 子配方名称 |
| | | std::string strDeviceName; // 设备名称 |
| | | std::vector<uint8_t> paramsRawData; // 配方原始数据 |
| | | std::vector<CParam*> m_params; // 出站时记录参数 |
| | | int nDeviceID; // 设备ID |
| | | int nRecipeID; // 子配方ID |
| | | std::string strRecipeName; // 设备名称 |
| | | std::string strDeviceName; // 子配方名称 |
| | | std::vector<uint8_t> paramsRawData; // 原始参数数据 |
| | | std::vector<CParam*> m_params; // 参数对象列表 |
| | | }; |
| | | |
| | | // 配方信息 |
| | | // 配方信息 |
| | | struct RecipeInfo { |
| | | std::string strPPID; // 配方ID |
| | | std::string strDescription; // 配方描述 |
| | | std::string strCreateTime; // 创建时间 |
| | | std::vector<DeviceRecipe> vecDeviceList; // 关联的设备信息列表 |
| | | std::string strPPID; // 配方ID |
| | | std::string strDescription; // 配方描述 |
| | | std::string strCreateTime; // 创建时间 |
| | | std::vector<DeviceRecipe> vecDeviceList; // 关联的设备信息列表 |
| | | }; |
| | | |
| | | using RecipeMap = std::unordered_map<std::string, RecipeInfo>; // 按 PPID 映射的配方表 |
| | | using RecipeMap = std::unordered_map<std::string, RecipeInfo>; // 按 PPID 映射的配方表 |
| | | |
| | | class RecipeManager { |
| | | public: |
| | | // 获取单例 |
| | | static RecipeManager& getInstance(); |
| | | // 获取单例 |
| | | static RecipeManager& getInstance(); |
| | | |
| | | // 初始化配方数据库 |
| | | bool initRecipeTable(); |
| | | // 初始化配方数据库 |
| | | bool initRecipeTable(); |
| | | |
| | | // 销毁表或关闭连接 |
| | | void termRecipeTable(); |
| | | bool destroyRecipeTable(); |
| | | // 销毁表或关闭连接 |
| | | void termRecipeTable(); |
| | | bool destroyRecipeTable(); |
| | | |
| | | // 检查 PPID 是否存在 |
| | | bool ppidExists(const std::string& ppid); |
| | | // 检查 PPID 是否存在 |
| | | bool ppidExists(const std::string& ppid); |
| | | |
| | | // 检查设备是否存在于指定 PPID 的配方中 |
| | | // 检查设备是否存在于指定 PPID 的配方中 |
| | | bool deviceExists(const std::string& ppid, int nDeviceID); |
| | | |
| | | // 添加一个配方及其设备映射 |
| | | bool addRecipe(const RecipeInfo& recipe); |
| | | // 添加一个配方及其设备映射 |
| | | bool addRecipe(const RecipeInfo& recipe); |
| | | |
| | | // 添加设备到指定配方 |
| | | bool addRecipeDevice(const std::string& ppid, const DeviceRecipe& device); |
| | | // 添加设备到指定配方 |
| | | bool addRecipeDevice(const std::string& ppid, const DeviceRecipe& device); |
| | | |
| | | // 删除指定 PPID 的设备配方 |
| | | bool deleteRecipeDeviceByID(const std::string& ppid, int nDeviceID); |
| | | // 删除指定 PPID 的设备配方 |
| | | bool deleteRecipeDeviceByID(const std::string& ppid, int nDeviceID); |
| | | |
| | | // 删除指定 PPID 的设备配方(通过设备名称) |
| | | bool deleteRecipeDeviceByName(const std::string& ppid, const std::string& strDeviceName); |
| | | // 删除指定 PPID 的设备配方(通过设备名称) |
| | | bool deleteRecipeDeviceByName(const std::string& ppid, const std::string& strDeviceName); |
| | | |
| | | // 查询所有配方 |
| | | std::vector<RecipeInfo> getAllRecipes(); |
| | | // 查询所有配方 |
| | | std::vector<RecipeInfo> getAllRecipes(); |
| | | |
| | | // 根据 PPID 或描述查询配方 |
| | | std::vector<RecipeInfo> getRecipesByKeyword(const std::string& keyword); |
| | | // 根据 PPID 或描述查询配方 |
| | | std::vector<RecipeInfo> getRecipesByKeyword(const std::string& keyword); |
| | | |
| | | // 获取所有 PPID |
| | | std::vector<std::string> getAllPPID() const; |
| | | // 获取所有 PPID |
| | | std::vector<std::string> getAllPPID() const; |
| | | |
| | | // 按 PPID 查询配方 |
| | | RecipeInfo getRecipeByPPID(const std::string& ppid); |
| | | // 按 ID 查询 PPID |
| | | std::string getPPIDById(int nId); |
| | | |
| | | // 根据 PPID 和设备ID 获取设备配方ID |
| | | int getDeviceRecipeIDByID(const std::string& ppid, int nDeviceID); |
| | | // 按 PPID 查询 ID |
| | | int getIdByPPID(const std::string& ppid); |
| | | |
| | | // 根据 PPID 和设备名称 获取设备配方ID |
| | | int getDeviceRecipeIDByName(const std::string& ppid, const std::string& strDeviceName); |
| | | // 按 PPID 查询配方 |
| | | RecipeInfo getRecipeByPPID(const std::string& ppid); |
| | | |
| | | // 删除指定 PPID 的配方 |
| | | bool deleteRecipeByPPID(const std::string& ppid); |
| | | // 根据 PPID 和设备ID 获取设备配方ID |
| | | int getDeviceRecipeIDByID(const std::string& ppid, int nDeviceID); |
| | | |
| | | // 更新指定 PPID 的配方 |
| | | bool updateRecipe(const RecipeInfo& recipe); |
| | | // 根据 PPID 和设备名称 获取设备配方ID |
| | | int getDeviceRecipeIDByName(const std::string& ppid, const std::string& strDeviceName); |
| | | |
| | | // 更新 PPID(通过旧 PPID 和新 PPID) |
| | | bool updatePPID(const std::string& oldPPID, const std::string& newPPID); |
| | | // 删除指定 PPID 的配方 |
| | | bool deleteRecipeByPPID(const std::string& ppid); |
| | | |
| | | // 更新配方描述(通过 PPID) |
| | | bool updateDescription(const std::string& ppid, const std::string& newDescription); |
| | | // 更新指定 PPID 的配方 |
| | | bool updateRecipe(const RecipeInfo& recipe); |
| | | |
| | | // 更新设备配方ID(通过 PPID 和设备ID) |
| | | bool updateDeviceRecipeIDByID(const std::string& ppid, int nDeviceID, int nNewRecipeID); |
| | | // 更新 PPID(通过旧 PPID 和新 PPID) |
| | | bool updatePPID(const std::string& oldPPID, const std::string& newPPID); |
| | | |
| | | // 更新设备配方ID(通过 PPID 和设备名称) |
| | | bool updateDeviceRecipeIDByName(const std::string& ppid, const std::string& strDeviceName, int nNewRecipeID); |
| | | // 更新配方描述(通过 PPID) |
| | | bool updateDescription(const std::string& ppid, const std::string& newDescription); |
| | | |
| | | // 模拟插入数据(测试用) |
| | | void insertMockData(); |
| | | // 更新设备配方ID(通过 PPID 和设备ID) |
| | | bool updateDeviceRecipeIDByID(const std::string& ppid, int nDeviceID, int nNewRecipeID); |
| | | |
| | | // 读取配方文件(CSV 或 JSON) |
| | | bool readRecipeFile(const std::string& filename); |
| | | // 更新设备配方ID(通过 PPID 和设备名称) |
| | | bool updateDeviceRecipeIDByName(const std::string& ppid, const std::string& strDeviceName, int nNewRecipeID); |
| | | |
| | | // 保存配方到文件 |
| | | bool saveRecipeFile(const std::string& filename); |
| | | bool addDeviceRecipe(const std::string& strDeviceName, int nID, const std::string& strName, const std::string& strPara); |
| | | bool updateDeviceRecipeName(const std::string& strDeviceName, int nID, const std::string& strNewName); |
| | | bool updateDeviceRecipePara(const std::string& strDeviceName, int nID, const std::string& strNewPara); |
| | | std::string getDeviceRecipeName(const std::string& strDeviceName, int nID); |
| | | std::string getDeviceRecipePara(const std::string& strDeviceName, int nID); |
| | | bool deleteDeviceRecipe(const std::string& strDeviceName, int nID); |
| | | std::vector<std::pair<int, std::string>> getDeviceRecipes(const std::string& strDeviceName); |
| | | |
| | | // 模拟插入数据(测试用) |
| | | void insertMockData(); |
| | | |
| | | // 读取配方文件(CSV 或 JSON) |
| | | bool readRecipeFile(const std::string& filename); |
| | | |
| | | // 保存配方到文件 |
| | | bool saveRecipeFile(const std::string& filename); |
| | | |
| | | private: |
| | | RecipeManager(); |
| | | ~RecipeManager(); |
| | | RecipeManager(); |
| | | ~RecipeManager(); |
| | | |
| | | RecipeManager(const RecipeManager&) = delete; |
| | | RecipeManager& operator=(const RecipeManager&) = delete; |
| | | RecipeManager(const RecipeManager&) = delete; |
| | | RecipeManager& operator=(const RecipeManager&) = delete; |
| | | |
| | | private: |
| | | BL::Database* m_pDB; |
| | | static std::recursive_mutex m_mutex; |
| | | BL::Database* m_pDB; |
| | | static std::recursive_mutex m_mutex; |
| | | }; |
| | | |
| | | #endif // RECIPE_MANAGER_H |
| | |
| | | #include "CPageReport.h" |
| | | #include "CPageCollectionEvent.h" |
| | | #include "CControlJobDlg.h" |
| | | #include "InputDialog.h" |
| | | |
| | | |
| | | #ifdef _DEBUG |
| | |
| | | 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) { |
| | | if (theApp.m_model.getMaster().getState() == SERVO::MASTERSTATE::MSERROR) { |
| | | AfxMessageBox("当前有机台发生错误,不能启动,请确认解决问题后再尝试重新启动!"); |
| | |
| | | #include "stdafx.h" |
| | | #include "stdafx.h" |
| | | #include "UserManager.h" |
| | | #include <chrono> |
| | | #include <iostream> |
| | |
| | | const std::string INITIAL_ADMIN_USERNAME = "admin"; |
| | | const std::string INITIAL_ADMIN_PASSWORD = "admin"; |
| | | |
| | | // 获取单例实例 |
| | | // 获取单例实例 |
| | | UserManager& UserManager::getInstance() { |
| | | static UserManager instance; |
| | | return instance; |
| | | static UserManager instance; |
| | | return instance; |
| | | } |
| | | |
| | | UserManager::UserManager() |
| | | : m_isLoggedIn(false), m_isRememberMe(false), m_tmSessionTimeout(std::chrono::minutes(30)), |
| | | m_tmSessionExpiration(std::chrono::hours(72)), m_hMouseHook(nullptr), m_hKeyboardHook(nullptr), |
| | | m_pDB(std::make_unique<BL::SQLiteDatabase>()) { |
| | | initializeDatabase(); |
| | | : m_isLoggedIn(false), m_isRememberMe(false), m_tmSessionTimeout(std::chrono::minutes(30)), |
| | | m_tmSessionExpiration(std::chrono::hours(72)), m_hMouseHook(nullptr), m_hKeyboardHook(nullptr), |
| | | m_pDB(std::make_unique<BL::SQLiteDatabase>()) { |
| | | initializeDatabase(); |
| | | } |
| | | |
| | | UserManager::~UserManager() { |
| | | terminateIdleDetection(); |
| | | terminateIdleDetection(); |
| | | } |
| | | |
| | | // 提供数据库连接 |
| | | // 提供数据库连接 |
| | | std::unique_ptr<BL::Database>& UserManager::getDatabaseInstance() { |
| | | return m_pDB; |
| | | return m_pDB; |
| | | } |
| | | |
| | | // 初始化数据库,创建用户表并插入初始管理员用户 |
| | | // 初始化数据库,创建用户表并插入初始管理员用户 |
| | | bool UserManager::initializeDatabase() { |
| | | std::string dbFilePath = getDatabaseFilePath(); |
| | | if (!m_pDB->connect(dbFilePath, true)) { |
| | | throw std::runtime_error("Failed to connect to database."); |
| | | } |
| | | std::string dbFilePath = getDatabaseFilePath(); |
| | | if (!m_pDB->connect(dbFilePath, true)) { |
| | | throw std::runtime_error("Failed to connect to database."); |
| | | } |
| | | |
| | | std::string createTableQuery = R"( |
| | | CREATE TABLE IF NOT EXISTS users ( |
| | | username VARCHAR(50) PRIMARY KEY, |
| | | password VARCHAR(255) NOT NULL, |
| | | role INT NOT NULL, |
| | | session_timeout INT DEFAULT 30, |
| | | session_expiration INT DEFAULT 72, |
| | | last_login DATETIME DEFAULT (datetime('now', 'localtime')) |
| | | ) |
| | | )"; |
| | | m_pDB->executeQuery(createTableQuery); |
| | | std::string createTableQuery = R"( |
| | | CREATE TABLE IF NOT EXISTS users ( |
| | | username VARCHAR(50) PRIMARY KEY, |
| | | password VARCHAR(255) NOT NULL, |
| | | role INT NOT NULL, |
| | | session_timeout INT DEFAULT 30, |
| | | session_expiration INT DEFAULT 72, |
| | | last_login DATETIME DEFAULT (datetime('now', 'localtime')) |
| | | ) |
| | | )"; |
| | | m_pDB->executeQuery(createTableQuery); |
| | | |
| | | std::string checkAdminQuery = "SELECT COUNT(*) FROM users WHERE role = 0"; |
| | | auto result = m_pDB->fetchResults(checkAdminQuery); |
| | | std::string checkAdminQuery = "SELECT COUNT(*) FROM users WHERE role = 0"; |
| | | auto result = m_pDB->fetchResults(checkAdminQuery); |
| | | |
| | | if (result.empty() || result[0][0] == "0") { |
| | | std::string insertAdminQuery = "INSERT INTO users (username, password, role, session_timeout, session_expiration) VALUES ('" + |
| | | INITIAL_ADMIN_USERNAME + "', '" + simpleEncryptDecrypt(INITIAL_ADMIN_PASSWORD, "BandKey") + "', 0, 30, 72)"; |
| | | m_pDB->executeQuery(insertAdminQuery); |
| | | } |
| | | if (result.empty() || result[0][0] == "0") { |
| | | std::string insertAdminQuery = "INSERT INTO users (username, password, role, session_timeout, session_expiration) VALUES ('" + |
| | | INITIAL_ADMIN_USERNAME + "', '" + simpleEncryptDecrypt(INITIAL_ADMIN_PASSWORD, "BandKey") + "', 0, 30, 72)"; |
| | | m_pDB->executeQuery(insertAdminQuery); |
| | | } |
| | | |
| | | return true; |
| | | return true; |
| | | } |
| | | |
| | | // 对密码进行哈希处理 |
| | | // 对密码进行哈希处理 |
| | | std::string UserManager::hashPassword(const std::string& password) { |
| | | return std::to_string(std::hash<std::string>{}(password)); |
| | | return std::to_string(std::hash<std::string>{}(password)); |
| | | } |
| | | |
| | | // 简单的加密和解密函数 |
| | | // 简单的加密和解密函数 |
| | | std::string UserManager::simpleEncryptDecrypt(const std::string& data, const std::string& key) { |
| | | std::string result = data; |
| | | for (size_t i = 0; i < data.size(); ++i) { |
| | | result[i] ^= key[i % key.size()]; // 简单异或加密 |
| | | } |
| | | return result; |
| | | std::string result = data; |
| | | for (size_t i = 0; i < data.size(); ++i) { |
| | | result[i] ^= key[i % key.size()]; // 简单异或加密 |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | // 从会话文件加载会话信息 |
| | | // 从会话文件加载会话信息 |
| | | bool UserManager::loadSession() { |
| | | std::ifstream sessionFile(getSessionFilePath(), std::ios::binary); |
| | | if (!sessionFile.is_open()) { |
| | | return false; |
| | | } |
| | | std::ifstream sessionFile(getSessionFilePath(), std::ios::binary); |
| | | if (!sessionFile.is_open()) { |
| | | return false; |
| | | } |
| | | |
| | | // 从文件读取加密数据 |
| | | std::string encryptedData((std::istreambuf_iterator<char>(sessionFile)), std::istreambuf_iterator<char>()); |
| | | sessionFile.close(); |
| | | // 从文件读取加密数据 |
| | | std::string encryptedData((std::istreambuf_iterator<char>(sessionFile)), std::istreambuf_iterator<char>()); |
| | | sessionFile.close(); |
| | | |
| | | // 解密数据 |
| | | std::string decryptedData = simpleEncryptDecrypt(encryptedData, "my_secret_key"); |
| | | // 解密数据 |
| | | std::string decryptedData = simpleEncryptDecrypt(encryptedData, "my_secret_key"); |
| | | |
| | | // 解析解密的数据 |
| | | std::istringstream sessionData(decryptedData); |
| | | std::string username; |
| | | // 解析解密的数据 |
| | | std::istringstream sessionData(decryptedData); |
| | | std::string username; |
| | | std::string password; |
| | | std::time_t lastLoginTime; |
| | | int timeoutMinutes; |
| | | int expirationHours; |
| | | std::time_t lastLoginTime; |
| | | int timeoutMinutes; |
| | | int expirationHours; |
| | | |
| | | sessionData >> username >> password >> lastLoginTime >> timeoutMinutes >> expirationHours; |
| | | sessionData >> username >> password >> lastLoginTime >> timeoutMinutes >> expirationHours; |
| | | |
| | | // 验证时间戳有效性 |
| | | auto now = std::chrono::system_clock::now(); |
| | | auto lastLogin = std::chrono::system_clock::from_time_t(lastLoginTime); |
| | | auto sessionDuration = std::chrono::duration_cast<std::chrono::hours>(now - lastLogin); |
| | | // 验证时间戳有效性 |
| | | auto now = std::chrono::system_clock::now(); |
| | | auto lastLogin = std::chrono::system_clock::from_time_t(lastLoginTime); |
| | | auto sessionDuration = std::chrono::duration_cast<std::chrono::hours>(now - lastLogin); |
| | | |
| | | if (sessionDuration > std::chrono::hours(expirationHours)) { |
| | | clearSession(); |
| | | return false; |
| | | } |
| | | if (sessionDuration > std::chrono::hours(expirationHours)) { |
| | | clearSession(); |
| | | return false; |
| | | } |
| | | |
| | | // 恢复会话数据 |
| | | m_strCurrentUser = username; |
| | | // 恢复会话数据 |
| | | m_strCurrentUser = username; |
| | | m_strCurrentPass = password; |
| | | m_tpLastLogin = lastLogin; |
| | | m_tmSessionTimeout = std::chrono::minutes(timeoutMinutes); |
| | | m_tmSessionExpiration = std::chrono::hours(expirationHours); |
| | | m_isLoggedIn = true; |
| | | m_isRememberMe = true; |
| | | updateActivityTime(); |
| | | m_tpLastLogin = lastLogin; |
| | | m_tmSessionTimeout = std::chrono::minutes(timeoutMinutes); |
| | | m_tmSessionExpiration = std::chrono::hours(expirationHours); |
| | | m_isLoggedIn = true; |
| | | m_isRememberMe = true; |
| | | updateActivityTime(); |
| | | |
| | | return true; |
| | | return true; |
| | | } |
| | | |
| | | // 保存会话信息到文件 |
| | | // 保存会话信息到文件 |
| | | void UserManager::saveSession() { |
| | | if (!m_isRememberMe) { |
| | | clearSession(); |
| | | return; |
| | | } |
| | | if (!m_isRememberMe) { |
| | | clearSession(); |
| | | return; |
| | | } |
| | | |
| | | // 原始会话数据 |
| | | std::stringstream sessionData; |
| | | std::time_t lastLoginTime = std::chrono::system_clock::to_time_t(m_tpLastLogin); |
| | | sessionData << m_strCurrentUser << " " << m_strCurrentPass << " " << lastLoginTime << " " |
| | | << m_tmSessionTimeout.count() << " " << m_tmSessionExpiration.count(); |
| | | // 原始会话数据 |
| | | std::stringstream sessionData; |
| | | std::time_t lastLoginTime = std::chrono::system_clock::to_time_t(m_tpLastLogin); |
| | | sessionData << m_strCurrentUser << " " << m_strCurrentPass << " " << lastLoginTime << " " |
| | | << m_tmSessionTimeout.count() << " " << m_tmSessionExpiration.count(); |
| | | |
| | | // 加密数据 |
| | | std::string encryptedData = simpleEncryptDecrypt(sessionData.str(), "my_secret_key"); |
| | | // 加密数据 |
| | | std::string encryptedData = simpleEncryptDecrypt(sessionData.str(), "my_secret_key"); |
| | | |
| | | // 写入加密数据到文件 |
| | | std::ofstream sessionFile(getSessionFilePath(), std::ios::binary); |
| | | if (sessionFile.is_open()) { |
| | | sessionFile << encryptedData; |
| | | sessionFile.close(); |
| | | } |
| | | // 写入加密数据到文件 |
| | | std::ofstream sessionFile(getSessionFilePath(), std::ios::binary); |
| | | if (sessionFile.is_open()) { |
| | | sessionFile << encryptedData; |
| | | sessionFile.close(); |
| | | } |
| | | } |
| | | |
| | | // 清除会话文件 |
| | | // 清除会话文件 |
| | | void UserManager::clearSession() { |
| | | std::remove(getSessionFilePath().c_str()); |
| | | std::remove(getSessionFilePath().c_str()); |
| | | } |
| | | |
| | | // 获取程序路径下的config文件夹路径 |
| | | // 获取程序路径下的config文件夹路径 |
| | | std::string UserManager::getConfigFolderPath() { |
| | | char szPath[MAX_PATH]; |
| | | GetModuleFileName(NULL, szPath, MAX_PATH); |
| | | std::string exePath(szPath); |
| | | std::string dbDir = exePath.substr(0, exePath.find_last_of("\\/")) + "\\DB\\"; |
| | | char szPath[MAX_PATH]; |
| | | GetModuleFileName(NULL, szPath, MAX_PATH); |
| | | std::string exePath(szPath); |
| | | std::string dbDir = exePath.substr(0, exePath.find_last_of("\\/")) + "\\DB\\"; |
| | | |
| | | // 检查并创建config文件夹 |
| | | DWORD fileAttr = GetFileAttributes(dbDir.c_str()); |
| | | if (fileAttr == INVALID_FILE_ATTRIBUTES) { |
| | | CreateDirectory(dbDir.c_str(), NULL); |
| | | } |
| | | // 检查并创建config文件夹 |
| | | DWORD fileAttr = GetFileAttributes(dbDir.c_str()); |
| | | if (fileAttr == INVALID_FILE_ATTRIBUTES) { |
| | | CreateDirectory(dbDir.c_str(), NULL); |
| | | } |
| | | |
| | | return dbDir; |
| | | return dbDir; |
| | | } |
| | | |
| | | // 获取session.dat文件路径 |
| | | // 获取session.dat文件路径 |
| | | std::string UserManager::getSessionFilePath() { |
| | | return getConfigFolderPath() + SESSION_FILE; |
| | | return getConfigFolderPath() + SESSION_FILE; |
| | | } |
| | | |
| | | // 获取数据库文件路径 |
| | | // 获取数据库文件路径 |
| | | std::string UserManager::getDatabaseFilePath() { |
| | | return getConfigFolderPath() + DATABASE_FILE; |
| | | return getConfigFolderPath() + DATABASE_FILE; |
| | | } |
| | | |
| | | // 登录方法 |
| | | // 登录方法 |
| | | bool UserManager::login(const std::string& username, const std::string& password, bool rememberMeFlag) { |
| | | std::string query = "SELECT username, password, role, session_timeout, session_expiration FROM users WHERE username = '" + username + "'"; |
| | | auto result = m_pDB->fetchResults(query); |
| | | std::string query = "SELECT username, password, role, session_timeout, session_expiration FROM users WHERE username = '" + username + "'"; |
| | | auto result = m_pDB->fetchResults(query); |
| | | |
| | | if (result.empty() || result[0][1] != simpleEncryptDecrypt(password, "BandKey")) { |
| | | std::cerr << "Login failed: Invalid username or password." << std::endl; |
| | | return false; |
| | | } |
| | | if (result.empty() || result[0][1] != simpleEncryptDecrypt(password, "BandKey")) { |
| | | std::cerr << "Login failed: Invalid username or password." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | m_strCurrentUser = username; |
| | | m_strCurrentUser = username; |
| | | m_strCurrentPass = password; |
| | | m_enCurrentUserRole = static_cast<UserRole>(std::stoi(result[0][2])); |
| | | m_tmSessionTimeout = std::chrono::minutes(std::stoi(result[0][3])); |
| | | m_tmSessionExpiration = std::chrono::hours(std::stoi(result[0][4])); |
| | | m_isLoggedIn = true; |
| | | m_isRememberMe = rememberMeFlag; |
| | | updateActivityTime(); |
| | | m_tpLastLogin = std::chrono::system_clock::now(); |
| | | m_enCurrentUserRole = static_cast<UserRole>(std::stoi(result[0][2])); |
| | | m_tmSessionTimeout = std::chrono::minutes(std::stoi(result[0][3])); |
| | | m_tmSessionExpiration = std::chrono::hours(std::stoi(result[0][4])); |
| | | m_isLoggedIn = true; |
| | | m_isRememberMe = rememberMeFlag; |
| | | updateActivityTime(); |
| | | m_tpLastLogin = std::chrono::system_clock::now(); |
| | | |
| | | std::string updateLoginTime = "UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE username = '" + username + "'"; |
| | | m_pDB->executeQuery(updateLoginTime); |
| | | std::string updateLoginTime = "UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE username = '" + username + "'"; |
| | | m_pDB->executeQuery(updateLoginTime); |
| | | |
| | | saveSession(); |
| | | return true; |
| | | saveSession(); |
| | | return true; |
| | | } |
| | | |
| | | // 登出方法 |
| | | // 登出方法 |
| | | void UserManager::logout() { |
| | | if (m_isLoggedIn) { |
| | | std::cout << "User logged out: " << m_strCurrentUser << std::endl; |
| | | m_strCurrentUser.clear(); |
| | | if (m_isLoggedIn) { |
| | | std::cout << "User logged out: " << m_strCurrentUser << std::endl; |
| | | m_strCurrentUser.clear(); |
| | | m_strCurrentPass.clear(); |
| | | m_isLoggedIn = false; |
| | | m_isRememberMe = false; |
| | | clearSession(); |
| | | } |
| | | m_isLoggedIn = false; |
| | | m_isRememberMe = false; |
| | | clearSession(); |
| | | } |
| | | } |
| | | |
| | | // 返回当前用户的登录状态 |
| | | // 返回当前用户的登录状态 |
| | | bool UserManager::isLoggedIn() const { |
| | | return m_isLoggedIn; |
| | | return m_isLoggedIn; |
| | | } |
| | | |
| | | // 返回当前用户的记住登录状态 |
| | | // 返回当前用户的记住登录状态 |
| | | bool UserManager::isRememberMe() const { |
| | | return m_isRememberMe; |
| | | } |
| | | |
| | | // 创建新用户,仅超级管理员有权限 |
| | | // 创建新用户,仅超级管理员有权限 |
| | | bool UserManager::createUser(const std::string& username, const std::string& password, UserRole role, |
| | | std::chrono::minutes timeout, std::chrono::hours expiration) { |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can create new users." << std::endl; |
| | | return false; |
| | | } |
| | | std::chrono::minutes timeout, std::chrono::hours expiration) { |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can create new users." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::string query = "INSERT INTO users (username, password, role, session_timeout, session_expiration) VALUES ('" + |
| | | username + "', '" + simpleEncryptDecrypt(password, "BandKey") + "', " + std::to_string(static_cast<int>(role)) + ", " + |
| | | std::to_string(timeout.count()) + ", " + std::to_string(expiration.count()) + ")"; |
| | | return m_pDB->executeQuery(query); |
| | | std::string query = "INSERT INTO users (username, password, role, session_timeout, session_expiration) VALUES ('" + |
| | | username + "', '" + simpleEncryptDecrypt(password, "BandKey") + "', " + std::to_string(static_cast<int>(role)) + ", " + |
| | | std::to_string(timeout.count()) + ", " + std::to_string(expiration.count()) + ")"; |
| | | return m_pDB->executeQuery(query); |
| | | } |
| | | |
| | | // 删除用户,仅超级管理员有权限,且不能删除自己 |
| | | // 删除用户,仅超级管理员有权限,且不能删除自己 |
| | | bool UserManager::deleteUser(const std::string& username) { |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can delete users." << std::endl; |
| | | return false; |
| | | } |
| | | if (username == m_strCurrentUser) { |
| | | std::cerr << "SuperAdmin cannot delete their own account." << std::endl; |
| | | return false; |
| | | } |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can delete users." << std::endl; |
| | | return false; |
| | | } |
| | | if (username == m_strCurrentUser) { |
| | | std::cerr << "SuperAdmin cannot delete their own account." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::string query = "DELETE FROM users WHERE username = '" + username + "'"; |
| | | return m_pDB->executeQuery(query); |
| | | std::string query = "DELETE FROM users WHERE username = '" + username + "'"; |
| | | return m_pDB->executeQuery(query); |
| | | } |
| | | |
| | | // 获取所有用户信息,仅超级管理员有权限 |
| | | // 获取所有用户信息,仅超级管理员有权限 |
| | | std::vector<std::vector<std::string>> UserManager::getUsers() { |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can retrieve user data." << std::endl; |
| | | return {}; |
| | | } |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can retrieve user data." << std::endl; |
| | | return {}; |
| | | } |
| | | |
| | | // 查询整个用户表 |
| | | std::string query = "SELECT username, password, role, session_timeout, session_expiration, last_login FROM users"; |
| | | std::vector<std::vector<std::string>> results = m_pDB->fetchResults(query); |
| | | for (auto& row : results) { |
| | | row[1] = simpleEncryptDecrypt(row[1], "BandKey"); |
| | | } |
| | | // 查询整个用户表 |
| | | std::string query = "SELECT username, password, role, session_timeout, session_expiration, last_login FROM users"; |
| | | std::vector<std::vector<std::string>> results = m_pDB->fetchResults(query); |
| | | for (auto& row : results) { |
| | | row[1] = simpleEncryptDecrypt(row[1], "BandKey"); |
| | | } |
| | | |
| | | return results; |
| | | return results; |
| | | } |
| | | |
| | | // 设置整个用户表的数据,仅超级管理员有权限 |
| | | // 设置整个用户表的数据,仅超级管理员有权限 |
| | | bool UserManager::setUsers(const std::vector<std::vector<std::string>>& usersData) { |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can set user data." << std::endl; |
| | | return false; |
| | | } |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can set user data." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | // 清空用户表 |
| | | std::string deleteQuery = "DELETE FROM users"; |
| | | if (!m_pDB->executeQuery(deleteQuery)) { |
| | | std::cerr << "Failed to clear the users table." << std::endl; |
| | | return false; |
| | | } |
| | | // 清空用户表 |
| | | std::string deleteQuery = "DELETE FROM users"; |
| | | if (!m_pDB->executeQuery(deleteQuery)) { |
| | | std::cerr << "Failed to clear the users table." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | // 插入新的用户数据 |
| | | for (const auto& user : usersData) { |
| | | if (user.size() != 6) { |
| | | std::cerr << "Invalid data format for user. Each user must have 6 fields." << std::endl; |
| | | return false; |
| | | } |
| | | // 插入新的用户数据 |
| | | for (const auto& user : usersData) { |
| | | if (user.size() != 6) { |
| | | std::cerr << "Invalid data format for user. Each user must have 6 fields." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::string insertQuery = "INSERT INTO users (username, password, role, session_timeout, session_expiration, last_login) VALUES ('" + |
| | | user[0] + "', '" + simpleEncryptDecrypt(user[1], "BandKey") + "', " + user[2] + ", " + user[3] + ", " + user[4] + ", '" + user[5] + "')"; |
| | | std::string insertQuery = "INSERT INTO users (username, password, role, session_timeout, session_expiration, last_login) VALUES ('" + |
| | | user[0] + "', '" + simpleEncryptDecrypt(user[1], "BandKey") + "', " + user[2] + ", " + user[3] + ", " + user[4] + ", '" + user[5] + "')"; |
| | | |
| | | if (!m_pDB->executeQuery(insertQuery)) { |
| | | std::cerr << "Failed to insert user: " << user[0] << std::endl; |
| | | return false; |
| | | } |
| | | } |
| | | if (!m_pDB->executeQuery(insertQuery)) { |
| | | std::cerr << "Failed to insert user: " << user[0] << std::endl; |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | return true; |
| | | return true; |
| | | } |
| | | |
| | | // 修改用户名,仅超级管理员有权限 |
| | | // 修改用户名,仅超级管理员有权限 |
| | | bool UserManager::changeUsername(const std::string& username, const std::string& newUsername) { |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can change usernames." << std::endl; |
| | | return false; |
| | | } |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can change usernames." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::string query = "UPDATE users SET username = '" + newUsername + "' WHERE username = '" + username + "'"; |
| | | bool success = m_pDB->executeQuery(query); |
| | | std::string query = "UPDATE users SET username = '" + newUsername + "' WHERE username = '" + username + "'"; |
| | | bool success = m_pDB->executeQuery(query); |
| | | |
| | | // 如果是当前登录用户修改自己的用户名,更新成员变量并保存会话文件 |
| | | if (success && m_strCurrentUser == username) { |
| | | m_strCurrentUser = newUsername; |
| | | // 如果是当前登录用户修改自己的用户名,更新成员变量并保存会话文件 |
| | | if (success && m_strCurrentUser == username) { |
| | | m_strCurrentUser = newUsername; |
| | | |
| | | // 如果“记住密码”已启用,更新会话文件 |
| | | if (m_isRememberMe) { |
| | | saveSession(); |
| | | } |
| | | } |
| | | return success; |
| | | // 如果“记住密码”已启用,更新会话文件 |
| | | if (m_isRememberMe) { |
| | | saveSession(); |
| | | } |
| | | } |
| | | return success; |
| | | } |
| | | |
| | | // 修改用户密码(仅允许当前用户或超级管理员) |
| | | // 修改用户密码(仅允许当前用户或超级管理员) |
| | | bool UserManager::changePassword(const std::string& username, const std::string& newPassword) { |
| | | if (username != m_strCurrentUser && m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Permission denied: Only the user or SuperAdmin can change passwords." << std::endl; |
| | | return false; |
| | | } |
| | | if (username != m_strCurrentUser && m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Permission denied: Only the user or SuperAdmin can change passwords." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::string query = "UPDATE users SET password = '" + simpleEncryptDecrypt(newPassword, "BandKey") + |
| | | "' WHERE username = '" + username + "'"; |
| | | bool success = m_pDB->executeQuery(query); |
| | | std::string query = "UPDATE users SET password = '" + simpleEncryptDecrypt(newPassword, "BandKey") + |
| | | "' WHERE username = '" + username + "'"; |
| | | bool success = m_pDB->executeQuery(query); |
| | | |
| | | // 如果是当前用户修改自己的密码,退出登录并清除会话文件 |
| | | if (success && m_strCurrentUser == username) { |
| | | logout(); |
| | | std::cout << "Password changed successfully. Please log in again." << std::endl; |
| | | } |
| | | // 如果是当前用户修改自己的密码,退出登录并清除会话文件 |
| | | if (success && m_strCurrentUser == username) { |
| | | logout(); |
| | | std::cout << "Password changed successfully. Please log in again." << std::endl; |
| | | } |
| | | |
| | | return success; |
| | | return success; |
| | | } |
| | | |
| | | // 更改用户角色,仅超级管理员有权限 |
| | | // 更改用户角色,仅超级管理员有权限 |
| | | bool UserManager::changeUserRole(const std::string& username, UserRole newRole) { |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can change user roles." << std::endl; |
| | | return false; |
| | | } |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can change user roles." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | // 防止管理员更改自己的角色 |
| | | if (m_strCurrentUser == username) { |
| | | std::cerr << "SuperAdmin cannot change their own role." << std::endl; |
| | | return false; |
| | | } |
| | | // 防止管理员更改自己的角色 |
| | | if (m_strCurrentUser == username) { |
| | | std::cerr << "SuperAdmin cannot change their own role." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::string query = "UPDATE users SET role = " + std::to_string(static_cast<int>(newRole)) + |
| | | " WHERE username = '" + username + "'"; |
| | | return m_pDB->executeQuery(query); |
| | | std::string query = "UPDATE users SET role = " + std::to_string(static_cast<int>(newRole)) + |
| | | " WHERE username = '" + username + "'"; |
| | | return m_pDB->executeQuery(query); |
| | | } |
| | | |
| | | // 修改用户的 session_timeout,仅超级管理员有权限 |
| | | // 修改用户的 session_timeout,仅超级管理员有权限 |
| | | bool UserManager::changeUserSessionTimeout(const std::string& username, int newTimeoutMinutes) { |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can change session timeout." << std::endl; |
| | | return false; |
| | | } |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can change session timeout." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::string query = "UPDATE users SET session_timeout = " + std::to_string(newTimeoutMinutes) + |
| | | " WHERE username = '" + username + "'"; |
| | | bool success = m_pDB->executeQuery(query); |
| | | // 如果是当前登录用户修改自己的超时设置,更新成员变量 |
| | | if (success && m_strCurrentUser == username) { |
| | | m_tmSessionTimeout = std::chrono::minutes(newTimeoutMinutes); |
| | | std::string query = "UPDATE users SET session_timeout = " + std::to_string(newTimeoutMinutes) + |
| | | " WHERE username = '" + username + "'"; |
| | | bool success = m_pDB->executeQuery(query); |
| | | // 如果是当前登录用户修改自己的超时设置,更新成员变量 |
| | | if (success && m_strCurrentUser == username) { |
| | | m_tmSessionTimeout = std::chrono::minutes(newTimeoutMinutes); |
| | | |
| | | if (m_isRememberMe) { |
| | | saveSession(); |
| | | } |
| | | } |
| | | return success; |
| | | if (m_isRememberMe) { |
| | | saveSession(); |
| | | } |
| | | } |
| | | return success; |
| | | } |
| | | |
| | | // 修改用户的 session_expiration,仅超级管理员有权限 |
| | | // 修改用户的 session_expiration,仅超级管理员有权限 |
| | | bool UserManager::changeUserSessionExpiration(const std::string& username, int newExpirationHours) { |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can change session expiration." << std::endl; |
| | | return false; |
| | | } |
| | | if (m_enCurrentUserRole != UserRole::SuperAdmin) { |
| | | std::cerr << "Only SuperAdmin can change session expiration." << std::endl; |
| | | return false; |
| | | } |
| | | |
| | | std::string query = "UPDATE users SET session_expiration = " + std::to_string(newExpirationHours) + |
| | | " WHERE username = '" + username + "'"; |
| | | bool success = m_pDB->executeQuery(query); |
| | | // 如果是当前登录用户修改自己的过期设置,更新成员变量 |
| | | if (success && m_strCurrentUser == username) { |
| | | m_tmSessionExpiration = std::chrono::hours(newExpirationHours); |
| | | std::string query = "UPDATE users SET session_expiration = " + std::to_string(newExpirationHours) + |
| | | " WHERE username = '" + username + "'"; |
| | | bool success = m_pDB->executeQuery(query); |
| | | // 如果是当前登录用户修改自己的过期设置,更新成员变量 |
| | | if (success && m_strCurrentUser == username) { |
| | | m_tmSessionExpiration = std::chrono::hours(newExpirationHours); |
| | | |
| | | if (m_isRememberMe) { |
| | | saveSession(); |
| | | } |
| | | } |
| | | return success; |
| | | if (m_isRememberMe) { |
| | | saveSession(); |
| | | } |
| | | } |
| | | return success; |
| | | } |
| | | |
| | | // 获取所有用户名称 |
| | | // 获取所有用户名称 |
| | | std::vector<std::string> UserManager::getUsernames() { |
| | | std::vector<std::string> usernames; |
| | | std::string query = "SELECT username FROM users"; |
| | | auto results = m_pDB->fetchResults(query); |
| | | std::vector<std::string> usernames; |
| | | std::string query = "SELECT username FROM users"; |
| | | auto results = m_pDB->fetchResults(query); |
| | | |
| | | for (const auto& row : results) { |
| | | if (!row.empty()) { |
| | | usernames.push_back(row[0]); // 获取用户名列的值 |
| | | } |
| | | } |
| | | for (const auto& row : results) { |
| | | if (!row.empty()) { |
| | | usernames.push_back(row[0]); // 获取用户名列的值 |
| | | } |
| | | } |
| | | |
| | | return usernames; |
| | | return usernames; |
| | | } |
| | | |
| | | // 获取指定用户名的用户信息 |
| | | // 获取指定用户名的用户信息 |
| | | std::vector<std::string> UserManager::getUserInfo(const std::string& username) |
| | | { |
| | | // 构建查询语句 |
| | | std::ostringstream query; |
| | | query << "SELECT username, password, role, session_timeout, session_expiration, last_login " |
| | | << "FROM users WHERE username = '" << username << "'"; |
| | | // 构建查询语句 |
| | | std::ostringstream query; |
| | | query << "SELECT username, password, role, session_timeout, session_expiration, last_login " |
| | | << "FROM users WHERE username = '" << username << "'"; |
| | | |
| | | // 执行查询并获取结果 |
| | | auto results = m_pDB->fetchResults(query.str()); |
| | | if (results.empty()) { |
| | | return {}; |
| | | } |
| | | // 执行查询并获取结果 |
| | | auto results = m_pDB->fetchResults(query.str()); |
| | | if (results.empty()) { |
| | | return {}; |
| | | } |
| | | |
| | | // 返回查询到的第一行数据 |
| | | return results[0]; |
| | | // 返回查询到的第一行数据 |
| | | return results[0]; |
| | | } |
| | | |
| | | // 更新最后活动时间,用于无操作超时检测 |
| | | // 更新最后活动时间,用于无操作超时检测 |
| | | void UserManager::updateActivityTime() { |
| | | m_tpLastActivity = std::chrono::system_clock::now(); |
| | | std::cout << "Activity updated at: " << std::chrono::system_clock::to_time_t(m_tpLastActivity) << std::endl; |
| | | m_tpLastActivity = std::chrono::system_clock::now(); |
| | | std::cout << "Activity updated at: " << std::chrono::system_clock::to_time_t(m_tpLastActivity) << std::endl; |
| | | } |
| | | |
| | | // 设置无操作超时时间 |
| | | // 设置无操作超时时间 |
| | | void UserManager::setSessionTimeout(std::chrono::minutes timeout) { |
| | | m_tmSessionTimeout = timeout; |
| | | m_tmSessionTimeout = timeout; |
| | | } |
| | | |
| | | // 检查是否超过无操作超时时间 |
| | | // 检查是否超过无操作超时时间 |
| | | bool UserManager::isInactiveTimeout() const { |
| | | auto now = std::chrono::system_clock::now(); |
| | | auto elapsedSeconds = std::chrono::duration_cast<std::chrono::seconds>(now - m_tpLastActivity).count(); |
| | | return elapsedSeconds > m_tmSessionTimeout.count() * 60; |
| | | auto now = std::chrono::system_clock::now(); |
| | | auto elapsedSeconds = std::chrono::duration_cast<std::chrono::seconds>(now - m_tpLastActivity).count(); |
| | | return elapsedSeconds > m_tmSessionTimeout.count() * 60; |
| | | } |
| | | |
| | | // 初始化无操作检测,包括设置全局鼠标和键盘钩子 |
| | | // 初始化无操作检测,包括设置全局鼠标和键盘钩子 |
| | | void UserManager::initializeIdleDetection(HWND hwnd) { |
| | | updateActivityTime(); |
| | | m_hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, (HINSTANCE) nullptr, 0); |
| | | m_hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, (HINSTANCE) nullptr, 0); |
| | | ::SetTimer(hwnd, 1, 60000, nullptr); |
| | | updateActivityTime(); |
| | | m_hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, (HINSTANCE) nullptr, 0); |
| | | m_hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, (HINSTANCE) nullptr, 0); |
| | | ::SetTimer(hwnd, 1, 60000, nullptr); |
| | | } |
| | | |
| | | // 终止无操作检测,清除鼠标和键盘钩子 |
| | | // 终止无操作检测,清除鼠标和键盘钩子 |
| | | void UserManager::terminateIdleDetection() { |
| | | if (m_hMouseHook) { |
| | | UnhookWindowsHookEx(m_hMouseHook); |
| | | m_hMouseHook = nullptr; |
| | | } |
| | | if (m_hKeyboardHook) { |
| | | UnhookWindowsHookEx(m_hKeyboardHook); |
| | | m_hKeyboardHook = nullptr; |
| | | } |
| | | ::KillTimer(nullptr, 1); |
| | | if (m_hMouseHook) { |
| | | UnhookWindowsHookEx(m_hMouseHook); |
| | | m_hMouseHook = nullptr; |
| | | } |
| | | if (m_hKeyboardHook) { |
| | | UnhookWindowsHookEx(m_hKeyboardHook); |
| | | m_hKeyboardHook = nullptr; |
| | | } |
| | | ::KillTimer(nullptr, 1); |
| | | } |
| | | |
| | | // 获取当前登录用户名 |
| | | // 获取当前登录用户名 |
| | | std::string UserManager::getCurrentUser() const { |
| | | return m_strCurrentUser; |
| | | } |
| | | |
| | | // 修改当前登录用户名 |
| | | // 修改当前登录用户名 |
| | | void UserManager::setCurrentUser(const std::string& strName) { |
| | | m_strCurrentUser = strName; |
| | | m_strCurrentUser = strName; |
| | | } |
| | | |
| | | // 获取当前登录用户密码 |
| | | // 获取当前登录用户密码 |
| | | std::string UserManager::getCurrentPass() const { |
| | | return m_strCurrentPass; |
| | | } |
| | | |
| | | // 修改当前登录用户密码 |
| | | // 修改当前登录用户密码 |
| | | void UserManager::setCurrentPass(const std::string& strPass) { |
| | | m_strCurrentPass = strPass; |
| | | m_strCurrentPass = strPass; |
| | | } |
| | | |
| | | // 获取当前登录用户角色 |
| | | // 获取当前登录用户角色 |
| | | UserRole UserManager::getCurrentUserRole() const { |
| | | return m_enCurrentUserRole; |
| | | } |
| | | |
| | | // 修改当前登录用户角色 |
| | | // 修改当前登录用户角色 |
| | | void UserManager::setCurrentUserRole(UserRole emRole) { |
| | | m_enCurrentUserRole = emRole; |
| | | m_enCurrentUserRole = emRole; |
| | | } |
| | | |
| | | // 获取当前登录用户的无操作超时时间 |
| | | // 获取当前登录用户的无操作超时时间 |
| | | std::chrono::minutes UserManager::getSessionTimeout() const { |
| | | return m_tmSessionTimeout; |
| | | } |
| | | |
| | | // 获取当前登录用户的会话过期时间 |
| | | // 获取当前登录用户的会话过期时间 |
| | | std::chrono::hours UserManager::getSessionExpiration() const { |
| | | return m_tmSessionExpiration; |
| | | } |
| | | |
| | | // 全局鼠标钩子回调,记录活动时间 |
| | | // 全局鼠标钩子回调,记录活动时间 |
| | | LRESULT CALLBACK UserManager::LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) { |
| | | if (nCode == HC_ACTION) { |
| | | UserManager::getInstance().updateActivityTime(); |
| | | std::cout << "Mouse event detected. Activity time updated." << std::endl; |
| | | } |
| | | return CallNextHookEx(nullptr, nCode, wParam, lParam); |
| | | if (nCode == HC_ACTION) { |
| | | UserManager::getInstance().updateActivityTime(); |
| | | std::cout << "Mouse event detected. Activity time updated." << std::endl; |
| | | } |
| | | return CallNextHookEx(nullptr, nCode, wParam, lParam); |
| | | } |
| | | |
| | | // 全局键盘钩子回调,记录活动时间 |
| | | // 全局键盘钩子回调,记录活动时间 |
| | | LRESULT CALLBACK UserManager::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { |
| | | if (nCode == HC_ACTION) { |
| | | UserManager::getInstance().updateActivityTime(); |
| | | std::cout << "Keyboard event detected. Activity time updated." << std::endl; |
| | | } |
| | | return CallNextHookEx(nullptr, nCode, wParam, lParam); |
| | | if (nCode == HC_ACTION) { |
| | | UserManager::getInstance().updateActivityTime(); |
| | | std::cout << "Keyboard event detected. Activity time updated." << std::endl; |
| | | } |
| | | return CallNextHookEx(nullptr, nCode, wParam, lParam); |
| | | } |
| | |
| | | #ifndef USER_MANAGER_H |
| | | #ifndef USER_MANAGER_H |
| | | #define USER_MANAGER_H |
| | | |
| | | #include <string> |
| | |
| | | #include <windows.h> |
| | | #include "Database.h" |
| | | |
| | | // 用户角色定义 |
| | | // 用户角色定义 |
| | | enum class UserRole { |
| | | SuperAdmin = 0, // 超级管理员 |
| | | Engineer, // 工程师 |
| | | Operator // 操作员 |
| | | SuperAdmin = 0, // 超级管理员:系统最高权限,管理所有用户和权限 |
| | | ProcessEngineer, // 制程工程师:负责工艺制定与优化 |
| | | EquipmentEngineer,// 设备工程师:负责设备维护与技术支持 |
| | | Operator, // 操作员:执行日常生产操作 |
| | | Unknown // 未知角色:默认或未识别的角色 |
| | | }; |
| | | |
| | | // 用户管理类,采用单例模式 |
| | | // 用户管理类,采用单例模式 |
| | | class UserManager { |
| | | public: |
| | | static UserManager& getInstance(); |
| | | static UserManager& getInstance(); |
| | | |
| | | UserManager(const UserManager&) = delete; |
| | | UserManager& operator=(const UserManager&) = delete; |
| | | UserManager(const UserManager&) = delete; |
| | | UserManager& operator=(const UserManager&) = delete; |
| | | |
| | | // 提供数据库连接 |
| | | std::unique_ptr<BL::Database>& getDatabaseInstance(); |
| | | // 提供数据库连接 |
| | | std::unique_ptr<BL::Database>& getDatabaseInstance(); |
| | | |
| | | // 用户操作 |
| | | bool login(const std::string& username, const std::string& password, bool rememberMe = false); |
| | | void logout(); |
| | | bool isLoggedIn() const; |
| | | // 用户操作 |
| | | bool login(const std::string& username, const std::string& password, bool rememberMe = false); |
| | | void logout(); |
| | | bool isLoggedIn() const; |
| | | bool isRememberMe() const; |
| | | bool createUser(const std::string& username, const std::string& password, UserRole role, |
| | | std::chrono::minutes timeout = std::chrono::minutes(30), |
| | | std::chrono::hours expiration = std::chrono::hours(72)); |
| | | bool deleteUser(const std::string& username); |
| | | std::vector<std::vector<std::string>> getUsers(); |
| | | bool setUsers(const std::vector<std::vector<std::string>>& usersData); |
| | | bool changeUsername(const std::string& username, const std::string& newUsername); |
| | | bool changePassword(const std::string& username, const std::string& newPassword); |
| | | bool changeUserRole(const std::string& username, UserRole newRole); |
| | | bool changeUserSessionTimeout(const std::string& username, int newTimeoutMinutes); |
| | | bool changeUserSessionExpiration(const std::string& username, int newExpirationHours); |
| | | std::vector<std::string> getUsernames(); |
| | | std::vector<std::string> getUserInfo(const std::string& username); |
| | | bool createUser(const std::string& username, const std::string& password, UserRole role, |
| | | std::chrono::minutes timeout = std::chrono::minutes(30), |
| | | std::chrono::hours expiration = std::chrono::hours(72)); |
| | | bool deleteUser(const std::string& username); |
| | | std::vector<std::vector<std::string>> getUsers(); |
| | | bool setUsers(const std::vector<std::vector<std::string>>& usersData); |
| | | bool changeUsername(const std::string& username, const std::string& newUsername); |
| | | bool changePassword(const std::string& username, const std::string& newPassword); |
| | | bool changeUserRole(const std::string& username, UserRole newRole); |
| | | bool changeUserSessionTimeout(const std::string& username, int newTimeoutMinutes); |
| | | bool changeUserSessionExpiration(const std::string& username, int newExpirationHours); |
| | | std::vector<std::string> getUsernames(); |
| | | std::vector<std::string> getUserInfo(const std::string& username); |
| | | |
| | | // 会话文件操作 |
| | | bool loadSession(); // 从会话文件加载会话信息 |
| | | void saveSession(); // 保存会话信息到文件 |
| | | void clearSession(); // 清除会话文件 |
| | | // 会话文件操作 |
| | | bool loadSession(); // 从会话文件加载会话信息 |
| | | void saveSession(); // 保存会话信息到文件 |
| | | void clearSession(); // 清除会话文件 |
| | | |
| | | // 配置文件夹路径管理 |
| | | static std::string getConfigFolderPath(); |
| | | static std::string getSessionFilePath(); |
| | | static std::string getDatabaseFilePath(); |
| | | // 配置文件夹路径管理 |
| | | static std::string getConfigFolderPath(); |
| | | static std::string getSessionFilePath(); |
| | | static std::string getDatabaseFilePath(); |
| | | |
| | | // 更新最后活动时间(用于无操作超时检测) |
| | | void updateActivityTime(); |
| | | // 更新最后活动时间(用于无操作超时检测) |
| | | void updateActivityTime(); |
| | | |
| | | // 设置用户的无操作超时时间 |
| | | void setSessionTimeout(std::chrono::minutes timeout); |
| | | // 设置用户的无操作超时时间 |
| | | void setSessionTimeout(std::chrono::minutes timeout); |
| | | |
| | | // 检查是否无操作超时 |
| | | bool isInactiveTimeout() const; |
| | | // 检查是否无操作超时 |
| | | bool isInactiveTimeout() const; |
| | | |
| | | // 初始化无操作检测(设置全局钩子和定时器) |
| | | void initializeIdleDetection(HWND hwnd); |
| | | // 初始化无操作检测(设置全局钩子和定时器) |
| | | void initializeIdleDetection(HWND hwnd); |
| | | |
| | | // 终止无操作检测(清除钩子和定时器) |
| | | void terminateIdleDetection(); |
| | | // 终止无操作检测(清除钩子和定时器) |
| | | void terminateIdleDetection(); |
| | | |
| | | // 获取当前登录用户名 |
| | | // 获取当前登录用户名 |
| | | std::string getCurrentUser() const; |
| | | |
| | | // 修改当前登录用户名 |
| | | void setCurrentUser(const std::string& strName); |
| | | // 修改当前登录用户名 |
| | | void setCurrentUser(const std::string& strName); |
| | | |
| | | // 获取当前登录用户密码 |
| | | // 获取当前登录用户密码 |
| | | std::string getCurrentPass() const; |
| | | |
| | | // 修改当前登录用户密码 |
| | | void setCurrentPass(const std::string& strPass); |
| | | // 修改当前登录用户密码 |
| | | void setCurrentPass(const std::string& strPass); |
| | | |
| | | // 获取当前登录用户角色 |
| | | // 获取当前登录用户角色 |
| | | UserRole getCurrentUserRole() const; |
| | | |
| | | // 修改当前登录用户角色 |
| | | void setCurrentUserRole(UserRole emRole); |
| | | // 修改当前登录用户角色 |
| | | void setCurrentUserRole(UserRole emRole); |
| | | |
| | | // 获取当前登录用户的无操作超时时间 |
| | | // 获取当前登录用户的无操作超时时间 |
| | | std::chrono::minutes getSessionTimeout() const; |
| | | |
| | | // 获取当前登录用户的会话过期时间 |
| | | // 获取当前登录用户的会话过期时间 |
| | | std::chrono::hours getSessionExpiration() const; |
| | | |
| | | private: |
| | | UserManager(); |
| | | ~UserManager(); |
| | | UserManager(); |
| | | ~UserManager(); |
| | | |
| | | // 初始化数据库连接和用户表 |
| | | bool initializeDatabase(); |
| | | // 初始化数据库连接和用户表 |
| | | bool initializeDatabase(); |
| | | |
| | | // 哈希密码,用于加密用户密码 |
| | | std::string hashPassword(const std::string& password); |
| | | // 哈希密码,用于加密用户密码 |
| | | std::string hashPassword(const std::string& password); |
| | | |
| | | // 加密和解密函数 |
| | | std::string simpleEncryptDecrypt(const std::string& data, const std::string& key); |
| | | // 加密和解密函数 |
| | | std::string simpleEncryptDecrypt(const std::string& data, const std::string& key); |
| | | |
| | | // 键盘和鼠标钩子函数 |
| | | static LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam); |
| | | static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); |
| | | // 键盘和鼠标钩子函数 |
| | | static LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam); |
| | | static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); |
| | | |
| | | // 属性定义 |
| | | std::string m_strCurrentUser; // 当前登录用户名 |
| | | std::string m_strCurrentPass; // 当前登录密码 |
| | | UserRole m_enCurrentUserRole; // 当前登录用户角色 |
| | | bool m_isLoggedIn; // 是否已登录 |
| | | bool m_isRememberMe; // 是否记住登录状态 |
| | | // 属性定义 |
| | | std::string m_strCurrentUser; // 当前登录用户名 |
| | | std::string m_strCurrentPass; // 当前登录密码 |
| | | UserRole m_enCurrentUserRole; // 当前登录用户角色 |
| | | bool m_isLoggedIn; // 是否已登录 |
| | | bool m_isRememberMe; // 是否记住登录状态 |
| | | |
| | | std::chrono::time_point<std::chrono::system_clock> m_tpLastLogin; // 上次登录时间 |
| | | std::chrono::time_point<std::chrono::system_clock> m_tpLastActivity; // 最后活动时间 |
| | | std::chrono::minutes m_tmSessionTimeout; // 无操作超时时间 |
| | | std::chrono::hours m_tmSessionExpiration; // 会话过期时间 |
| | | HHOOK m_hMouseHook; // 鼠标钩子句柄 |
| | | HHOOK m_hKeyboardHook; // 键盘钩子句柄 |
| | | std::chrono::time_point<std::chrono::system_clock> m_tpLastLogin; // 上次登录时间 |
| | | std::chrono::time_point<std::chrono::system_clock> m_tpLastActivity; // 最后活动时间 |
| | | std::chrono::minutes m_tmSessionTimeout; // 无操作超时时间 |
| | | std::chrono::hours m_tmSessionExpiration; // 会话过期时间 |
| | | HHOOK m_hMouseHook; // 鼠标钩子句柄 |
| | | HHOOK m_hKeyboardHook; // 键盘钩子句柄 |
| | | |
| | | std::unique_ptr<BL::Database> m_pDB; // 数据库接口 |
| | | std::unique_ptr<BL::Database> m_pDB; // 数据库接口 |
| | | }; |
| | | |
| | | #endif // USER_MANAGER_H |
| | |
| | | m_gridUserManager.ExpandLastColumn(); // 最后一列填充网格 |
| | | |
| | | m_mapRoleDescriptions.clear(); |
| | | m_mapRoleDescriptions.emplace(_T("管理员"), _T("管理所有用户,分配权限")); |
| | | m_mapRoleDescriptions.emplace(_T("工程师"), _T("维护系统,解决技术问题")); |
| | | m_mapRoleDescriptions.emplace(_T("操作员"), _T("执行日常操作任务")); |
| | | m_mapRoleDescriptions.emplace(_T("管理员"), _T("管理所有用户账户,分配和调整权限,负责系统安全与整体运行")); |
| | | m_mapRoleDescriptions.emplace(_T("制程工程师"), _T("负责生产工艺的制定、优化与改进,确保工艺稳定和良率提升")); |
| | | m_mapRoleDescriptions.emplace(_T("设备工程师"), _T("维护和保养设备,处理故障,保障设备稳定运行,参与技术升级")); |
| | | m_mapRoleDescriptions.emplace(_T("操作员"), _T("按照标准流程执行日常操作任务,监控生产状况,及时反馈异常")); |
| | | |
| | | FillUserManager(); |
| | | } |
| | |
| | | |
| | | CStringArray permissions; |
| | | permissions.Add(_T("管理员")); |
| | | permissions.Add(_T("工程师")); |
| | | permissions.Add(_T("制程工程师")); |
| | | permissions.Add(_T("设备工程师")); |
| | | permissions.Add(_T("操作员")); |
| | | |
| | | int nCols = m_gridUserManager.GetColumnCount(); |
| | | for (int i = 1; i < m_gridUserManager.GetRowCount(); ++i) { |
| | | m_gridUserManager.SetItemState(i, 0, GVIS_READONLY); // 第一列只读 |
| | | m_gridUserManager.SetItemState(i, 0, GVIS_READONLY); // 第一列只读 |
| | | m_gridUserManager.SetItemState(i, nCols - 2, GVIS_READONLY); // 倒数第二列只读 |
| | | m_gridUserManager.SetItemState(i, nCols - 1, GVIS_READONLY); // 最后一列只读 |
| | | |
| | |
| | | pCell->SetOptions(permissions); |
| | | pCell->SetStyle(CBS_DROPDOWNLIST); |
| | | |
| | | CString cstrRole = m_gridUserManager.GetItemText(i, 3); |
| | | int nRole = _ttoi(cstrRole); |
| | | if (nRole < 0 || nRole > 2) { |
| | | int nRole = _ttoi(m_gridUserManager.GetItemText(i, 3)); |
| | | if (nRole < 0 || nRole > 3) { |
| | | CString cstrMessage; |
| | | cstrMessage.Format(_T("用户 [%s],权限异常!将设置成操作员!"), m_gridUserManager.GetItemText(i, 1)); |
| | | AfxMessageBox(cstrMessage); |
| | | nRole = 2; |
| | | nRole = 3; |
| | | } |
| | | |
| | | m_gridUserManager.SetItemText(i, 3, permissions.GetAt(nRole)); |
| | |
| | | // 第四列设置(权限列)为下拉框 |
| | | CStringArray permissions; |
| | | permissions.Add(_T("管理员")); |
| | | permissions.Add(_T("工程师")); |
| | | permissions.Add(_T("制程工程师")); |
| | | permissions.Add(_T("设备工程师")); |
| | | permissions.Add(_T("操作员")); |
| | | |
| | | if (pGridCtrl->SetCellType(newRowIndex, 3, RUNTIME_CLASS(CGridCellCombo))) { |
| | |
| | | |
| | | CStringArray permissions; |
| | | permissions.Add(_T("管理员")); |
| | | permissions.Add(_T("工程师")); |
| | | permissions.Add(_T("制程工程师")); |
| | | permissions.Add(_T("设备工程师")); |
| | | permissions.Add(_T("操作员")); |
| | | |
| | | if (m_gridUserManager.SetCellType(row, 3, RUNTIME_CLASS(CGridCellCombo))) { |
| | |
| | | if (j == 3) { |
| | | if (cellText == _T("管理员")) |
| | | cellString = "0"; |
| | | else if (cellText == _T("工程师")) |
| | | else if (cellText == _T("制程工程师")) |
| | | cellString = "1"; |
| | | else if (cellText == _T("设备工程师")) |
| | | cellString = "2"; |
| | | else if (cellText == _T("操作员")) |
| | | cellString = "2"; |
| | | cellString = "3"; |
| | | else |
| | | cellString = "2"; |
| | | cellString = "3"; |
| | | } |
| | | |
| | | rowData.push_back(cellString); |