From 3970068b82a21617443fd99a152723e54289ecf2 Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期三, 08 一月 2025 16:14:49 +0800
Subject: [PATCH] 1.继续移入相关文件,警告功能等;
---
SourceCode/Bond/BoounionPLC/AlarmMonitor.h | 42
SourceCode/Bond/BoounionPLC/DBManager/UserManager.cpp | 542 +++++++
SourceCode/Bond/BoounionPLC/PLC.h | 77 +
SourceCode/Bond/BoounionPLC/ToolUnits.cpp | 304 ++++
SourceCode/Bond/BoounionPLC/McInt.h | 12
SourceCode/Bond/BoounionPLC/DBManager/AxisManager.cpp | 246 +++
SourceCode/Bond/BoounionPLC/DBManager/SystemLogManager.cpp | 208 +++
SourceCode/Bond/BoounionPLC/Intent.h | 25
SourceCode/Bond/BoounionPLC/ToolUnits.h | 32
SourceCode/Bond/BoounionPLC/DBManager/AlarmManager.h | 142 ++
SourceCode/Bond/BoounionPLC/McString.h | 15
SourceCode/Bond/BoounionPLC/AlarmPopupDlg.h | 61
SourceCode/Bond/BoounionPLC/Component.h | 59
SourceCode/Bond/BoounionPLC/Context.cpp | 157 ++
SourceCode/Bond/BoounionPLC/McItem.h | 8
SourceCode/Bond/BoounionPLC/TopToolbar.h | 1
SourceCode/Bond/BoounionPLC/AlarmMonitor.cpp | 255 +++
SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj | 33
SourceCode/Bond/BoounionPLC/Alarm.cpp | 131 +
SourceCode/Bond/BoounionPLC/DBManager/SystemLogManager.h | 76 +
SourceCode/Bond/BoounionPLC/McBool.h | 12
SourceCode/Bond/BoounionPLC/PLC.cpp | 330 ++++
SourceCode/Bond/x64/BoounionPLC/Debug/Res/alarm_gray_32.ico | 0
SourceCode/Bond/BoounionPLC/BoounionPLC.rc | 0
SourceCode/Bond/BoounionPLC/McInt.cpp | 14
SourceCode/Bond/BoounionPLC/Context.h | 44
SourceCode/Bond/x64/BoounionPLC/Debug/Res/alarm_o_32.ico | 0
SourceCode/Bond/BoounionPLC/Common.h | 33
SourceCode/Bond/BoounionPLC/Intent.cpp | 51
SourceCode/Bond/BoounionPLC/McBool.cpp | 14
SourceCode/Bond/BoounionPLC/Resource.h | 0
SourceCode/Bond/BoounionPLC/TopToolbar.cpp | 8
SourceCode/Bond/BoounionPLC/DBManager/UserManager.h | 131 +
SourceCode/Bond/BoounionPLC/DBManager/AxisManager.h | 75 +
SourceCode/Bond/BoounionPLC/stdafx.h | 18
SourceCode/Bond/BoounionPLC/Component.cpp | 126 +
SourceCode/Bond/BoounionPLC/Alarm.h | 37
SourceCode/Bond/BoounionPLC/BoounionPLCDlg.cpp | 36
SourceCode/Bond/BoounionPLC/BoounionPLCDlg.h | 4
SourceCode/Bond/BoounionPLC/McItem.cpp | 12
SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.filters | 93 +
SourceCode/Bond/BoounionPLC/McString.cpp | 14
SourceCode/Bond/BoounionPLC/AlarmPopupDlg.cpp | 329 ++++
SourceCode/Bond/BoounionPLC/DBManager/AlarmManager.cpp | 235 +++
44 files changed, 4,040 insertions(+), 2 deletions(-)
diff --git a/SourceCode/Bond/BoounionPLC/Alarm.cpp b/SourceCode/Bond/BoounionPLC/Alarm.cpp
new file mode 100644
index 0000000..ef82a47
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/Alarm.cpp
@@ -0,0 +1,131 @@
+#include "stdafx.h"
+#include "Alarm.h"
+#include "ToolUnits.h"
+
+
+CAlarm::CAlarm()
+{
+ m_nStatus = 0;
+ m_nId = 0;
+ m_nLevel = 0;
+}
+
+CAlarm::CAlarm(int id, int level, const char* pszText)
+{
+ m_nStatus = 0;
+ m_nId = id;
+ m_nLevel = level;
+ m_strText = pszText;
+}
+
+CAlarm::CAlarm(CAlarm* pScr)
+{
+ m_nStatus = 0;
+ m_nId = pScr->m_nId;
+ m_nLevel = pScr->m_nLevel;
+ m_strText = pScr->m_strText;;
+}
+
+CAlarm::~CAlarm()
+{
+}
+
+std::string& CAlarm::getClassName()
+{
+ static std::string strName = "CAlarm";
+ return strName;
+}
+
+std::string CAlarm::toString()
+{
+ std::string strText;
+ strText += "CAlarm[";
+ strText += ("m_timeOn:" + CToolUnits::timeToString2(m_timeOn) + ";");
+ strText += ("m_timeOff:" + CToolUnits::timeToString2(m_timeOff) + ";");
+ strText += ("m_nStatus:" + std::to_string(m_nStatus) + ";");
+ strText += ("m_nId:" + std::to_string(m_nId) + ";");
+ strText += ("m_nLevel:" + std::to_string(m_nLevel) + ";");
+ strText += ("m_strText:" + m_strText + ";");
+ strText += "]";
+
+ return strText;
+}
+
+int CAlarm::getUnitId()
+{
+ return m_nUnitId;
+}
+
+void CAlarm::alarmOn()
+{
+ if (m_nStatus == 0) {
+ m_nStatus++;
+ m_timeOn = CToolUnits::getTimestamp();
+ }
+}
+
+void CAlarm::alarmOff()
+{
+ if (m_nStatus == 1) {
+ m_nStatus++;
+ m_timeOff = CToolUnits::getTimestamp();
+ }
+}
+
+ULONGLONG CAlarm::getOnTime()
+{
+ return m_timeOn;
+}
+
+ULONGLONG CAlarm::getOffTime()
+{
+ return m_timeOff;
+}
+
+int CAlarm::getId()
+{
+ return m_nId;
+}
+
+int CAlarm::getLevel()
+{
+ return m_nLevel;
+}
+
+int CAlarm::getStatus()
+{
+ return m_nStatus;
+}
+
+std::string& CAlarm::getText()
+{
+ return m_strText;
+}
+
+void CAlarm::Serialize(CArchive& ar)
+{
+ if (ar.IsStoring())
+ {
+ Lock();
+ ar << m_nUnitId;
+ ar << m_nId;
+ ar << m_nLevel;
+ ar << m_timeOn;
+ ar << m_timeOff;
+ ar << m_nStatus;
+ WriteString(ar, m_strText);
+ Unlock();
+ }
+ else
+ {
+ Lock();
+ ar >> m_nUnitId;
+ ar >> m_nId;
+ ar >> m_nLevel;
+ ar >> m_timeOn;
+ ar >> m_timeOff;
+ ar >> m_nStatus;
+ ReadString(ar, m_strText);
+ Unlock();
+ }
+}
diff --git a/SourceCode/Bond/BoounionPLC/Alarm.h b/SourceCode/Bond/BoounionPLC/Alarm.h
new file mode 100644
index 0000000..12b4a26
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/Alarm.h
@@ -0,0 +1,37 @@
+#pragma once
+#include "Context.h"
+
+class CAlarm :
+ public CContext
+{
+public:
+ CAlarm();
+ CAlarm(int id, int level, const char* pszText);
+ CAlarm(int status, int id, int level, const char* pszText);
+ CAlarm(CAlarm* pScr);
+ ~CAlarm();
+
+public:
+ virtual std::string& getClassName();
+ virtual std::string toString();
+ int getUnitId();
+ void alarmOn();
+ void alarmOff();
+ ULONGLONG getOnTime();
+ ULONGLONG getOffTime();
+ int getId();
+ int getLevel();
+ int getStatus();
+ std::string& getText();
+ void Serialize(CArchive& ar);
+
+private:
+ int m_nUnitId;
+ ULONG64 m_timeOn;
+ ULONG64 m_timeOff;
+ int m_nStatus; // 0:未知;1:ON;2:OFF;
+ int m_nId;
+ int m_nLevel;
+ std::string m_strText;
+};
+
diff --git a/SourceCode/Bond/BoounionPLC/AlarmMonitor.cpp b/SourceCode/Bond/BoounionPLC/AlarmMonitor.cpp
new file mode 100644
index 0000000..999e0cb
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/AlarmMonitor.cpp
@@ -0,0 +1,255 @@
+#include "stdafx.h"
+#include "AlarmMonitor.h"
+#include "Common.h"
+#include "BoounionPLC.h"
+#include "Log.h"
+#include "ToolUnits.h"
+#include "AlarmManager.h"
+
+#define ALARM_MAX 200
+
+CAlarmMonitor::CAlarmMonitor()
+{
+ m_pRawData = new char[512];
+ memset(m_pRawData, 0, 512);
+}
+
+
+CAlarmMonitor::~CAlarmMonitor()
+{
+ if (m_pRawData != nullptr) {
+ delete[] m_pRawData;
+ m_pRawData = nullptr;
+ }
+
+ for (auto item : m_mapAlarmTemplate) {
+ delete item.second;
+ }
+ m_mapAlarmTemplate.clear();
+
+ for (auto item : m_mapAlarming) {
+ item.second->release();
+ }
+ m_mapAlarming.clear();
+}
+
+std::string& CAlarmMonitor::getClassName()
+{
+ static std::string strClassName = "CAlarmMonitor";
+ return strClassName;
+}
+
+void CAlarmMonitor::onRecvBroadcast(void* pSender, CIntent* pIntent)
+{
+
+}
+
+void CAlarmMonitor::onData(int id, const void* pData, int size)
+{
+ const char* pszData = (const char*)pData;
+ if (MONITOR_ID_ALARM != id) {
+ return;
+ }
+
+ // 比较有没有变化
+ if (compareData(m_pRawData, (const char*)pData, size)) {
+ return;
+ }
+ memcpy(m_pRawData, (const char*)pData, size);
+
+
+ // 找到On的报警并缓存
+ std::vector<int> alarmIds;
+ for (auto item : m_mapAlarmTemplate) {
+ if (isAlarmOn(item.first)) {
+ alarmIds.push_back(item.first);
+ }
+ }
+
+
+ // 发生警告:
+ // 比较新加的ON的警告
+ // 即m_mapAlarming无,alarmIds有
+ for (auto item : alarmIds) {
+ if (m_mapAlarming.find(item) == m_mapAlarming.end()) {
+ auto iter = m_mapAlarmTemplate.find(item);
+ if (iter != m_mapAlarmTemplate.end()) {
+ CAlarm* pAlarm = new CAlarm(iter->second);
+ pAlarm->alarmOn();
+ pAlarm->addRef();
+ m_mapAlarming[item] = pAlarm;
+ LOGE("发生了警告:%s", pAlarm->toString().c_str());
+
+ // 警告信息发出,以使界面显示和历史记录保存
+ SendBroadcast(&CIntent(BC_CODE_ALARM_ON, "", pAlarm));
+ }
+ }
+ }
+
+ // 削除警告:
+ // 比较得到原来ON(m_mapAlarming有), 现在OFF的警告(alarmIds无)
+ for (auto iter = m_mapAlarming.begin(); iter != m_mapAlarming.end();/* iter++*/) {
+ if (!findAlarm(alarmIds, iter->first)) {
+ // 消除警告, 同时将信息发出,以使界面显示和历史记录保存
+ CAlarm* pAlarm = iter->second;
+ pAlarm->alarmOff();
+ addAlarmToHistoryRecord(pAlarm);
+ m_mapAlarming.erase(iter++);
+
+ LOGE("消除了警告:%s", pAlarm->toString().c_str());
+ SendBroadcast(&CIntent(BC_CODE_ALARM_OFF, "", pAlarm));
+ pAlarm->release();
+ }
+ else {
+ iter++;
+ }
+ }
+}
+
+int CAlarmMonitor::readAlarmListFromFile(const char* pszFilepath)
+{
+ CStdioFile file;
+ if (!file.Open(pszFilepath, CFile::modeRead)) {
+ return -1;
+ }
+
+ CString strLine, strNumber, strLevel, strDescription;
+ int number, level;
+ while (file.ReadString(strLine)) {
+ if (!AfxExtractSubString(strNumber, (LPCTSTR)strLine, 0, ','))
+ continue;
+ if (!AfxExtractSubString(strLevel, (LPCTSTR)strLine, 1, ','))
+ continue;
+ if (!AfxExtractSubString(strDescription, (LPCTSTR)strLine, 2, ','))
+ continue;
+
+ try {
+ number = std::stoi((LPTSTR)(LPCTSTR)strNumber);
+ level = std::stoi((LPTSTR)(LPCTSTR)strLevel);
+ }
+ catch (...) {
+ continue;
+ }
+
+ addAlarmTemplate(number, level, (LPTSTR)(LPCTSTR)strDescription);
+ }
+
+ file.Close();
+ return (int)m_mapAlarmTemplate.size();
+}
+
+void CAlarmMonitor::init()
+{
+ CComponent::init();
+}
+
+void CAlarmMonitor::term()
+{
+
+}
+
+void CAlarmMonitor::OnTimer(UINT nTimerid)
+{
+
+}
+
+const char* CAlarmMonitor::getAlarmText(int nID)
+{
+ auto iter = m_mapAlarmTemplate.find(nID);
+ if (iter == m_mapAlarmTemplate.end()) return "";
+ return iter->second->getText().c_str();
+}
+
+void CAlarmMonitor::Serialize(CArchive& ar)
+{
+ if (ar.IsStoring()) {
+ }
+ else {
+ }
+}
+
+std::map<int, CAlarm*>& CAlarmMonitor::getAlarmingMap()
+{
+ return m_mapAlarming;
+}
+
+BOOL CAlarmMonitor::isAlarming()
+{
+ Lock();
+ BOOL bAlarming = !m_mapAlarming.empty();
+ Unlock();
+ return bAlarming;
+}
+
+CAlarm* CAlarmMonitor::getActiveAlarm()
+{
+ Lock();
+ if (m_mapAlarming.empty()) {
+ Unlock();
+ return nullptr;
+ }
+ auto iter = m_mapAlarming.begin();
+ Unlock();
+
+ return iter->second;
+}
+
+BOOL CAlarmMonitor::compareData(const char* pScrData, const char* pTarData, int len)
+{
+ for (int i = 0; i < len; i++) {
+ if (pScrData[i] != pTarData[i]) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+int CAlarmMonitor::addAlarmTemplate(int id, int level, const char* pszDescription)
+{
+ auto iter = m_mapAlarmTemplate.find(id);
+ if (iter != m_mapAlarmTemplate.end()) return -1;
+
+ CAlarm* pAlarm = new CAlarm(id, level, pszDescription);
+ m_mapAlarmTemplate[id] = pAlarm;
+ return 0;
+}
+
+BOOL CAlarmMonitor::isAlarmOn(int id)
+{
+ int byteIndex, bitIndex;
+ byteIndex = (id - 1) / 8;
+ bitIndex = (id - 1) % 8;
+
+ return CToolUnits::getBit(m_pRawData[byteIndex], bitIndex);
+}
+
+BOOL CAlarmMonitor::findAlarm(std::vector<int>& ids, int id)
+{
+ for (auto item : ids) {
+ if (item == id) return TRUE;
+ }
+
+ return FALSE;
+}
+
+void CAlarmMonitor::addAlarmToHistoryRecord(CAlarm* pAlarm)
+{
+ // 加入数据库
+ AlarmManager::getInstance().addAlarm(
+ std::to_string(pAlarm->getId()).c_str(),
+ getAlarmText(pAlarm->getId()),
+ CToolUnits::timeToString2(pAlarm->getOnTime()).c_str(),
+ CToolUnits::timeToString2(pAlarm->getOffTime()).c_str());
+}
+
+BOOL CAlarmMonitor::addAlarming(CAlarm* pAlarm)
+{
+ auto iter = m_mapAlarming.find(pAlarm->getId());
+ if (iter != m_mapAlarming.end()) return FALSE;
+
+ pAlarm->addRef();
+ m_mapAlarming[pAlarm->getId()] = pAlarm;
+
+ return TRUE;
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/BoounionPLC/AlarmMonitor.h b/SourceCode/Bond/BoounionPLC/AlarmMonitor.h
new file mode 100644
index 0000000..c7cf2f1
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/AlarmMonitor.h
@@ -0,0 +1,42 @@
+#pragma once
+#include "Component.h"
+#include <map>
+#include <list>
+#include "Alarm.h"
+
+class CAlarmMonitor :
+ public CComponent
+{
+public:
+ CAlarmMonitor();
+ ~CAlarmMonitor();
+
+public:
+ virtual std::string& getClassName();
+ virtual void onData(int id, const void* pData, int size);
+ virtual void onRecvBroadcast(void* pSender, CIntent* pIntent);
+ virtual void init();
+ virtual void term();
+ int readAlarmListFromFile(const char* pszFilepath);
+ virtual void OnTimer(UINT nTimerid);
+ const char* getAlarmText(int nID);
+ virtual void Serialize(CArchive& ar);
+ std::map<int, CAlarm*>& getAlarmingMap();
+ BOOL isAlarming();
+ CAlarm* getActiveAlarm();
+ void getAlarmRecords(std::list< CAlarm*>& list);
+
+private:
+ BOOL compareData(const char* pScrData, const char* pTarData, int len);
+ int addAlarmTemplate(int id, int level, const char* pszDescription);
+ BOOL isAlarmOn(int id);
+ BOOL findAlarm(std::vector<int>& ids, int id);
+ void addAlarmToHistoryRecord(CAlarm* pAlarm);
+ BOOL addAlarming(CAlarm* pAlarm);
+
+private:
+ std::map<int, CAlarm*> m_mapAlarmTemplate; // 这是警告的模板,从文件加载
+ std::map<int, CAlarm*> m_mapAlarming; // 正在发生的警告
+ char* m_pRawData;
+};
+
diff --git a/SourceCode/Bond/BoounionPLC/AlarmPopupDlg.cpp b/SourceCode/Bond/BoounionPLC/AlarmPopupDlg.cpp
new file mode 100644
index 0000000..c62e850
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/AlarmPopupDlg.cpp
@@ -0,0 +1,329 @@
+// AlarmPopupDlg.cpp : 实现文件
+//
+
+#include "stdafx.h"
+#include "BoounionPLC.h"
+#include "AlarmPopupDlg.h"
+#include "afxdialogex.h"
+#include "HorizontalLine.h"
+#include "AlarmMonitor.h"
+
+
+// CAlarmPopupDlg 对话框
+
+IMPLEMENT_DYNAMIC(CAlarmPopupDlg, CDialogEx)
+
+CAlarmPopupDlg::CAlarmPopupDlg(CWnd* pParent /*=NULL*/)
+ : CDialogEx(IDD_DIALOG_POPUP_ALARM, pParent)
+{
+ m_pPLC = nullptr;
+
+ m_crBkgnd = RGB(225, 225, 225);
+ m_hbrBkgnd = nullptr;
+ m_pActiveAlarm = nullptr;
+ m_pObserver = nullptr;
+}
+
+CAlarmPopupDlg::~CAlarmPopupDlg()
+{
+}
+
+void CAlarmPopupDlg::SetPLC(CPLC* pPLC)
+{
+ ASSERT(pPLC);
+ m_pPLC = pPLC;
+}
+
+
+void CAlarmPopupDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialogEx::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CAlarmPopupDlg, CDialogEx)
+ ON_WM_CTLCOLOR()
+ ON_WM_DESTROY()
+ ON_WM_SIZE()
+ ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CAlarmPopupDlg::OnBnClickedButtonClose)
+ ON_BN_CLICKED(IDC_BUTTON_SOUND_OFF, &CAlarmPopupDlg::OnBnClickedButtonSoundOff)
+ ON_BN_CLICKED(IDC_BUTTON_ALARM_OFF, &CAlarmPopupDlg::OnBnClickedButtonAlarmOff)
+END_MESSAGE_MAP()
+
+
+// CAlarmPopupDlg 消息处理程序
+
+
+void CAlarmPopupDlg::InitRxWindows()
+{
+ /* code */
+ // 订阅数据
+ IRxWindows* pRxWindows = RX_GetRxWindows();
+ pRxWindows->enableLog(5);
+ if (m_pObserver == NULL) {
+ m_pObserver = pRxWindows->allocObserver([&](IAny* pAny) -> void {
+ // onNext
+ pAny->addRef();
+ int code = pAny->getCode();
+ if (RX_CODE_BONDER_BEEP == code) {
+ bool bMute = FALSE;// theApp.m_model.getBonder().isMute();
+ SetButtonBackgroundColors(bMute);
+ }
+ pAny->release();
+ }, [&]() -> void {
+ // onComplete
+ }, [&](IThrowable* pThrowable) -> void {
+ // onErrorm
+ pThrowable->printf();
+ });
+
+ theApp.m_model.getObservable()->observeOn(pRxWindows->mainThread())
+ ->subscribe(m_pObserver);
+ }
+}
+
+BOOL CAlarmPopupDlg::OnInitDialog()
+{
+ CDialogEx::OnInitDialog();
+
+
+ // 字体
+ HFONT hFontDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+ LOGFONT lf;
+
+ ::GetObject(hFontDefault, sizeof(LOGFONT), &lf);
+ lf.lfHeight -= 8;
+ lf.lfWeight = 700;
+ m_fontTitle.CreateFontIndirect(&lf);
+
+ ::GetObject(hFontDefault, sizeof(LOGFONT), &lf);
+ lf.lfHeight -= 8;
+ m_fontLevel.CreateFontIndirect(&lf);
+
+ ::GetObject(hFontDefault, sizeof(LOGFONT), &lf);
+ lf.lfHeight -= 16;
+ m_fontName.CreateFontIndirect(&lf);
+
+ ::GetObject(hFontDefault, sizeof(LOGFONT), &lf);
+ lf.lfHeight -= 8;
+ m_fontDescription.CreateFontIndirect(&lf);
+
+ GetDlgItem(IDC_LABEL_TITLE)->SetFont(&m_fontTitle);
+ GetDlgItem(IDC_LABEL_LEVEL)->SetFont(&m_fontLevel);
+ GetDlgItem(IDC_LABEL_NAME)->SetFont(&m_fontName);
+ GetDlgItem(IDC_LABEL_DESCRIPTION)->SetFont(&m_fontDescription);
+
+
+ // 图标
+ CString strIcon1;
+ HICON hIcon;
+ CStatic* pStatic;
+
+ strIcon1.Format(_T("%s\\Res\\Alarm_o_24.ico"), theApp.m_strAppDir);
+ pStatic = (CStatic*)GetDlgItem(IDC_ICON_TITLE);
+ hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(),
+ strIcon1, IMAGE_ICON, 24, 24,
+ LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
+ pStatic->SetIcon(hIcon);
+
+ strIcon1.Format(_T("%s\\Res\\Alarm_o_64.ico"), theApp.m_strAppDir);
+ pStatic = (CStatic*)GetDlgItem(IDC_ICON_ALARM);
+ hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(),
+ strIcon1, IMAGE_ICON, 64, 64,
+ LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
+ pStatic->SetIcon(hIcon);
+
+
+ // 关闭按钮
+ strIcon1.Format(_T("%s\\Res\\close_blcak_24.ico"), theApp.m_strAppDir);
+ pStatic = (CStatic*)GetDlgItem(IDC_ICON_ALARM);
+ hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(),
+ strIcon1, IMAGE_ICON, 128, 128,
+ LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
+ m_btnClose.SubclassDlgItem(IDC_BUTTON_CLOSE, this);
+ m_btnClose.SetIcon(hIcon, hIcon, 24);
+
+
+ // 解除警告按钮
+ m_btnAlarmOff.SubclassDlgItem(IDC_BUTTON_ALARM_OFF, this);
+ m_btnAlarmOff.SetFrameColor(BS_NORMAL, BTN_ALARM_OFF_FRAME_NORMAL);
+ m_btnAlarmOff.SetFrameColor(BS_HOVER, BTN_ALARM_OFF_FRAME_HOVER);
+ m_btnAlarmOff.SetFrameColor(BS_PRESS, BTN_ALARM_OFF_FRAME_PRESS);
+ m_btnAlarmOff.SetBkgndColor(BS_NORMAL, BTN_ALARM_OFF_BKGND_NORMAL);
+ m_btnAlarmOff.SetBkgndColor(BS_HOVER, BTN_ALARM_OFF_BKGND_HOVER);
+ m_btnAlarmOff.SetBkgndColor(BS_PRESS, BTN_ALARM_OFF_BKGND_PRESS);
+
+
+ // 静音按钮
+ bool bMute = FALSE;// theApp.m_model.getBonder().isMute();
+ m_btnSoundOff.SubclassDlgItem(IDC_BUTTON_SOUND_OFF, this);
+ m_btnSoundOff.SetFrameColor(BS_NORMAL, BTN_SOUND_OFF_FRAME_NORMAL);
+ m_btnSoundOff.SetFrameColor(BS_HOVER, BTN_SOUND_OFF_FRAME_HOVER);
+ m_btnSoundOff.SetFrameColor(BS_PRESS, BTN_SOUND_OFF_FRAME_PRESS);
+ SetButtonBackgroundColors(bMute);
+
+ // 横线1
+ CHorizontalLine* pLine = CHorizontalLine::Hook(GetDlgItem(IDC_LINE1)->m_hWnd);
+ pLine->SetBkgndColor(RGB(225, 225, 225));
+ pLine->SetLineColor(RGB(168, 168, 168));
+
+ pLine = CHorizontalLine::Hook(GetDlgItem(IDC_LINE2)->m_hWnd);
+ pLine->SetBkgndColor(RGB(225, 225, 225));
+ pLine->SetLineColor(RGB(168, 168, 168));
+
+
+ InitRxWindows();
+ return TRUE; // return TRUE unless you set the focus to a control
+ // 异常: OCX 属性页应返回 FALSE
+}
+
+
+HBRUSH CAlarmPopupDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
+{
+ HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
+
+ if (nCtlColor == CTLCOLOR_STATIC) {
+ pDC->SetBkColor(m_crBkgnd);
+ pDC->SetTextColor(RGB(0, 0, 0));
+ }
+
+ if (m_hbrBkgnd == nullptr) {
+ m_hbrBkgnd = CreateSolidBrush(m_crBkgnd);
+ }
+
+ return m_hbrBkgnd;
+}
+
+
+void CAlarmPopupDlg::OnDestroy()
+{
+ CDialogEx::OnDestroy();
+
+ if (m_hbrBkgnd != nullptr) {
+ ::DeleteObject(m_hbrBkgnd);
+ }
+
+ if (m_pActiveAlarm != nullptr) {
+ m_pActiveAlarm->release();
+ m_pActiveAlarm = nullptr;
+ }
+
+ if (m_pObserver != nullptr) {
+ m_pObserver->unsubscribe();
+ m_pObserver = NULL;
+ }
+}
+
+
+void CAlarmPopupDlg::OnSize(UINT nType, int cx, int cy)
+{
+ CDialogEx::OnSize(nType, cx, cy);
+
+ // TODO: 在此处添加消息处理程序代码
+}
+
+void CAlarmPopupDlg::AlarmOn()
+{
+ ShowFirstAlarm();
+}
+
+void CAlarmPopupDlg::AlarmOff()
+{
+ ShowFirstAlarm();
+}
+
+void CAlarmPopupDlg::OnBnClickedButtonClose()
+{
+ // OnCancel();
+ ShowWindow(SW_HIDE);
+}
+
+void CAlarmPopupDlg::ShowFirstAlarm()
+{
+ // 取出警告信息首条并显示
+ if (m_pActiveAlarm != nullptr) {
+ m_pActiveAlarm->release();
+ }
+
+ CString strText;
+ CAlarmMonitor* pAlarmMonitor = m_pPLC->getAlarmMonitor();
+ m_pActiveAlarm = pAlarmMonitor->getActiveAlarm();
+ if (m_pActiveAlarm != nullptr) {
+ m_pActiveAlarm->addRef();
+ SetDlgItemText(IDC_LABEL_NAME, pAlarmMonitor->getAlarmText(m_pActiveAlarm->getId()));
+ strText.Format(_T("ID: %d"), m_pActiveAlarm->getId());
+ SetDlgItemText(IDC_LABEL_LEVEL, strText);
+ ShowWindow(SW_SHOW);
+ }
+ else {
+ ShowWindow(SW_HIDE);
+ }
+}
+
+void CAlarmPopupDlg::SetButtonBackgroundColors(bool bMute)
+{
+ if (!bMute) {
+ m_btnSoundOff.SetBkgndColor(BS_NORMAL, BTN_SOUND_OFF_BKGND_NORMAL);
+ m_btnSoundOff.SetBkgndColor(BS_HOVER, BTN_SOUND_OFF_BKGND_HOVER);
+ m_btnSoundOff.SetBkgndColor(BS_PRESS, BTN_SOUND_OFF_BKGND_PRESS);
+ m_btnSoundOff.Invalidate();
+ }
+ else {
+ m_btnSoundOff.SetBkgndColor(BS_NORMAL, BTN_SOUND_ON_BKGND_NORMAL);
+ m_btnSoundOff.SetBkgndColor(BS_HOVER, BTN_SOUND_ON_BKGND_HOVER);
+ m_btnSoundOff.SetBkgndColor(BS_PRESS, BTN_SOUND_ON_BKGND_PRESS);
+ m_btnSoundOff.Invalidate();
+ }
+}
+
+void CAlarmPopupDlg::OnBnClickedButtonSoundOff()
+{
+ // TODO: 在此添加控件通知处理程序代码
+ if (m_pPLC == nullptr || !m_pPLC->isConnected()) {
+ return;
+ }
+
+ // 向 PLC 写入信号
+ bool bMute = m_pPLC->isMute();
+ char szWrite[4] = { 0x1, 0x0, 0x0, 0x0 };
+ szWrite[0] = !bMute;
+ m_pPLC->writeData(MC::M, 1003, szWrite, 2, [](IMcChannel* pChannel, int nAddr, DWORD nValue, int nFlag) {
+ if (nFlag == 0) {
+ TRACE("操作成功:地址=1003\n", nAddr);
+ }
+ else {
+ TRACE("操作失败:地址=1003,错误码=%d\n", nFlag);
+ }
+ });
+}
+
+void CAlarmPopupDlg::OnBnClickedButtonAlarmOff()
+{
+ // TODO: 在此添加控件通知处理程序代码
+ if (m_pPLC == nullptr || !m_pPLC->isConnected()) {
+ return;
+ }
+
+ // 向 PLC 写入信号
+ char szWrite[4] = { 0x1, 0x0, 0x0, 0x0 };
+ m_pPLC->writeData(MC::M, 1009, szWrite, 2, [](IMcChannel* pChannel, int nAddr, DWORD nValue, int nFlag) {
+ if (nFlag == 0) {
+ TRACE("操作成功:地址=1009\n", nAddr);
+ }
+ else {
+ TRACE("操作失败:地址=1009,错误码=%d\n", nFlag);
+ }
+ });
+
+ Sleep(500);
+
+ szWrite[0] = 0x0;
+ m_pPLC->writeData(MC::M, 1009, szWrite, 2, [](IMcChannel* pChannel, int nAddr, DWORD nValue, int nFlag) {
+ if (nFlag == 0) {
+ TRACE("操作成功:地址=1009\n", nAddr);
+ }
+ else {
+ TRACE("操作失败:地址=1009,错误码=%d\n", nFlag);
+ }
+ });
+}
diff --git a/SourceCode/Bond/BoounionPLC/AlarmPopupDlg.h b/SourceCode/Bond/BoounionPLC/AlarmPopupDlg.h
new file mode 100644
index 0000000..cce5908
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/AlarmPopupDlg.h
@@ -0,0 +1,61 @@
+#pragma once
+#include "BlButton.h"
+#include "Alarm.h"
+
+
+// CAlarmPopupDlg 对话框
+
+class CAlarmPopupDlg : public CDialogEx
+{
+ DECLARE_DYNAMIC(CAlarmPopupDlg)
+
+public:
+ CAlarmPopupDlg(CWnd* pParent = NULL); // 标准构造函数
+ virtual ~CAlarmPopupDlg();
+
+public:
+ void SetPLC(CPLC* pPLC);
+
+public:
+ void AlarmOn();
+ void AlarmOff();
+
+private:
+ void InitRxWindows();
+ void ShowFirstAlarm();
+ void SetButtonBackgroundColors(bool bMute);
+
+private:
+ COLORREF m_crBkgnd;
+ HBRUSH m_hbrBkgnd;
+ CFont m_fontTitle;
+ CFont m_fontLevel;
+ CFont m_fontName;
+ CFont m_fontDescription;
+
+private:
+ IObserver* m_pObserver;
+ CPLC* m_pPLC;
+ CAlarm* m_pActiveAlarm;
+ CBlButton m_btnClose;
+ CBlButton m_btnSoundOff;
+ CBlButton m_btnAlarmOff;
+
+// 对话框数据
+#ifdef AFX_DESIGN_TIME
+ enum { IDD = IDD_DIALOG_POPUP_ALARM };
+#endif
+
+protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
+
+ DECLARE_MESSAGE_MAP()
+public:
+ virtual BOOL OnInitDialog();
+ afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
+ afx_msg void OnDestroy();
+ afx_msg void OnSize(UINT nType, int cx, int cy);
+ afx_msg void OnBnClickedButtonClose();
+ afx_msg void OnBnClickedButtonSoundOff();
+ afx_msg void OnBnClickedButtonAlarmOff();
+};
diff --git a/SourceCode/Bond/BoounionPLC/BoounionPLC.rc b/SourceCode/Bond/BoounionPLC/BoounionPLC.rc
index e936298..c27ba0d 100644
--- a/SourceCode/Bond/BoounionPLC/BoounionPLC.rc
+++ b/SourceCode/Bond/BoounionPLC/BoounionPLC.rc
Binary files differ
diff --git a/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj b/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj
index 74969b5..d697913 100644
--- a/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj
+++ b/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj
@@ -116,6 +116,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>.;.\DBManager;..\DatabaseSDK\include</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@@ -191,6 +192,9 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\BondEq\HorizontalLine.h" />
+ <ClInclude Include="Alarm.h" />
+ <ClInclude Include="AlarmMonitor.h" />
+ <ClInclude Include="AlarmPopupDlg.h" />
<ClInclude Include="ApredTreeCtrl.h" />
<ClInclude Include="BlButton.h" />
<ClInclude Include="BoounionPLC.h" />
@@ -198,8 +202,19 @@
<ClInclude Include="CBaseView.h" />
<ClInclude Include="CMainContainer.h" />
<ClInclude Include="Common.h" />
+ <ClInclude Include="Component.h" />
<ClInclude Include="Configuration.h" />
+ <ClInclude Include="Context.h" />
+ <ClInclude Include="DBManager\AlarmManager.h" />
+ <ClInclude Include="DBManager\AxisManager.h" />
+ <ClInclude Include="DBManager\SystemLogManager.h" />
+ <ClInclude Include="DBManager\UserManager.h" />
+ <ClInclude Include="Intent.h" />
<ClInclude Include="Log.h" />
+ <ClInclude Include="McBool.h" />
+ <ClInclude Include="McInt.h" />
+ <ClInclude Include="McItem.h" />
+ <ClInclude Include="McString.h" />
<ClInclude Include="Model.h" />
<ClInclude Include="PagePlcList.h" />
<ClInclude Include="PLC.h" />
@@ -207,19 +222,36 @@
<ClInclude Include="Resource.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
+ <ClInclude Include="ToolUnits.h" />
<ClInclude Include="TopToolbar.h" />
<ClInclude Include="VerticalLine.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\BondEq\HorizontalLine.cpp" />
+ <ClCompile Include="Alarm.cpp" />
+ <ClCompile Include="AlarmMonitor.cpp" />
+ <ClCompile Include="AlarmPopupDlg.cpp" />
<ClCompile Include="ApredTreeCtrl.cpp" />
<ClCompile Include="BlButton.cpp" />
<ClCompile Include="BoounionPLC.cpp" />
<ClCompile Include="BoounionPLCDlg.cpp" />
<ClCompile Include="CBaseView.cpp" />
<ClCompile Include="CMainContainer.cpp" />
+ <ClCompile Include="Component.cpp" />
<ClCompile Include="Configuration.cpp" />
+ <ClCompile Include="Context.cpp" />
+ <ClCompile Include="DBManager\AlarmManager.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Use</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="DBManager\AxisManager.cpp" />
+ <ClCompile Include="DBManager\SystemLogManager.cpp" />
+ <ClCompile Include="DBManager\UserManager.cpp" />
+ <ClCompile Include="Intent.cpp" />
<ClCompile Include="Log.cpp" />
+ <ClCompile Include="McBool.cpp" />
+ <ClCompile Include="McInt.cpp" />
+ <ClCompile Include="McItem.cpp" />
+ <ClCompile Include="McString.cpp" />
<ClCompile Include="Model.cpp" />
<ClCompile Include="PagePlcList.cpp" />
<ClCompile Include="PLC.cpp" />
@@ -230,6 +262,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
+ <ClCompile Include="ToolUnits.cpp" />
<ClCompile Include="TopToolbar.cpp" />
<ClCompile Include="VerticalLine.cpp" />
</ItemGroup>
diff --git a/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.filters b/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.filters
index 5344377..d7d8301 100644
--- a/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.filters
+++ b/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.filters
@@ -13,6 +13,9 @@
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
+ <Filter Include="DBManager">
+ <UniqueIdentifier>{c5603403-bc3a-451f-b300-c56d9fe09307}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
@@ -75,6 +78,51 @@
<ClInclude Include="PlcView.h">
<Filter>澶存枃浠�</Filter>
</ClInclude>
+ <ClInclude Include="AlarmPopupDlg.h">
+ <Filter>澶存枃浠�</Filter>
+ </ClInclude>
+ <ClInclude Include="Alarm.h">
+ <Filter>澶存枃浠�</Filter>
+ </ClInclude>
+ <ClInclude Include="Context.h">
+ <Filter>澶存枃浠�</Filter>
+ </ClInclude>
+ <ClInclude Include="Component.h">
+ <Filter>澶存枃浠�</Filter>
+ </ClInclude>
+ <ClInclude Include="Intent.h">
+ <Filter>澶存枃浠�</Filter>
+ </ClInclude>
+ <ClInclude Include="McBool.h">
+ <Filter>澶存枃浠�</Filter>
+ </ClInclude>
+ <ClInclude Include="McInt.h">
+ <Filter>澶存枃浠�</Filter>
+ </ClInclude>
+ <ClInclude Include="McItem.h">
+ <Filter>澶存枃浠�</Filter>
+ </ClInclude>
+ <ClInclude Include="McString.h">
+ <Filter>澶存枃浠�</Filter>
+ </ClInclude>
+ <ClInclude Include="ToolUnits.h">
+ <Filter>澶存枃浠�</Filter>
+ </ClInclude>
+ <ClInclude Include="AlarmMonitor.h">
+ <Filter>澶存枃浠�</Filter>
+ </ClInclude>
+ <ClInclude Include="DBManager\AlarmManager.h">
+ <Filter>DBManager</Filter>
+ </ClInclude>
+ <ClInclude Include="DBManager\AxisManager.h">
+ <Filter>DBManager</Filter>
+ </ClInclude>
+ <ClInclude Include="DBManager\SystemLogManager.h">
+ <Filter>DBManager</Filter>
+ </ClInclude>
+ <ClInclude Include="DBManager\UserManager.h">
+ <Filter>DBManager</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="BoounionPLC.cpp">
@@ -125,6 +173,51 @@
<ClCompile Include="PlcView.cpp">
<Filter>婧愭枃浠�</Filter>
</ClCompile>
+ <ClCompile Include="AlarmPopupDlg.cpp">
+ <Filter>婧愭枃浠�</Filter>
+ </ClCompile>
+ <ClCompile Include="Alarm.cpp">
+ <Filter>婧愭枃浠�</Filter>
+ </ClCompile>
+ <ClCompile Include="Context.cpp">
+ <Filter>婧愭枃浠�</Filter>
+ </ClCompile>
+ <ClCompile Include="Component.cpp">
+ <Filter>婧愭枃浠�</Filter>
+ </ClCompile>
+ <ClCompile Include="Intent.cpp">
+ <Filter>婧愭枃浠�</Filter>
+ </ClCompile>
+ <ClCompile Include="McBool.cpp">
+ <Filter>婧愭枃浠�</Filter>
+ </ClCompile>
+ <ClCompile Include="McInt.cpp">
+ <Filter>婧愭枃浠�</Filter>
+ </ClCompile>
+ <ClCompile Include="McItem.cpp">
+ <Filter>婧愭枃浠�</Filter>
+ </ClCompile>
+ <ClCompile Include="McString.cpp">
+ <Filter>婧愭枃浠�</Filter>
+ </ClCompile>
+ <ClCompile Include="ToolUnits.cpp">
+ <Filter>婧愭枃浠�</Filter>
+ </ClCompile>
+ <ClCompile Include="AlarmMonitor.cpp">
+ <Filter>婧愭枃浠�</Filter>
+ </ClCompile>
+ <ClCompile Include="DBManager\AlarmManager.cpp">
+ <Filter>DBManager</Filter>
+ </ClCompile>
+ <ClCompile Include="DBManager\AxisManager.cpp">
+ <Filter>DBManager</Filter>
+ </ClCompile>
+ <ClCompile Include="DBManager\SystemLogManager.cpp">
+ <Filter>DBManager</Filter>
+ </ClCompile>
+ <ClCompile Include="DBManager\UserManager.cpp">
+ <Filter>DBManager</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="BoounionPLC.rc">
diff --git a/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.cpp b/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.cpp
index dbd2ea0..c7bd004 100644
--- a/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.cpp
+++ b/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.cpp
@@ -8,6 +8,8 @@
#include "afxdialogex.h"
#include "Common.h"
#include "PlcView.h"
+#include "AlarmMonitor.h"
+
#ifdef _DEBUG
#define new DEBUG_NEW
@@ -115,7 +117,16 @@
}
}
}
-
+ else if (code == RX_CODE_ALARM_ON) {
+ AlarmOn();
+ // CAlarmMonitor* pComponent = (CAlarmMonitor*)theApp.m_model.getBonder().GetComponent(ALARM_MONITOR);
+ // m_pTopToolbar->GetBtn(IDC_BUTTON_ALARM)->EnableWindow(pComponent->isAlarming());
+ }
+ else if (code == RX_CODE_ALARM_OFF) {
+ AlarmOff();
+ // CAlarmMonitor* pComponent = (CAlarmMonitor*)theApp.m_model.getBonder().GetComponent(ALARM_MONITOR);
+ // m_pTopToolbar->GetBtn(IDC_BUTTON_ALARM)->EnableWindow(pComponent->isAlarming());
+ }
pAny->release();
}, [&]() -> void {
// onComplete
@@ -163,6 +174,7 @@
// toolbar
m_pTopToolbar = new CTopToolbar();
m_pTopToolbar->Create(IDD_TOP_TOOLBAR, this);
+ m_pTopToolbar->GetBtn(IDC_BUTTON_ALARM)->EnableWindow(FALSE);
m_pTopToolbar->ShowWindow(SW_SHOW);
HMENU hMenu = m_pTopToolbar->GetOperatorMenu();
ASSERT(hMenu);
@@ -554,3 +566,25 @@
m_pActiveView = nullptr;
m_pMainContainer->Resize();
}
+
+void CBoounionPLCDlg::AlarmOn()
+{
+ if (m_pAlarmWnd == nullptr) {
+ m_pAlarmWnd = new CAlarmPopupDlg();
+ //m_pAlarmWnd->SetPLC(theApp.m_model.getBonder().getPLC("PLC(1)"));
+ m_pAlarmWnd->Create(IDD_DIALOG_POPUP_ALARM, this);
+ m_pAlarmWnd->CenterWindow();
+ }
+ m_pAlarmWnd->AlarmOn();
+}
+
+void CBoounionPLCDlg::AlarmOff()
+{
+ if (m_pAlarmWnd == nullptr) {
+ m_pAlarmWnd = new CAlarmPopupDlg();
+ //m_pAlarmWnd->SetPLC(theApp.m_model.getBonder().getPLC("PLC(1)"));
+ m_pAlarmWnd->Create(IDD_DIALOG_POPUP_ALARM, this);
+ m_pAlarmWnd->CenterWindow();
+ }
+ m_pAlarmWnd->AlarmOff();
+}
diff --git a/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.h b/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.h
index 3c2fb64..286767b 100644
--- a/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.h
+++ b/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.h
@@ -7,6 +7,7 @@
#include "PagePlcList.h"
#include "CMainContainer.h"
#include "CBaseView.h"
+#include "AlarmPopupDlg.h"
// CBoounionPLCDlg 对话框
@@ -21,6 +22,8 @@
void Resize();
CBaseView* CreatePlcView(CPLC* pPlc);
void CloseView(CBaseView* pView);
+ void AlarmOn();
+ void AlarmOff();
private:
COLORREF m_crBkgnd;
@@ -30,6 +33,7 @@
CPagePlcList* m_pPagePlcList;
CMainContainer* m_pMainContainer;
CBaseView* m_pActiveView;
+ CAlarmPopupDlg* m_pAlarmWnd;
// 对话框数据
diff --git a/SourceCode/Bond/BoounionPLC/Common.h b/SourceCode/Bond/BoounionPLC/Common.h
index ee7db10..6f11ade 100644
--- a/SourceCode/Bond/BoounionPLC/Common.h
+++ b/SourceCode/Bond/BoounionPLC/Common.h
@@ -7,6 +7,9 @@
#define RX_CODE_ADD_PLC 1001
#define RX_CODE_REMOVE_PLC 1002
#define RX_CODE_SELECT_PLC 1003
+#define RX_CODE_ALARM_ON 1004
+#define RX_CODE_ALARM_OFF 1005
+#define RX_CODE_BONDER_BEEP 1006
/* 定制颜色 */
@@ -17,6 +20,34 @@
#define BASE_VIEW_BACKGROUND RGB(252, 252, 255)
#define PLC_VIEW_BACKGROUND RGB(252, 252, 255)
+/* 解除警告 按钮 */
+#define BTN_ALARM_OFF_FRAME_NORMAL RGB(88, 88, 88)
+#define BTN_ALARM_OFF_FRAME_HOVER RGB(88, 88, 88)
+#define BTN_ALARM_OFF_FRAME_PRESS RGB(88, 88, 88)
+#define BTN_ALARM_OFF_BKGND_NORMAL RGB(255, 127, 39)
+#define BTN_ALARM_OFF_BKGND_HOVER RGB(255, 157, 59)
+#define BTN_ALARM_OFF_BKGND_PRESS RGB(255, 100, 29)
+
+/* 静音按钮 */
+#define BTN_SOUND_OFF_FRAME_NORMAL RGB(88, 88, 88)
+#define BTN_SOUND_OFF_FRAME_HOVER RGB(88, 88, 88)
+#define BTN_SOUND_OFF_FRAME_PRESS RGB(88, 88, 88)
+#define BTN_SOUND_OFF_BKGND_NORMAL RGB(255, 127, 39)
+#define BTN_SOUND_OFF_BKGND_HOVER RGB(255, 157, 59)
+#define BTN_SOUND_OFF_BKGND_PRESS RGB(255, 100, 29)
+#define BTN_SOUND_ON_BKGND_NORMAL RGB(100, 200, 100)
+#define BTN_SOUND_ON_BKGND_HOVER RGB(150, 250, 150)
+#define BTN_SOUND_ON_BKGND_PRESS RGB(50, 150, 50)
+
/* 按钮id */
-#define VIEW_TOOL_BTN_CLOSE 0x1016
\ No newline at end of file
+#define VIEW_TOOL_BTN_CLOSE 0x1016
+
+
+/* 广播代码 */
+#define BC_CODE_ALARM_ON 1
+#define BC_CODE_ALARM_OFF 2
+
+
+/* 监控数据id */
+#define MONITOR_ID_ALARM 1001
\ No newline at end of file
diff --git a/SourceCode/Bond/BoounionPLC/Component.cpp b/SourceCode/Bond/BoounionPLC/Component.cpp
new file mode 100644
index 0000000..ee14c03
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/Component.cpp
@@ -0,0 +1,126 @@
+#include "stdafx.h"
+#include "Common.h"
+#include "Component.h"
+#include "Log.h"
+#include "BoounionPLC.h"
+
+CComponent::CComponent()
+{
+ m_pChannel1 = NULL;
+ m_nIndex = 0;
+ m_bRunning = FALSE;
+ m_pPlc = nullptr;
+ InitializeCriticalSection(&m_criticalSection);
+}
+
+CComponent::~CComponent()
+{
+ DeleteCriticalSection(&m_criticalSection);
+}
+
+void CComponent::setPlc(CPLC* pPlc)
+{
+ m_pPlc = pPlc;
+}
+
+void CComponent::init()
+{
+
+}
+
+void CComponent::term()
+{
+
+}
+
+int CComponent::run()
+{
+ m_bRunning = TRUE;
+ return 0;
+}
+
+int CComponent::stop()
+{
+ m_bRunning = FALSE;
+ return 0;
+}
+
+void CComponent::setName(const char* pszName)
+{
+ m_strName = pszName;
+}
+
+std::string& CComponent::getName()
+{
+ return m_strName;
+}
+
+void CComponent::setDescription(const char* pszDescription)
+{
+ m_strDescription = pszDescription;
+}
+
+std::string& CComponent::getDescription()
+{
+ return m_strDescription;
+}
+
+void CComponent::setIndex(int index)
+{
+ m_nIndex = index;
+}
+
+int CComponent::getIndex()
+{
+ return m_nIndex;
+}
+
+void CComponent::onRecvBroadcast(void* pSender, CIntent* pIntent)
+{
+
+}
+
+void CComponent::onData(int id, const void* pData, int size)
+{
+
+}
+
+void CComponent::SendBroadcast(CIntent* pIntent)
+{
+ m_pPlc->sendBroadcast(this, pIntent);
+}
+
+int CComponent::WriteInt(int unitId, int addr, int value)
+{
+ return 0;// m_pBonder->writeInt(unitId, addr, value);
+}
+
+int CComponent::WriteData(MC::SOFT_COMPONENT softComponent, unsigned int addr,
+ const char* pszData, unsigned int length, ONWRITE funOnWrite)
+{
+ return 0;// m_pBonder->writeData(softComponent, addr, pszData, length, funOnWrite);
+}
+
+void CComponent::OnTimer(UINT nTimerid)
+{
+
+}
+
+void CComponent::Serialize(CArchive& ar)
+{
+
+}
+
+float CComponent::toFloat(const char* pszAddr)
+{
+ BYTE szBuffer[4];
+ szBuffer[0] = pszAddr[0];
+ szBuffer[1] = pszAddr[1];
+ szBuffer[2] = pszAddr[2];
+ szBuffer[3] = pszAddr[3];
+ float f = 0.0;
+ memcpy(&f, szBuffer, 4);
+
+ return f;
+}
+
diff --git a/SourceCode/Bond/BoounionPLC/Component.h b/SourceCode/Bond/BoounionPLC/Component.h
new file mode 100644
index 0000000..a29c397
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/Component.h
@@ -0,0 +1,59 @@
+#pragma once
+#include <functional>
+#include <string>
+#include "Context.h"
+#include "Intent.h"
+#include "McBool.h"
+#include "McString.h"
+#include "McInt.h"
+
+
+class CPLC;
+class CComponent
+{
+public:
+ CComponent();
+ virtual ~CComponent();
+
+
+public:
+ virtual std::string& getClassName() = 0;
+ void setPlc(CPLC* pPlc);
+ void setName(const char* pszName);
+ std::string& getName();
+ void setDescription(const char* pszDescription);
+ std::string& getDescription();
+ void setIndex(int index);
+ int getIndex();
+ virtual void onRecvBroadcast(void* pSender, CIntent* pIntent);
+ virtual void onData(int id, const void* pData, int size);
+ virtual void init();
+ virtual void term();
+ virtual int run();
+ virtual int stop();
+ virtual void OnTimer(UINT nTimerid);
+ virtual void Serialize(CArchive& ar);
+ static float toFloat(const char* pszAddr);
+ int WriteInt(int unitId, int addr, int value);
+ int WriteData(MC::SOFT_COMPONENT softComponent, unsigned int addr,
+ const char* pszData, unsigned int length, ONWRITE funOnWrite);
+
+public:
+ inline void Lock() { EnterCriticalSection(&m_criticalSection); }
+ inline void Unlock() { LeaveCriticalSection(&m_criticalSection); }
+
+protected:
+ void SendBroadcast(CIntent* pIntent);
+
+protected:
+ CPLC* m_pPlc;
+ IMcChannel* m_pChannel1;
+ int m_nIndex;
+ std::string m_strName;
+ std::string m_strDescription;
+ CRITICAL_SECTION m_criticalSection;
+
+protected:
+ BOOL m_bRunning;
+};
+
diff --git a/SourceCode/Bond/BoounionPLC/Context.cpp b/SourceCode/Bond/BoounionPLC/Context.cpp
new file mode 100644
index 0000000..693da12
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/Context.cpp
@@ -0,0 +1,157 @@
+#include "stdafx.h"
+#include "Context.h"
+
+
+CContext::CContext()
+{
+ m_nRef = 0;
+ m_nRetCode = 0;
+ m_hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+ InitializeCriticalSection(&m_criticalSection);
+}
+
+
+CContext::~CContext()
+{
+ if (m_hEvent != NULL) {
+ CloseHandle(m_hEvent);
+ m_hEvent = NULL;
+ }
+ DeleteCriticalSection(&m_criticalSection);
+}
+
+int CContext::addRef()
+{
+ Lock();
+ m_nRef++;
+ Unlock();
+
+ return m_nRef;
+}
+
+int CContext::release()
+{
+ Lock();
+ m_nRef--;
+ BOOL bDelete = m_nRef == 0;
+ Unlock();
+
+ int nRef = m_nRef;;
+ if (bDelete) delete this;
+ return nRef;
+}
+
+void CContext::setRetCode(int code)
+{
+ m_nRetCode = code;
+}
+
+int CContext::getRetCode()
+{
+ return m_nRetCode;
+}
+
+void CContext::setRetMsg(const char* pszMsg)
+{
+ m_strRetMsg = pszMsg;
+}
+
+std::string& CContext::getRetMsg()
+{
+ return m_strRetMsg;
+}
+
+HANDLE CContext::getEventHandle()
+{
+ return m_hEvent;
+}
+
+void CContext::setEvent()
+{
+ if (m_hEvent != NULL) {
+ SetEvent(m_hEvent);
+ }
+}
+
+void CContext::resetEvent()
+{
+ if (m_hEvent != NULL) {
+ ResetEvent(m_hEvent);
+ }
+}
+
+void CContext::ReadString(CArchive& ar, std::string& string)
+{
+ CString strTemp;
+ ar >> strTemp;
+ string = (LPTSTR)(LPCTSTR)strTemp;
+}
+
+void CContext::WriteString(CArchive& ar, std::string& string)
+{
+ CString strTemp = string.c_str();
+ ar << strTemp;
+}
+
+void CContext::createDir(CString strDir)
+{
+ int lastIndex = 0;
+ int index = strDir.Find(_T("\\"), lastIndex);
+ while (index > 0) {
+ CString strTempDir = strDir.Left(index);
+ CreateDirectory(strTempDir, NULL);
+
+ lastIndex = index + 1;
+ index = strDir.Find(_T("\\"), lastIndex);
+ }
+ CreateDirectory(strDir, NULL);
+}
+
+BOOL CContext::IsBoxId(CString& strId)
+{
+ //'W20'开头,倒数第五位为'Z'的字符串
+ if (strId.GetLength() < 8) {
+ return FALSE;
+ }
+
+ if (strId.Left(3).Compare(_T("W20")) != 0) {
+ return FALSE;
+ }
+
+ if (strId.Right(5).GetAt(0) != (char)'Z') {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL CContext::IsLotId(CString& strId)
+{
+ //'N20'开头,倒数第五位为'Z'的字符串
+ if (strId.GetLength() < 8) {
+ return FALSE;
+ }
+
+ if (strId.Left(3).Compare(_T("N20")) != 0) {
+ return FALSE;
+ }
+
+ if (strId.Right(5).GetAt(0) != (char)'Z') {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+float CContext::toFloat(const char* pszAddr)
+{
+ BYTE szBuffer[4];
+ szBuffer[0] = pszAddr[0];
+ szBuffer[1] = pszAddr[1];
+ szBuffer[2] = pszAddr[2];
+ szBuffer[3] = pszAddr[3];
+ float f = 0.0;
+ memcpy(&f, szBuffer, 4);
+
+ return f;
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/BoounionPLC/Context.h b/SourceCode/Bond/BoounionPLC/Context.h
new file mode 100644
index 0000000..cfad188
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/Context.h
@@ -0,0 +1,44 @@
+#pragma once
+#include "Common.h"
+
+class CContext : public IRxObject
+{
+public:
+ CContext();
+ virtual ~CContext();
+
+public:
+ int addRef();
+ int release();
+
+public:
+ virtual std::string& getClassName() = 0;
+ virtual std::string toString() = 0;
+ void setRetCode(int code);
+ int getRetCode();
+ void setRetMsg(const char* pszMsg);
+ std::string& getRetMsg();
+ HANDLE getEventHandle();
+ void setEvent();
+ void resetEvent();
+ static void createDir(CString strDir);
+ float toFloat(const char* pszAddr);
+
+protected:
+ inline void Lock() { EnterCriticalSection(&m_criticalSection); }
+ inline void Unlock() { LeaveCriticalSection(&m_criticalSection); }
+ void ReadString(CArchive& ar, std::string& string);
+ void WriteString(CArchive& ar, std::string& string);
+ static BOOL IsBoxId(CString& strId);
+ static BOOL IsLotId(CString& strId);
+
+private:
+ int m_nRef;
+ CRITICAL_SECTION m_criticalSection;
+
+protected:
+ int m_nRetCode;
+ std::string m_strRetMsg;
+ HANDLE m_hEvent;
+};
+
diff --git a/SourceCode/Bond/BoounionPLC/DBManager/AlarmManager.cpp b/SourceCode/Bond/BoounionPLC/DBManager/AlarmManager.cpp
new file mode 100644
index 0000000..d71f01a
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/DBManager/AlarmManager.cpp
@@ -0,0 +1,235 @@
+#include "stdafx.h"
+#include <sstream>
+#include <iostream>
+#include <stdexcept>
+#include <ctime>
+#include <mutex>
+#include "AlarmManager.h"
+
+
+// 静态成员初始化
+std::mutex AlarmManager::m_mutex;
+
+// 获取单例实例
+AlarmManager& AlarmManager::getInstance() {
+ static AlarmManager instance;
+ return instance;
+}
+
+// 构造函数
+AlarmManager::AlarmManager() : m_pDB(nullptr) {}
+
+// 析构函数
+AlarmManager::~AlarmManager() {
+ m_pDB = nullptr;
+}
+
+// 设置数据库连接
+void AlarmManager::setDatabase(BL::Database* db) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_pDB = db;
+}
+
+// 初始化报警表
+bool AlarmManager::initializeAlarmTable() {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ const std::string createTableQuery = R"(
+ CREATE TABLE IF NOT EXISTS alarms (
+ id TEXT NOT NULL,
+ description TEXT NOT NULL,
+ start_time DATETIME NOT NULL,
+ end_time DATETIME NOT NULL
+ )
+ )";
+
+ return m_pDB->executeQuery(createTableQuery);
+}
+
+// 添加报警
+bool AlarmManager::addAlarm(const std::string& id, const std::string& description, const std::string& startTime, const std::string& endTime) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "INSERT INTO alarms (id, description, start_time, end_time) VALUES ("
+ << "'" << id << "', "
+ << "'" << description << "', "
+ << "'" << startTime << "', "
+ << "'" << endTime << "')";
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_pDB->executeQuery(query.str());
+}
+
+// 查询所有报警数据
+std::vector<std::vector<std::string>> AlarmManager::getAllAlarms() {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ const std::string query = "SELECT id, description, start_time, end_time FROM alarms";
+ return m_pDB->fetchResults(query);
+}
+
+// 根据报警ID查询报警
+std::vector<std::vector<std::string>> AlarmManager::getAlarmsById(const std::string& id) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "SELECT id, description, start_time, end_time FROM alarms WHERE id = '" << id << "'";
+ return m_pDB->fetchResults(query.str());
+}
+
+// 根据描述查询报警
+std::vector<std::vector<std::string>> AlarmManager::getAlarmsByDescription(const std::string& description) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "SELECT id, description, start_time, end_time FROM alarms WHERE description LIKE '%" << description << "%'";
+ return m_pDB->fetchResults(query.str());
+}
+
+// 根据时间范围查询报警
+std::vector<std::vector<std::string>> AlarmManager::getAlarmsByTimeRange(
+ const std::string& startTime, const std::string& endTime) {
+
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "SELECT id, description, start_time, end_time FROM alarms WHERE 1=1";
+
+ if (!startTime.empty()) {
+ query << " AND start_time >= '" << startTime << "'";
+ }
+ if (!endTime.empty()) {
+ query << " AND end_time <= '" << endTime << "'";
+ }
+
+ return m_pDB->fetchResults(query.str());
+}
+
+// 根据ID、开始时间和结束时间查询报警
+std::vector<std::vector<std::string>> AlarmManager::getAlarmsByIdAndTimeRange(
+ const std::string& id, const std::string& startTime, const std::string& endTime) {
+
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "SELECT id, description, start_time, end_time FROM alarms WHERE id = '" << id << "'";
+
+ if (!startTime.empty()) {
+ query << " AND start_time >= '" << startTime << "'";
+ }
+ if (!endTime.empty()) {
+ query << " AND end_time <= '" << endTime << "'";
+ }
+
+ return m_pDB->fetchResults(query.str());
+}
+
+// 分页查询报警数据
+std::vector<std::vector<std::string>> AlarmManager::getAlarms(int startPosition, int count) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "SELECT id, description, start_time, end_time FROM alarms LIMIT " << count << " OFFSET " << startPosition;
+ return m_pDB->fetchResults(query.str());
+}
+
+// 筛选报警数据
+std::vector<std::vector<std::string>> AlarmManager::getFilteredAlarms(
+ const std::string& description,
+ const std::string& startTime,
+ const std::string& endTime,
+ int pageNumber,
+ int pageSize) {
+
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "SELECT id, description, start_time, end_time FROM alarms WHERE 1=1";
+
+ if (!description.empty()) {
+ query << " AND description LIKE '%" << description << "%'";
+ }
+ if (!startTime.empty()) {
+ query << " AND start_time >= '" << startTime << "'";
+ }
+ if (!endTime.empty()) {
+ query << " AND end_time <= '" << endTime << "'";
+ }
+
+ int offset = (pageNumber - 1) * pageSize;
+ query << " ORDER BY start_time DESC LIMIT " << pageSize << " OFFSET " << offset;
+
+ return m_pDB->fetchResults(query.str());
+}
+
+// 获取符合条件的报警总数
+int AlarmManager::getTotalAlarmCount(
+ const std::string& description,
+ const std::string& startTime,
+ const std::string& endTime) {
+
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "SELECT COUNT(*) FROM alarms WHERE 1=1";
+
+ if (!description.empty()) {
+ query << " AND description LIKE '%" << description << "%'";
+ }
+ if (!startTime.empty()) {
+ query << " AND start_time >= '" << startTime << "'";
+ }
+ if (!endTime.empty()) {
+ query << " AND end_time <= '" << endTime << "'";
+ }
+
+ auto results = m_pDB->fetchResults(query.str());
+ return (!results.empty() && !results[0].empty()) ? std::stoi(results[0][0]) : 0;
+}
+
+// 更新报警的结束时间
+bool AlarmManager::updateAlarmEndTime(const std::string& id, const std::string& description, const std::string& startTime, const std::string& newEndTime) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "UPDATE alarms SET end_time = '" << newEndTime << "'"
+ << " WHERE id = '" << id << "'"
+ << " AND description = '" << description << "'"
+ << " AND start_time = '" << startTime << "'";
+
+ return m_pDB->executeQuery(query.str());
+}
+
+// 清理旧报警数据
+void AlarmManager::cleanOldAlarms(int daysToKeep) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "DELETE FROM alarms WHERE end_time < datetime('now', '-" << daysToKeep << " days')";
+ m_pDB->executeQuery(query.str());
+}
diff --git a/SourceCode/Bond/BoounionPLC/DBManager/AlarmManager.h b/SourceCode/Bond/BoounionPLC/DBManager/AlarmManager.h
new file mode 100644
index 0000000..bbe3e3a
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/DBManager/AlarmManager.h
@@ -0,0 +1,142 @@
+#ifndef ALARM_MANAGER_H
+#define ALARM_MANAGER_H
+
+#include <string>
+#include <vector>
+#include <mutex>
+#include "Database.h"
+
+class AlarmManager {
+public:
+ /**
+ * 获取单例实例
+ * @return AlarmManager实例的引用
+ */
+ static AlarmManager& getInstance();
+
+ /**
+ * 设置数据库连接
+ * @param db 数据库连接的指针
+ */
+ void setDatabase(BL::Database* db);
+
+ /**
+ * 初始化报警表
+ * @return 成功返回true,失败返回false
+ */
+ bool initializeAlarmTable();
+
+ /**
+ * 添加报警
+ * @param id 报警ID
+ * @param description 报警描述
+ * @param startTime 报警开始时间
+ * @param endTime 报警结束时间
+ * @return 成功返回true,失败返回false
+ */
+ bool addAlarm(const std::string& id, const std::string& description, const std::string& startTime, const std::string& endTime);
+
+ /**
+ * 查询所有报警数据
+ * @return 包含所有报警数据的二维字符串向量
+ */
+ std::vector<std::vector<std::string>> getAllAlarms();
+
+ /**
+ * 根据报警ID查询报警
+ * @param id 报警ID
+ * @return 包含筛选后报警数据的二维字符串向量
+ */
+ std::vector<std::vector<std::string>> getAlarmsById(const std::string& id);
+
+ /**
+ * 根据描述查询报警
+ * @param description 报警描述的筛选条件
+ * @return 包含筛选后报警数据的二维字符串向量
+ */
+ std::vector<std::vector<std::string>> getAlarmsByDescription(const std::string& description);
+
+ /**
+ * 根据时间范围查询报警
+ * @param startTime 起始时间
+ * @param endTime 结束时间
+ * @return 包含查询结果的二维字符串向量
+ */
+ std::vector<std::vector<std::string>> getAlarmsByTimeRange(
+ const std::string& startTime, const std::string& endTime);
+
+ /**
+ * 根据ID和时间范围查询报警
+ * @param id 报警ID
+ * @param startTime 起始时间
+ * @param endTime 结束时间
+ * @return 包含查询结果的二维字符串向量
+ */
+ std::vector<std::vector<std::string>> getAlarmsByIdAndTimeRange(
+ const std::string& id, const std::string& startTime, const std::string& endTime);
+
+ /**
+ * 获取报警数据
+ * @param startPosition 起始位置
+ * @param count 获取的记录数量
+ * @return 包含报警数据的二维字符串向量
+ */
+ std::vector<std::vector<std::string>> getAlarms(int startPosition, int count);
+
+ /**
+ * 获取筛选后的报警数据
+ * @param description 报警描述的筛选条件
+ * @param startTime 起始时间筛选条件
+ * @param endTime 结束时间筛选条件
+ * @param pageNumber 页码
+ * @param pageSize 每页的记录数
+ * @return 包含筛选后报警数据的二维字符串向量
+ */
+ std::vector<std::vector<std::string>> getFilteredAlarms(
+ const std::string& description,
+ const std::string& startTime,
+ const std::string& endTime,
+ int pageNumber,
+ int pageSize);
+
+ /**
+ * 获取符合条件的报警总数
+ * @param description 报警描述的筛选条件
+ * @param startTime 起始时间筛选条件
+ * @param endTime 结束时间筛选条件
+ * @return 符合条件的报警总数
+ */
+ int getTotalAlarmCount(
+ const std::string& description,
+ const std::string& startTime,
+ const std::string& endTime);
+
+ /**
+ * 更新报警结束时间
+ * @param id 报警ID
+ * @param description 报警描述
+ * @param startTime 报警开始时间
+ * @param newEndTime 新的报警结束时间
+ * @return 成功返回true,失败返回false
+ */
+ bool updateAlarmEndTime(const std::string& id, const std::string& description, const std::string& startTime, const std::string& newEndTime);
+
+ /**
+ * 清理旧报警
+ * @param daysToKeep 保留的天数
+ */
+ void cleanOldAlarms(int daysToKeep = 30);
+
+private:
+ AlarmManager();
+ ~AlarmManager();
+
+ // 禁止拷贝和赋值
+ AlarmManager(const AlarmManager&) = delete;
+ AlarmManager& operator=(const AlarmManager&) = delete;
+
+ BL::Database* m_pDB;
+ static std::mutex m_mutex;
+};
+
+#endif // ALARM_MANAGER_H
\ No newline at end of file
diff --git a/SourceCode/Bond/BoounionPLC/DBManager/AxisManager.cpp b/SourceCode/Bond/BoounionPLC/DBManager/AxisManager.cpp
new file mode 100644
index 0000000..e3e1ae5
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/DBManager/AxisManager.cpp
@@ -0,0 +1,246 @@
+#include "stdafx.h"
+#include "AxisManager.h"
+#include <sstream>
+#include <stdexcept>
+#include <mutex>
+
+// 静态成员初始化
+std::mutex AxisManager::m_mutex;
+
+// 获取单例实例
+AxisManager& AxisManager::getInstance() {
+ static AxisManager instance;
+ return instance;
+}
+
+AxisManager::AxisManager() : m_pDB(nullptr) {}
+
+AxisManager::~AxisManager() {
+ m_pDB = nullptr;
+}
+
+// 设置数据库连接
+void AxisManager::setDatabase(BL::Database* db) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_pDB = db;
+}
+
+// 初始化轴表和定位点表
+bool AxisManager::initializeTables() {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ const std::string createAxesTableQuery = R"(
+ CREATE TABLE IF NOT EXISTS axes (
+ axis_id INTEGER PRIMARY KEY,
+ axis_no TEXT NOT NULL,
+ description TEXT NOT NULL,
+ start_address TEXT,
+ jog_distance REAL,
+ manual_speed REAL,
+ max_manual_speed REAL,
+ min_manual_speed REAL,
+ auto_speed REAL,
+ max_auto_speed REAL,
+ min_auto_speed REAL,
+ acceleration_time REAL,
+ deceleration_time REAL
+ )
+ )";
+
+ const std::string createPositionsTableQuery = R"(
+ CREATE TABLE IF NOT EXISTS positions (
+ position_id INTEGER PRIMARY KEY AUTOINCREMENT,
+ axis_id INTEGER NOT NULL,
+ description TEXT,
+ position_value REAL,
+ plc_address TEXT,
+ FOREIGN KEY (axis_id) REFERENCES axes(axis_id)
+ )
+ )";
+
+ return m_pDB->executeQuery(createAxesTableQuery) && m_pDB->executeQuery(createPositionsTableQuery);
+}
+
+// 初始化默认数据
+bool AxisManager::initializeDefaultData() {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ for (int axisId = 1; axisId <= 12; ++axisId) {
+ std::ostringstream axisQuery;
+ axisQuery << "INSERT OR IGNORE INTO axes (axis_id, axis_no, description, start_address, jog_distance, manual_speed, "
+ << "max_manual_speed, min_manual_speed, auto_speed, max_auto_speed, min_auto_speed, acceleration_time, deceleration_time) "
+ << "VALUES (" << axisId << ", 'M" << axisId * 10 << "', '轴 " << axisId << "', 'D" << (5090 + axisId * 2) << "', "
+ << "0.5, 10.0, 20.0, 5.0, 15.0, 25.0, 10.0, 0.2, 0.3)";
+ m_pDB->executeQuery(axisQuery.str());
+ }
+
+ for (int axisId = 1; axisId <= 12; ++axisId) {
+ for (int positionIndex = 1; positionIndex <= 25; ++positionIndex) {
+ std::ostringstream positionQuery;
+ positionQuery << "INSERT OR IGNORE INTO positions (axis_id, description, position_value, plc_address) "
+ << "VALUES (" << axisId << ", '定位点 " << positionIndex << "', " << (positionIndex * 10.0) << ", "
+ << "'D" << (5240 + positionIndex * 2) << "')";
+ m_pDB->executeQuery(positionQuery.str());
+ }
+ }
+
+ return true;
+}
+
+// 添加或更新轴信息
+bool AxisManager::saveAxis(int axisId, const std::string& axisNo, const std::string& description,
+ const std::string& startAddress, double jogDistance, double manualSpeed,
+ double maxManualSpeed, double minManualSpeed, double autoSpeed,
+ double maxAutoSpeed, double minAutoSpeed, double accelerationTime,
+ double decelerationTime) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "INSERT INTO axes (axis_id, axis_no, description, start_address, jog_distance, manual_speed, "
+ << "max_manual_speed, min_manual_speed, auto_speed, max_auto_speed, min_auto_speed, acceleration_time, deceleration_time) "
+ << "VALUES (" << axisId << ", '" << axisNo << "', '" << description << "', '" << startAddress << "', "
+ << jogDistance << ", " << manualSpeed << ", " << maxManualSpeed << ", " << minManualSpeed << ", " << autoSpeed
+ << ", " << maxAutoSpeed << ", " << minAutoSpeed << ", " << accelerationTime << ", " << decelerationTime << ") "
+ << "ON CONFLICT(axis_id) DO UPDATE SET "
+ << "axis_no=excluded.axis_no, description=excluded.description, start_address=excluded.start_address, "
+ << "jog_distance=excluded.jog_distance, manual_speed=excluded.manual_speed, max_manual_speed=excluded.max_manual_speed, "
+ << "min_manual_speed=excluded.min_manual_speed, auto_speed=excluded.auto_speed, max_auto_speed=excluded.max_auto_speed, "
+ << "min_auto_speed=excluded.min_auto_speed, acceleration_time=excluded.acceleration_time, deceleration_time=excluded.deceleration_time";
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_pDB->executeQuery(query.str());
+}
+
+// 获取单个轴信息
+std::vector<std::string> AxisManager::getAxis(int axisId) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "SELECT * FROM axes WHERE axis_id = " << axisId;
+
+ auto result = m_pDB->fetchResults(query.str());
+ return !result.empty() ? result[0] : std::vector<std::string>();
+}
+
+// 获取所有轴信息
+std::vector<std::vector<std::string>> AxisManager::getAllAxes() {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ return m_pDB->fetchResults("SELECT * FROM axes ORDER BY axis_id");
+}
+
+// 删除指定轴
+bool AxisManager::deleteAxis(int axisId) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "DELETE FROM axes WHERE axis_id = " << axisId;
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_pDB->executeQuery(query.str());
+}
+
+// 添加或更新定位点
+bool AxisManager::savePosition(int axisId, const std::string& description, double positionValue, const std::string& plcAddress) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "INSERT INTO positions (axis_id, description, position_value, plc_address) VALUES ("
+ << axisId << ", '" << description << "', " << positionValue << ", '" << plcAddress << "') "
+ << "ON CONFLICT(axis_id) DO UPDATE SET "
+ << "description=excluded.description, position_value=excluded.position_value, plc_address=excluded.plc_address";
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_pDB->executeQuery(query.str());
+}
+
+// 获取轴的所有定位点
+std::vector<std::vector<std::string>> AxisManager::getPositions(int axisId, int pageNumber, int pageSize) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ int offset = (pageNumber - 1) * pageSize;
+ std::ostringstream query;
+ query << "SELECT * FROM positions WHERE axis_id = " << axisId << " LIMIT " << pageSize << " OFFSET " << offset;
+
+ return m_pDB->fetchResults(query.str());
+}
+
+// 获取定位点总数
+int AxisManager::getTotalPositionCount(int axisId) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "SELECT COUNT(*) FROM positions WHERE axis_id = " << axisId;
+
+ auto result = m_pDB->fetchResults(query.str());
+ return (!result.empty() && !result[0].empty()) ? std::stoi(result[0][0]) : 0;
+}
+
+// 删除指定定位点
+bool AxisManager::deletePosition(int positionId) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "DELETE FROM positions WHERE position_id = " << positionId;
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_pDB->executeQuery(query.str());
+}
+
+// 获取所有的轴ID
+std::vector<int> AxisManager::getUsedAxisIds() {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::vector<int> usedAxisIds;
+ std::string query = "SELECT axis_id FROM axes ORDER BY axis_id";
+ auto results = m_pDB->fetchResults(query);
+
+ for (const auto& row : results) {
+ if (!row.empty()) {
+ usedAxisIds.push_back(std::stoi(row[0]));
+ }
+ }
+
+ return usedAxisIds;
+}
+
+// 获取所有轴的轴NO
+std::vector<std::string> AxisManager::getAllAxisNumbers() {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::vector<std::string> axisNumbers;
+ std::string query = "SELECT axis_no FROM axes ORDER BY axis_id";
+ auto results = m_pDB->fetchResults(query);
+
+ for (const auto& row : results) {
+ if (!row.empty()) {
+ axisNumbers.push_back(row[0]);
+ }
+ }
+
+ return axisNumbers;
+}
diff --git a/SourceCode/Bond/BoounionPLC/DBManager/AxisManager.h b/SourceCode/Bond/BoounionPLC/DBManager/AxisManager.h
new file mode 100644
index 0000000..b0d65ca
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/DBManager/AxisManager.h
@@ -0,0 +1,75 @@
+#ifndef AXIS_MANAGER_H
+#define AXIS_MANAGER_H
+
+#include <string>
+#include <vector>
+#include <mutex>
+#include "Database.h"
+
+// 轴管理类
+class AxisManager {
+public:
+ // 获取单例实例
+ static AxisManager& getInstance();
+
+ // 设置数据库连接
+ void setDatabase(BL::Database* db);
+
+ // 初始化轴表和定位点表
+ bool initializeTables();
+
+ // 初始化默认数据
+ bool initializeDefaultData();
+
+ // 添加或更新轴信息
+ bool saveAxis(int axisId, const std::string& axisNo, const std::string& description,
+ const std::string& startAddress, double jogDistance, double manualSpeed,
+ double maxManualSpeed, double minManualSpeed, double autoSpeed,
+ double maxAutoSpeed, double minAutoSpeed, double accelerationTime,
+ double decelerationTime);
+
+ // 获取单个轴信息
+ std::vector<std::string> getAxis(int axisId);
+
+ // 获取所有轴信息
+ std::vector<std::vector<std::string>> getAllAxes();
+
+ // 删除指定轴
+ bool deleteAxis(int axisId);
+
+ // 添加或更新定位点
+ bool savePosition(int axisId, const std::string& description, double positionValue,
+ const std::string& plcAddress);
+
+ // 获取轴的所有定位点
+ std::vector<std::vector<std::string>> getPositions(int axisId, int pageNumber, int pageSize);
+
+ // 获取定位点总数
+ int getTotalPositionCount(int axisId);
+
+ // 删除指定定位点
+ bool deletePosition(int positionId);
+
+ // 获取所有的轴ID
+ std::vector<int> getUsedAxisIds();
+
+ // 获取所有轴的轴NO
+ std::vector<std::string> getAllAxisNumbers();
+
+private:
+ // 私有构造函数和析构函数
+ AxisManager();
+ ~AxisManager();
+
+ // 禁止拷贝和赋值
+ AxisManager(const AxisManager&) = delete;
+ AxisManager& operator=(const AxisManager&) = delete;
+
+ // 数据库连接
+ BL::Database* m_pDB;
+
+ // 线程安全锁
+ static std::mutex m_mutex;
+};
+
+#endif // AXIS_MANAGER_H
\ No newline at end of file
diff --git a/SourceCode/Bond/BoounionPLC/DBManager/SystemLogManager.cpp b/SourceCode/Bond/BoounionPLC/DBManager/SystemLogManager.cpp
new file mode 100644
index 0000000..d225167
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/DBManager/SystemLogManager.cpp
@@ -0,0 +1,208 @@
+#include "stdafx.h"
+#include "SystemLogManager.h"
+#include "UserManager.h"
+#include <sstream>
+#include <iostream>
+#include <stdexcept>
+#include <ctime>
+#include <mutex>
+
+// 静态成员初始化
+std::mutex SystemLogManager::m_mutex;
+
+// 获取单例实例
+SystemLogManager& SystemLogManager::getInstance() {
+ static SystemLogManager instance;
+ return instance;
+}
+
+// 构造函数
+SystemLogManager::SystemLogManager() : m_pDB(nullptr) {}
+
+// 析构函数
+SystemLogManager::~SystemLogManager() {
+ m_pDB = nullptr; // 清除指针引用
+}
+
+// 设置数据库连接
+void SystemLogManager::setDatabase(BL::Database* db) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_pDB = db;
+}
+
+// 初始化日志表
+bool SystemLogManager::initializeLogTable() {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ const std::string createTableQuery = R"(
+ CREATE TABLE IF NOT EXISTS system_logs (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ log_type TEXT NOT NULL,
+ event TEXT NOT NULL,
+ username TEXT NOT NULL,
+ timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
+ )
+ )";
+
+ return m_pDB->executeQuery(createTableQuery);
+}
+
+// 添加日志(使用当前用户)
+bool SystemLogManager::log(LogType logType, const std::string& event) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ cleanOldLogs();
+
+ std::string username = UserManager::getInstance().getCurrentUser();
+ if (username.empty()) {
+ username = "SYSTEM";
+ }
+
+ std::ostringstream query;
+ query << "INSERT INTO system_logs (log_type, event, username) VALUES ("
+ << "'" << logTypeToString(logType) << "', "
+ << "'" << event << "', "
+ << "'" << username << "')";
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_pDB->executeQuery(query.str());
+}
+
+// 添加日志(指定用户)
+bool SystemLogManager::log(LogType logType, const std::string& event, const std::string& username) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ cleanOldLogs();
+
+ std::ostringstream query;
+ query << "INSERT INTO system_logs (log_type, event, username) VALUES ("
+ << "'" << logTypeToString(logType) << "', "
+ << "'" << event << "', "
+ << "'" << username << "')";
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_pDB->executeQuery(query.str());
+}
+
+// 获取日志内容
+std::vector<std::vector<std::string>> SystemLogManager::getLogs(int startPosition, int count) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ if (startPosition == -1 && count == -1) {
+ query << "SELECT id, log_type, event, username, datetime(timestamp, 'localtime') FROM system_logs";
+ }
+ else {
+ query << "SELECT id, log_type, event, username, datetime(timestamp, 'localtime') FROM system_logs "
+ << "LIMIT " << count << " OFFSET " << startPosition;
+ }
+
+ return m_pDB->fetchResults(query.str());
+}
+
+// 获取筛选后的日志数据
+std::vector<std::vector<std::string>> SystemLogManager::getFilteredLogs(
+ const std::string& logType,
+ const std::string& username,
+ const std::string& description,
+ const std::string& startTime,
+ const std::string& endTime,
+ int pageNumber,
+ int pageSize)
+{
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "SELECT id, log_type, event, username, datetime(timestamp, 'localtime') FROM system_logs WHERE 1=1";
+
+ if (logType != "ALL") {
+ query << " AND log_type = '" << logType << "'";
+ }
+ if (username != "ALL") {
+ query << " AND username = '" << username << "'";
+ }
+ if (!description.empty()) {
+ query << " AND event LIKE '%" << description << "%'";
+ }
+ if (!startTime.empty()) {
+ query << " AND timestamp >= '" << startTime << "'";
+ }
+ if (!endTime.empty()) {
+ query << " AND timestamp <= '" << endTime << "'";
+ }
+
+ int offset = (pageNumber - 1) * pageSize;
+ query << " ORDER BY timestamp DESC LIMIT " << pageSize << " OFFSET " << offset;
+
+ return m_pDB->fetchResults(query.str());
+}
+
+// 获取符合条件的日志总数
+int SystemLogManager::getTotalLogCount(
+ const std::string& logType,
+ const std::string& username,
+ const std::string& description,
+ const std::string& startTime,
+ const std::string& endTime)
+{
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "SELECT COUNT(*) FROM system_logs WHERE 1=1";
+
+ if (logType != "ALL") {
+ query << " AND log_type = '" << logType << "'";
+ }
+ if (username != "ALL") {
+ query << " AND username = '" << username << "'";
+ }
+ if (!description.empty()) {
+ query << " AND event LIKE '%" << description << "%'";
+ }
+ if (!startTime.empty()) {
+ query << " AND timestamp >= '" << startTime << "'";
+ }
+ if (!endTime.empty()) {
+ query << " AND timestamp <= '" << endTime << "'";
+ }
+
+ auto results = m_pDB->fetchResults(query.str());
+ return (!results.empty() && !results[0].empty()) ? std::stoi(results[0][0]) : 0;
+}
+
+// 清理超过指定天数的旧日志
+void SystemLogManager::cleanOldLogs(int daysToKeep) {
+ if (!m_pDB) {
+ throw std::runtime_error("Database connection is not set.");
+ }
+
+ std::ostringstream query;
+ query << "DELETE FROM system_logs WHERE timestamp < datetime('now', '-" << daysToKeep << " days')";
+ m_pDB->executeQuery(query.str());
+}
+
+// 转换日志类型为字符串
+std::string SystemLogManager::logTypeToString(LogType logType) {
+ switch (logType) {
+ case LogType::Info:
+ return "信息";
+ case LogType::Error:
+ return "错误";
+ case LogType::Operation:
+ return "操作";
+ default:
+ return "未知";
+ }
+}
diff --git a/SourceCode/Bond/BoounionPLC/DBManager/SystemLogManager.h b/SourceCode/Bond/BoounionPLC/DBManager/SystemLogManager.h
new file mode 100644
index 0000000..764450c
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/DBManager/SystemLogManager.h
@@ -0,0 +1,76 @@
+#ifndef SYSTEM_LOG_MANAGER_H
+#define SYSTEM_LOG_MANAGER_H
+
+#include <string>
+#include <vector>
+#include <mutex>
+#include "Database.h"
+
+// 系统日志管理类
+class SystemLogManager {
+public:
+ // 日志类型定义
+ enum class LogType {
+ Info,
+ Error,
+ Operation,
+ Unknown
+ };
+
+ // 获取单例实例
+ static SystemLogManager& getInstance();
+
+ // 设置数据库连接
+ void setDatabase(BL::Database* db);
+
+ // 初始化日志表
+ bool initializeLogTable();
+
+ // 添加日志
+ bool log(LogType logType, const std::string& event);
+ bool log(LogType logType, const std::string& event, const std::string& username);
+
+ // 获取日志内容
+ std::vector<std::vector<std::string>> getLogs(int startPosition = -1, int count = -1);
+
+ // 获取筛选后的日志数据
+ std::vector<std::vector<std::string>> getFilteredLogs(
+ const std::string& logType,
+ const std::string& username,
+ const std::string& description,
+ const std::string& startTime,
+ const std::string& endTime,
+ int pageNumber,
+ int pageSize);
+
+ // 获取符合条件的日志总数
+ int getTotalLogCount(
+ const std::string& logType,
+ const std::string& username,
+ const std::string& description,
+ const std::string& startTime,
+ const std::string& endTime);
+
+ // 清理超过指定天数的旧日志
+ void cleanOldLogs(int daysToKeep = 30);
+
+ // 转换日志类型为字符串
+ static std::string logTypeToString(LogType logType);
+
+private:
+ // 构造函数和析构函数
+ SystemLogManager();
+ ~SystemLogManager();
+
+ // 禁止拷贝和赋值
+ SystemLogManager(const SystemLogManager&) = delete;
+ SystemLogManager& operator=(const SystemLogManager&) = delete;
+
+ // 数据库连接
+ BL::Database* m_pDB = nullptr;
+
+ // 线程安全锁
+ static std::mutex m_mutex;
+};
+
+#endif // SYSTEM_LOG_MANAGER_H
\ No newline at end of file
diff --git a/SourceCode/Bond/BoounionPLC/DBManager/UserManager.cpp b/SourceCode/Bond/BoounionPLC/DBManager/UserManager.cpp
new file mode 100644
index 0000000..db9f1e5
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/DBManager/UserManager.cpp
@@ -0,0 +1,542 @@
+#include "stdafx.h"
+#include "UserManager.h"
+#include <chrono>
+#include <iostream>
+#include <fstream>
+#include <ctime>
+#include <sstream>
+
+const std::string SESSION_FILE = R"(session.dat)";
+const std::string DATABASE_FILE = R"(BondEq.db)";
+
+const std::string INITIAL_ADMIN_USERNAME = "admin";
+const std::string INITIAL_ADMIN_PASSWORD = "admin";
+
+// 获取单例实例
+UserManager& UserManager::getInstance() {
+ 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();
+}
+
+UserManager::~UserManager() {
+ terminateIdleDetection();
+}
+
+// 提供数据库连接
+std::unique_ptr<BL::Database>& UserManager::getDatabaseInstance() {
+ 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 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);
+
+ 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;
+}
+
+// 对密码进行哈希处理
+std::string UserManager::hashPassword(const 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;
+}
+
+// 从会话文件加载会话信息
+bool UserManager::loadSession() {
+ 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 decryptedData = simpleEncryptDecrypt(encryptedData, "my_secret_key");
+
+ // 解析解密的数据
+ std::istringstream sessionData(decryptedData);
+ std::string username;
+ std::string password;
+ std::time_t lastLoginTime;
+ int timeoutMinutes;
+ int 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);
+
+ if (sessionDuration > std::chrono::hours(expirationHours)) {
+ clearSession();
+ return false;
+ }
+
+ // 恢复会话数据
+ 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();
+
+ return true;
+}
+
+// 保存会话信息到文件
+void UserManager::saveSession() {
+ 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::string encryptedData = simpleEncryptDecrypt(sessionData.str(), "my_secret_key");
+
+ // 写入加密数据到文件
+ std::ofstream sessionFile(getSessionFilePath(), std::ios::binary);
+ if (sessionFile.is_open()) {
+ sessionFile << encryptedData;
+ sessionFile.close();
+ }
+}
+
+// 清除会话文件
+void UserManager::clearSession() {
+ std::remove(getSessionFilePath().c_str());
+}
+
+// 获取程序路径下的config文件夹路径
+std::string UserManager::getConfigFolderPath() {
+ char path[MAX_PATH];
+ GetModuleFileName(NULL, path, MAX_PATH);
+ std::string exePath = std::string(path).substr(0, std::string(path).find_last_of("\\/"));
+ std::string configPath = exePath + "\\Config\\";
+
+ // 检查并创建config文件夹
+ DWORD fileAttr = GetFileAttributes(configPath.c_str());
+ if (fileAttr == INVALID_FILE_ATTRIBUTES) {
+ CreateDirectory(configPath.c_str(), NULL);
+ }
+
+ return configPath;
+}
+
+// 获取session.dat文件路径
+std::string UserManager::getSessionFilePath() {
+ return getConfigFolderPath() + SESSION_FILE;
+}
+
+// 获取数据库文件路径
+std::string UserManager::getDatabaseFilePath() {
+ 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);
+
+ 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_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();
+
+ std::string updateLoginTime = "UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE username = '" + username + "'";
+ m_pDB->executeQuery(updateLoginTime);
+
+ saveSession();
+ return true;
+}
+
+// 登出方法
+void UserManager::logout() {
+ 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();
+ }
+}
+
+// 返回当前用户的登录状态
+bool UserManager::isLoggedIn() const {
+ 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::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;
+ }
+
+ 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 {};
+ }
+
+ // 查询整个用户表
+ 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;
+}
+
+// 设置整个用户表的数据,仅超级管理员有权限
+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;
+ }
+
+ // 清空用户表
+ 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;
+ }
+
+ 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;
+ }
+ }
+
+ 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;
+ }
+
+ 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 (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;
+ }
+
+ 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;
+ }
+
+ 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_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);
+}
+
+// 修改用户的 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;
+ }
+
+ 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;
+}
+
+// 修改用户的 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;
+ }
+
+ 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;
+}
+
+// 获取所有用户名称
+std::vector<std::string> UserManager::getUsernames() {
+ 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]); // 获取用户名列的值
+ }
+ }
+
+ 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 << "'";
+
+ // 执行查询并获取结果
+ auto results = m_pDB->fetchResults(query.str());
+ if (results.empty()) {
+ return {};
+ }
+
+ // 返回查询到的第一行数据
+ 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;
+}
+
+// 设置无操作超时时间
+void UserManager::setSessionTimeout(std::chrono::minutes 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;
+}
+
+// 初始化无操作检测,包括设置全局鼠标和键盘钩子
+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);
+}
+
+// 终止无操作检测,清除鼠标和键盘钩子
+void UserManager::terminateIdleDetection() {
+ 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;
+}
+
+// 获取当前登录用户密码
+std::string UserManager::getCurrentPass() const {
+ return m_strCurrentPass;
+}
+
+// 修改当前登录用户密码
+void UserManager::setCurrentPass(const std::string& strPass) {
+ m_strCurrentPass = strPass;
+}
+
+// 获取当前登录用户角色
+UserRole UserManager::getCurrentUserRole() const {
+ return m_enCurrentUserRole;
+}
+
+// 修改当前登录用户角色
+void UserManager::setCurrentUserRole(UserRole 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);
+}
+
+// 全局键盘钩子回调,记录活动时间
+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);
+}
diff --git a/SourceCode/Bond/BoounionPLC/DBManager/UserManager.h b/SourceCode/Bond/BoounionPLC/DBManager/UserManager.h
new file mode 100644
index 0000000..48c206f
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/DBManager/UserManager.h
@@ -0,0 +1,131 @@
+#ifndef USER_MANAGER_H
+#define USER_MANAGER_H
+
+#include <string>
+#include <memory>
+#include <chrono>
+#include <windows.h>
+#include "Database.h"
+
+
+// 用户角色定义
+enum class UserRole {
+ SuperAdmin = 0, // 超级管理员
+ Engineer, // 工程师
+ Operator // 操作员
+};
+
+// 用户管理类,采用单例模式
+class UserManager {
+public:
+ static UserManager& getInstance();
+
+ UserManager(const UserManager&) = delete;
+ UserManager& operator=(const UserManager&) = delete;
+
+ // 提供数据库连接
+ 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 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 loadSession(); // 从会话文件加载会话信息
+ void saveSession(); // 保存会话信息到文件
+ void clearSession(); // 清除会话文件
+
+ // 配置文件夹路径管理
+ static std::string getConfigFolderPath();
+ static std::string getSessionFilePath();
+ static std::string getDatabaseFilePath();
+
+ // 更新最后活动时间(用于无操作超时检测)
+ void updateActivityTime();
+
+ // 设置用户的无操作超时时间
+ void setSessionTimeout(std::chrono::minutes timeout);
+
+ // 检查是否无操作超时
+ bool isInactiveTimeout() const;
+
+ // 初始化无操作检测(设置全局钩子和定时器)
+ void initializeIdleDetection(HWND hwnd);
+
+ // 终止无操作检测(清除钩子和定时器)
+ void terminateIdleDetection();
+
+ // 获取当前登录用户名
+ std::string getCurrentUser() const;
+
+ // 修改当前登录用户名
+ void setCurrentUser(const std::string& strName);
+
+ // 获取当前登录用户密码
+ std::string getCurrentPass() const;
+
+ // 修改当前登录用户密码
+ void setCurrentPass(const std::string& strPass);
+
+ // 获取当前登录用户角色
+ UserRole getCurrentUserRole() const;
+
+ // 修改当前登录用户角色
+ void setCurrentUserRole(UserRole emRole);
+
+ // 获取当前登录用户的无操作超时时间
+ std::chrono::minutes getSessionTimeout() const;
+
+ // 获取当前登录用户的会话过期时间
+ std::chrono::hours getSessionExpiration() const;
+
+private:
+ UserManager();
+ ~UserManager();
+
+ // 初始化数据库连接和用户表
+ bool initializeDatabase();
+
+ // 哈希密码,用于加密用户密码
+ std::string hashPassword(const std::string& password);
+
+ // 加密和解密函数
+ 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);
+
+ // 属性定义
+ 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::unique_ptr<BL::Database> m_pDB; // 数据库接口
+};
+
+#endif // USER_MANAGER_H
\ No newline at end of file
diff --git a/SourceCode/Bond/BoounionPLC/Intent.cpp b/SourceCode/Bond/BoounionPLC/Intent.cpp
new file mode 100644
index 0000000..66603b6
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/Intent.cpp
@@ -0,0 +1,51 @@
+#include "stdafx.h"
+#include "Intent.h"
+
+
+CIntent::CIntent()
+{
+ m_nCode = 0;
+ m_pContext = nullptr;
+}
+
+CIntent::CIntent(int nCode, const char* pszMsg, CContext* pContext)
+{
+ m_nCode = nCode;
+ m_strMsg = pszMsg;
+ m_pContext = pContext;
+}
+
+CIntent::~CIntent()
+{
+}
+
+void CIntent::setCode(int nCode)
+{
+ m_nCode = nCode;
+}
+
+int CIntent::getCode()
+{
+ return m_nCode;
+}
+
+void CIntent::setMsg(const char* pszMsg)
+{
+ m_strMsg = pszMsg;
+}
+
+const char* CIntent::getMsg()
+{
+ return m_strMsg.c_str();
+}
+
+void CIntent::setContext(CContext* pContext)
+{
+ pContext->addRef();
+ m_pContext = pContext;
+}
+
+CContext* CIntent::getContext()
+{
+ return m_pContext;
+}
diff --git a/SourceCode/Bond/BoounionPLC/Intent.h b/SourceCode/Bond/BoounionPLC/Intent.h
new file mode 100644
index 0000000..081466f
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/Intent.h
@@ -0,0 +1,25 @@
+#pragma once
+#include <string>
+#include "Context.h"
+
+class CIntent
+{
+public:
+ CIntent();
+ CIntent(int nCode, const char* pszMsg, CContext* pContext);
+ ~CIntent();
+
+public:
+ void setCode(int nCode);
+ int getCode();
+ void setMsg(const char* pszMsg);
+ const char* getMsg();
+ void setContext(CContext* pContext);
+ CContext* getContext();
+
+private:
+ int m_nCode;
+ std::string m_strMsg;
+ CContext* m_pContext;
+};
+
diff --git a/SourceCode/Bond/BoounionPLC/McBool.cpp b/SourceCode/Bond/BoounionPLC/McBool.cpp
new file mode 100644
index 0000000..fc4daca
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/McBool.cpp
@@ -0,0 +1,14 @@
+#include "stdafx.h"
+#include "McBool.h"
+
+
+CMcBool::CMcBool()
+{
+ m_nAddr = 0;
+ m_bValue = false;
+}
+
+
+CMcBool::~CMcBool()
+{
+}
diff --git a/SourceCode/Bond/BoounionPLC/McBool.h b/SourceCode/Bond/BoounionPLC/McBool.h
new file mode 100644
index 0000000..d5db692
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/McBool.h
@@ -0,0 +1,12 @@
+#pragma once
+class CMcBool
+{
+public:
+ CMcBool();
+ ~CMcBool();
+
+public:
+ int m_nAddr;
+ bool m_bValue;
+};
+
diff --git a/SourceCode/Bond/BoounionPLC/McInt.cpp b/SourceCode/Bond/BoounionPLC/McInt.cpp
new file mode 100644
index 0000000..81cbbc4
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/McInt.cpp
@@ -0,0 +1,14 @@
+#include "stdafx.h"
+#include "McInt.h"
+
+
+CMcInt::CMcInt()
+{
+ m_nAddr = 0;
+ m_nValue = 0;
+}
+
+
+CMcInt::~CMcInt()
+{
+}
diff --git a/SourceCode/Bond/BoounionPLC/McInt.h b/SourceCode/Bond/BoounionPLC/McInt.h
new file mode 100644
index 0000000..f3ec9e4
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/McInt.h
@@ -0,0 +1,12 @@
+#pragma once
+class CMcInt
+{
+public:
+ CMcInt();
+ ~CMcInt();
+
+public:
+ int m_nAddr;
+ int m_nValue;
+};
+
diff --git a/SourceCode/Bond/BoounionPLC/McItem.cpp b/SourceCode/Bond/BoounionPLC/McItem.cpp
new file mode 100644
index 0000000..3841a87
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/McItem.cpp
@@ -0,0 +1,12 @@
+#include "stdafx.h"
+#include "McItem.h"
+
+
+CMcItem::CMcItem()
+{
+}
+
+
+CMcItem::~CMcItem()
+{
+}
diff --git a/SourceCode/Bond/BoounionPLC/McItem.h b/SourceCode/Bond/BoounionPLC/McItem.h
new file mode 100644
index 0000000..290d1d3
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/McItem.h
@@ -0,0 +1,8 @@
+#pragma once
+class CMcItem
+{
+public:
+ CMcItem();
+ ~CMcItem();
+};
+
diff --git a/SourceCode/Bond/BoounionPLC/McString.cpp b/SourceCode/Bond/BoounionPLC/McString.cpp
new file mode 100644
index 0000000..9108ba9
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/McString.cpp
@@ -0,0 +1,14 @@
+#include "stdafx.h"
+#include "McString.h"
+
+
+CMcString::CMcString()
+{
+ m_nAddrStart = 0;
+ m_nAddrEnd = 0;
+}
+
+
+CMcString::~CMcString()
+{
+}
diff --git a/SourceCode/Bond/BoounionPLC/McString.h b/SourceCode/Bond/BoounionPLC/McString.h
new file mode 100644
index 0000000..bb44e80
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/McString.h
@@ -0,0 +1,15 @@
+#pragma once
+#include <string>
+
+class CMcString
+{
+public:
+ CMcString();
+ ~CMcString();
+
+public:
+ int m_nAddrStart;
+ int m_nAddrEnd;
+ std::string m_strValue;
+};
+
diff --git a/SourceCode/Bond/BoounionPLC/PLC.cpp b/SourceCode/Bond/BoounionPLC/PLC.cpp
index 153d52a..92e13e6 100644
--- a/SourceCode/Bond/BoounionPLC/PLC.cpp
+++ b/SourceCode/Bond/BoounionPLC/PLC.cpp
@@ -1,9 +1,36 @@
#include "stdafx.h"
#include "PLC.h"
+#include "Log.h"
+
+void CALLBACK TimerFileProc(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
+{
+ CPLC* pPlc = (CPLC*)dwUser;
+ SetEvent(pPlc->m_hTimeEvent);
+}
+
+unsigned __stdcall McMonitorThreadFunction(LPVOID lpParam)
+{
+ CPLC* pPlc = (CPLC*)lpParam;
+ return pPlc->onMonitor();
+}
CPLC::CPLC()
{
+ m_pChannel = nullptr;
+ m_state = PLCSTATE::READY;
+ m_listener.onStateChanged = nullptr;
+ m_listener.onMonitorData = nullptr;
+ m_listener.onAlarm = nullptr;
+ m_nUnHeartBeat = 0;
+ m_nActionInterval = 500;
+ m_hTimeEvent = nullptr;
+ m_hMcMonitorStop = nullptr;
+ m_hMcMonitorThreadHandle = nullptr;
+ m_mcMonitorThrdaddr = 0;
+ m_nTimerId = 0;
+ m_hTimeEvent = nullptr;
+ m_bMute = false;
}
CPLC::CPLC(const char* pszName, const char* pszIp, const unsigned int port)
@@ -11,10 +38,26 @@
m_strName = pszName;
m_strIp = pszIp;
m_nPort = port;
+ m_pChannel = nullptr;
+ m_state = PLCSTATE::READY;
+ m_listener.onStateChanged = nullptr;
+ m_listener.onMonitorData = nullptr;
+ m_nUnHeartBeat = 0;
+ m_hTimeEvent = nullptr;
+ m_hMcMonitorStop = nullptr;
+ m_hMcMonitorThreadHandle = nullptr;
+ m_mcMonitorThrdaddr = 0;
+ m_nTimerId = 0;
+ m_hTimeEvent = nullptr;
}
CPLC::~CPLC()
{
+}
+
+void CPLC::setWorkDir(const char* pszDir)
+{
+ m_strWorkDir = pszDir;
}
std::string& CPLC::getName()
@@ -31,3 +74,290 @@
{
return m_nPort;
}
+
+bool CPLC::isMute()
+{
+ return m_bMute;
+}
+
+CAlarmMonitor* CPLC::getAlarmMonitor()
+{
+ return (CAlarmMonitor*)getComponent("PLC(1)");
+}
+
+void CPLC::init()
+{
+ // mc channel
+ McChannelListener m_mcChannellistener;
+ m_mcChannellistener.funOnConnected = [&](IMcChannel* pChannel, int nErrorCode) -> void {
+ LOGI("<PLC-%s>连接结果<code= %d>", m_strName.c_str(), nErrorCode);
+ if (nErrorCode == 0) {
+ setState(PLCSTATE::CONNECTED);
+ }
+ else {
+ setState(PLCSTATE::DISCONNECTED);
+ }
+ };
+ m_mcChannellistener.funOnClose = [&](IMcChannel* pChannel) -> void {
+ setState(PLCSTATE::DISCONNECTED);
+ };
+ m_mcChannellistener.funOnClosing = [&](IMcChannel* pChannel) -> void {
+ };
+ m_mcChannellistener.funOnRead = [&](IMcChannel* pChannel, char* pData, unsigned int nDataSize, int nDecodeRet) -> void {
+ CString strText;
+ dataToHexString(pData, nDataSize, strText);
+ if (nDecodeRet != 0) {
+ LOGE("<PLC-%s>funOnRead[%s], nDecodeRet=%d", m_strName.c_str(), (LPTSTR)(LPCTSTR)strText, nDecodeRet);
+ }
+ m_nUnHeartBeat = 0;
+ };
+ m_mcChannellistener.funOnWrite = [&](IMcChannel* pChannel) -> void {
+
+ };
+
+ if (0 == MCL_CreateChannel(m_pChannel, m_strName.c_str(), m_strIp.c_str(), m_nPort, 0)
+ && m_pChannel != NULL) {
+ m_pChannel->setChannelListener(&m_mcChannellistener);
+ m_pChannel->setActionInterval(m_nActionInterval);
+ LOGI("<PLC-%s>正在连接PLC.", m_strName.c_str());
+ setState(PLCSTATE::CONNECTING);
+ m_pChannel->connect();
+ }
+ else if (m_pChannel != NULL) {
+ m_pChannel->setChannelListener(&m_mcChannellistener);
+ m_pChannel->setActionInterval(m_nActionInterval);
+ }
+
+
+ // 警告监控
+ CString strAlarmFile;
+ strAlarmFile.Format(_T("%s\\%s\\AlarmList.txt"), m_strWorkDir.c_str(), m_strName.c_str());
+ CAlarmMonitor* pAlarmMonitor = new CAlarmMonitor();
+ pAlarmMonitor->setName("警告信息");
+ pAlarmMonitor->setDescription("警告信息监控");
+ pAlarmMonitor->setIndex(0);
+ pAlarmMonitor->readAlarmListFromFile((LPTSTR)(LPCTSTR)strAlarmFile);
+ addComponent(pAlarmMonitor);
+ pAlarmMonitor->init();
+
+
+ // 定时器
+ m_hTimeEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+ timeBeginPeriod(1);
+ m_nTimerId = timeSetEvent(200, 1, TimerFileProc, (DWORD_PTR)this, TIME_PERIODIC);
+
+
+ // 数据监控线程
+ if (m_hMcMonitorStop != NULL) return;
+ m_hMcMonitorStop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+ m_hMcMonitorThreadHandle = (HANDLE)_beginthreadex(NULL, 0, ::McMonitorThreadFunction, this,
+ 0, &m_mcMonitorThrdaddr);
+
+}
+
+void CPLC::term()
+{
+ timeKillEvent(m_nTimerId);
+ timeEndPeriod(1); // 清除前面对定时器的设置
+
+ for (auto item : m_components) {
+ delete item;
+ }
+ m_components.clear();
+
+ ASSERT(m_hMcMonitorStop);
+ SetEvent(m_hMcMonitorStop);
+ if (m_hMcMonitorThreadHandle != NULL) {
+ WaitForSingleObject(m_hMcMonitorThreadHandle, INFINITE);
+ CloseHandle(m_hMcMonitorThreadHandle);
+ m_hMcMonitorThreadHandle = NULL;
+ }
+ CloseHandle(m_hMcMonitorStop);
+ m_hMcMonitorStop = NULL;
+
+ for (auto& m : m_monitors) {
+ CloseHandle(m.hEvent);
+ }
+}
+
+bool CPLC::isConnected()
+{
+ return m_pChannel != nullptr && m_pChannel->isConnected();
+}
+
+void CPLC::setState(PLCSTATE state)
+{
+ m_state = state;
+ if (m_listener.onStateChanged != nullptr) {
+ m_listener.onStateChanged(this, (int)m_state);
+ }
+}
+
+void CPLC::setActionInterval(unsigned int nInterval)
+{
+ m_nActionInterval = nInterval;
+}
+
+CString& CPLC::dataToHexString(const char* pData, const int size, CString& strOut)
+{
+ strOut.Empty();
+ for (int i = 0; i < size; i++) {
+ if (i < size - 1) {
+ strOut.AppendFormat(_T("%02X "), (BYTE)pData[i]);
+ }
+ else {
+ strOut.AppendFormat(_T("%02X"), (BYTE)pData[i]);
+ }
+ }
+
+ return strOut;
+}
+
+unsigned CPLC::onMonitor()
+{
+ HANDLE hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ int nReadLen = 60 * 2;
+ HANDLE hEvents[2] = { m_hMcMonitorStop, m_hTimeEvent };
+
+ while (1) {
+ int nRet = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
+ ResetEvent(m_hTimeEvent);
+ if (nRet == WAIT_OBJECT_0) {
+ break;
+ }
+
+ if (/*!m_bRunning || */!isConnected()) {
+ continue;
+ }
+
+ for (auto& m : m_monitors) {
+ monitorReadData(m);
+ }
+ }
+
+ TRACE("CPLC::onMonitor 线程退出\n");
+ return 0;
+}
+
+void CPLC::monitorReadData(MONITOR& monitor)
+{
+ BOOL bOutputLog = FALSE;
+ BOOL bReadOk;
+
+
+ // 批量读数据再解释
+ auto funOnReadData = [&](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) -> void {
+ if (flag == 0) {
+ if (bOutputLog) {
+ CString s;
+ s.Format(_T("CPLC::monitorReadData::funOnReadData %d ["), nDataSize);
+ for (unsigned int i = 0; i < nDataSize; i++) {
+ s.AppendFormat(" %x", (BYTE)pData[i]);
+ }
+ s.Append("]");
+ LOGD("<CPLC-%s>Received plc data.%s.monitor=%d", m_strName.c_str(), monitor.id, (LPTSTR)(LPCTSTR)s, monitor.id);
+ }
+ }
+ else {
+ LOGE("<CPLC-%s>PLC批读取数据位超时.monitor=%d, flag=%d", m_strName.c_str(), monitor.id, flag);
+ }
+
+ if (nDataSize == monitor.readLen && flag == 0) {
+ memcpy(monitor.szRecvBuffer, pData, nDataSize);
+ monitor.readCount++;
+ bReadOk = TRUE;
+ }
+ SetEvent(monitor.hEvent);
+ };
+
+
+ bReadOk = FALSE;
+ m_pChannel->readData(monitor.softComponent, monitor.beginAddr, monitor.readLen, funOnReadData);
+ WaitForSingleObject(monitor.hEvent, INFINITE);
+ ResetEvent(monitor.hEvent);
+ if (bReadOk) {
+ ASSERT(m_listener.onMonitorData);
+ m_listener.onMonitorData(this, monitor.id);
+ }
+}
+
+int CPLC::readWord(MC::SOFT_COMPONENT softComponent, unsigned int addr,
+ ONREAD funOnRead)
+{
+ return m_pChannel->readWord(softComponent, addr, funOnRead);
+}
+
+int CPLC::readData(MC::SOFT_COMPONENT softComponent, unsigned int addr,
+ unsigned int nReadLen, ONREADDATA funOnReadData)
+{
+ return m_pChannel->readData(softComponent, addr, nReadLen, funOnReadData);
+}
+
+int CPLC::writeBit(MC::SOFT_COMPONENT softComponent, unsigned int addr,
+ BOOL bValue, ONWRITE funOnWrite)
+{
+ return m_pChannel->writeBit(softComponent, addr, bValue, funOnWrite);
+}
+
+int CPLC::writeWord(MC::SOFT_COMPONENT softComponent, unsigned int addr,
+ int value, ONWRITE funOnWrite)
+{
+ return m_pChannel->writeWord(softComponent, addr, value, funOnWrite);
+}
+
+int CPLC::writeDWord(MC::SOFT_COMPONENT softComponent, unsigned int addr,
+ int value, ONWRITE funOnWrite)
+{
+ return m_pChannel->writeDWord(softComponent, addr, value, funOnWrite);
+}
+
+int CPLC::writeData(MC::SOFT_COMPONENT softComponent, unsigned int addr,
+ const char* pszData, unsigned int length, ONWRITE funOnWrite)
+{
+ return m_pChannel->writeData(softComponent, addr, pszData, length, funOnWrite);
+}
+
+void CPLC::addComponent(CComponent* pComponent)
+{
+ ASSERT(pComponent);
+ pComponent->setPlc(this);
+ m_components.push_back(pComponent);
+}
+
+CComponent* CPLC::getComponent(const char* pszName)
+{
+ for (auto c : m_components) {
+ if (c->getName().compare(pszName) == 0) {
+ return c;
+ }
+ }
+
+ return nullptr;
+}
+
+void CPLC::sendBroadcast(CComponent* pSender, CIntent* pIntent)
+{
+ for (auto item : m_components) {
+ if (item != pSender) {
+ item->onRecvBroadcast(pSender, pIntent);
+ }
+ }
+ this->onRecvBroadcast(pSender, pIntent);
+}
+
+void CPLC::onRecvBroadcast(CComponent* pSender, CIntent* pIntent)
+{
+ int code = pIntent->getCode();
+ if (BC_CODE_ALARM_ON == code) {
+ if (m_listener.onAlarm != nullptr) {
+ m_listener.onAlarm(this, (CAlarm*)pIntent->getContext(), 1);
+ }
+ }
+ else if (BC_CODE_ALARM_OFF == code) {
+ if (m_listener.onAlarm != nullptr) {
+ m_listener.onAlarm(this, (CAlarm*)pIntent->getContext(), 0);
+ }
+ }
+}
+
diff --git a/SourceCode/Bond/BoounionPLC/PLC.h b/SourceCode/Bond/BoounionPLC/PLC.h
index 7922f2f..40bf436 100644
--- a/SourceCode/Bond/BoounionPLC/PLC.h
+++ b/SourceCode/Bond/BoounionPLC/PLC.h
@@ -1,5 +1,38 @@
#pragma once
#include <string>
+#include "AlarmMonitor.h"
+#include "MMSystem.h"
+#pragma comment(lib,"winmm")
+
+
+typedef std::function<void(void* pFrom, int)> ONPLCSTATECHANGED;
+typedef std::function<void(void* pFrom, int)> ONPLCMONITORDATA;
+typedef std::function<void(void* pFrom, CAlarm*, int)> ONALARM;
+typedef struct _PLCListener
+{
+ ONPLCSTATECHANGED onStateChanged;
+ ONPLCMONITORDATA onMonitorData;
+ ONALARM onAlarm;
+} PLCListener;
+
+typedef struct _MONITOR
+{
+ int id;
+ int beginAddr;
+ int readLen;
+ MC::SOFT_COMPONENT softComponent;
+ char* szRecvBuffer;
+ HANDLE hEvent;
+ ULONGLONG readCount;
+} MONITOR;
+
+enum class PLCSTATE
+{
+ READY = 0,
+ CONNECTING,
+ CONNECTED,
+ DISCONNECTED
+};
class CPLC
{
@@ -9,13 +42,57 @@
~CPLC();
public:
+ void setWorkDir(const char* pszDir);
+ void init();
+ void term();
+ void sendBroadcast(CComponent* pSender, CIntent* pIntent);
+ void onRecvBroadcast(CComponent* pSender, CIntent* pIntent);
+ bool isConnected();
+ void setActionInterval(unsigned int nInterval);
std::string& getName();
std::string& getIp();
unsigned int getPort();
+ bool isMute();
+ void addComponent(CComponent* pComponent);
+ CComponent* getComponent(const char* pszName);
+ CAlarmMonitor* getAlarmMonitor();
+ unsigned onMonitor();
+ void OnTimer(UINT nTimerid);
+ int addMonitor(int id, int beginAddr, int endAddr, MC::SOFT_COMPONENT softComponent, char* pszRecvBuffer);
+ int readWord(MC::SOFT_COMPONENT softComponent, unsigned int addr, ONREAD funOnRead);
+ int readData(MC::SOFT_COMPONENT softComponent, unsigned int addr, unsigned int nReadLen, ONREADDATA funOnReadData);
+ int writeWord(MC::SOFT_COMPONENT softComponent, unsigned int addr, int value, ONWRITE funOnWrite);
+ int writeDWord(MC::SOFT_COMPONENT softComponent, unsigned int addr, int value, ONWRITE funOnWrite);
+ int writeBit(MC::SOFT_COMPONENT softComponent, unsigned int addr, BOOL bValue, ONWRITE funOnWrite);
+ int writeData(MC::SOFT_COMPONENT softComponent, unsigned int addr, const char* pszData, unsigned int length, ONWRITE funOnWrite);
+
+
+public:
+ HANDLE m_hTimeEvent;
private:
+ void setState(PLCSTATE state);
+ void monitorReadData(MONITOR& monitor);
+ CString& dataToHexString(const char* pData, const int size, CString& strOut);
+
+private:
+ std::string m_strWorkDir;
std::string m_strName;
std::string m_strIp;
unsigned int m_nPort;
+ IMcChannel* m_pChannel;
+ PLCSTATE m_state;
+ PLCListener m_listener;
+ unsigned int m_nActionInterval;
+ unsigned int m_nUnHeartBeat;
+ std::vector<CComponent*> m_components;
+
+private:
+ std::vector<MONITOR> m_monitors;
+ HANDLE m_hMcMonitorStop;
+ HANDLE m_hMcMonitorThreadHandle;
+ unsigned m_mcMonitorThrdaddr;
+ MMRESULT m_nTimerId;
+ bool m_bMute;
};
diff --git a/SourceCode/Bond/BoounionPLC/Resource.h b/SourceCode/Bond/BoounionPLC/Resource.h
index c8ecf6c..1e2104c 100644
--- a/SourceCode/Bond/BoounionPLC/Resource.h
+++ b/SourceCode/Bond/BoounionPLC/Resource.h
Binary files differ
diff --git a/SourceCode/Bond/BoounionPLC/ToolUnits.cpp b/SourceCode/Bond/BoounionPLC/ToolUnits.cpp
new file mode 100644
index 0000000..664f802
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/ToolUnits.cpp
@@ -0,0 +1,304 @@
+#include "stdafx.h"
+#include "ToolUnits.h"
+#include <chrono>
+#include <memory>
+
+
+CToolUnits::CToolUnits()
+{
+}
+
+
+CToolUnits::~CToolUnits()
+{
+}
+
+std::string CToolUnits::timeToString(ULONGLONG time)
+{
+ ULONGLONG time1, time2;
+ time1 = time / 1000000000;
+ time2 = time % 1000000000;
+
+ char buffer1[256], buffer[128];
+ struct tm timeinfo;
+ time_t t = time_t(time1);
+ localtime_s(&timeinfo, &t);
+ strftime(buffer, 128, "%Y-%m-%d %H:%M:%S", &timeinfo);
+ sprintf_s(buffer1, 256, "%s.%lld", buffer, time2);
+ return std::string(buffer1);
+}
+
+std::string CToolUnits::timeToString2(ULONGLONG time)
+{
+ ULONGLONG time1;
+ time1 = time / 1000;
+
+ char buffer[256];
+ struct tm timeinfo;
+ time_t t = time_t(time1);
+ localtime_s(&timeinfo, &t);
+ strftime(buffer, 128, "%Y-%m-%d %H:%M:%S", &timeinfo);
+ return std::string(buffer);
+}
+
+std::string CToolUnits::timeToString3(ULONGLONG time)
+{
+ ULONGLONG time1;
+ int ms;
+ time1 = time / 1000;
+ ms = time % 1000;
+
+ char buffer1[256], buffer[128];
+ struct tm timeinfo;
+ time_t t = time_t(time1);
+ localtime_s(&timeinfo, &t);
+ strftime(buffer, 128, "%Y-%m-%d %H:%M:%S", &timeinfo);
+ sprintf_s(buffer1, 256, "%s.%03d", buffer, ms);
+ return std::string(buffer1);
+}
+
+ULONGLONG CToolUnits::stringToTime(const char* pszTime)
+{
+ struct tm tm;
+
+ memset(&tm, 0, sizeof(tm));
+ sscanf_s(pszTime, "%d-%d-%d %d:%d:%d",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+ tm.tm_year -= 1900;
+ tm.tm_mon--;
+
+ return mktime(&tm) * 1000;
+}
+
+ULONGLONG CToolUnits::getTimestamp()
+{
+ auto now = std::chrono::system_clock::now();
+ auto duration_in_milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
+ uint64_t timestamp = duration_in_milliseconds.count();
+ return timestamp;
+}
+
+void CToolUnits::createDir(const char* pszDir)
+{
+ if (isDirectory(std::string(pszDir))) {
+ return;
+ }
+
+ CString strDir = pszDir;
+ int lastIndex = 0;
+ int index = strDir.Find(_T("\\"), lastIndex);
+ while (index > 0) {
+ CString strTempDir = strDir.Left(index);
+ CreateDirectory(strTempDir, NULL);
+
+ lastIndex = index + 1;
+ index = strDir.Find(_T("\\"), lastIndex);
+ }
+ CreateDirectory(strDir, NULL);
+}
+
+CString& CToolUnits::floatToString1(float value, CString& strOut)
+{
+ strOut.Format(_T("%.1f"), value);
+ return strOut;
+}
+
+CString& CToolUnits::floatToString3(float value, CString& strOut)
+{
+ strOut.Format(_T("%.3f"), value);
+ return strOut;
+}
+
+
+BOOL CToolUnits::copyTextToClipboard(CWnd* pWnd, const CString& strText)
+{
+ if (OpenClipboard(pWnd->GetSafeHwnd())) {
+ EmptyClipboard();
+
+ HGLOBAL hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (strText.GetLength() + 1) * sizeof(TCHAR));
+ if (hglbCopy == NULL) {
+ CloseClipboard();
+ return FALSE;
+ }
+
+ LPTSTR lptstrCopy = (LPTSTR)GlobalLock(hglbCopy);
+ strcpy_s(lptstrCopy, strText.GetLength()+1, strText);
+ GlobalUnlock(hglbCopy);
+ SetClipboardData(CF_TEXT, hglbCopy);
+ CloseClipboard();
+ GlobalFree(hglbCopy);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+std::string CToolUnits::getCurrentExePath() {
+ char path[MAX_PATH];
+ GetModuleFileName(NULL, path, MAX_PATH);
+ std::string exePath(path);
+ return exePath.substr(0, exePath.find_last_of("\\/"));
+}
+
+bool CToolUnits::isFile(const std::string& path) {
+ DWORD attributes = GetFileAttributes(path.c_str());
+ return (attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY));
+}
+
+bool CToolUnits::isDirectory(const std::string& path) {
+ DWORD attributes = GetFileAttributes(path.c_str());
+ return (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY));
+}
+
+int CToolUnits::toInt32(const char* pBuffer)
+{
+ return (pBuffer[0] & 0xff) | ((pBuffer[1] & 0xff) << 8) | ((pBuffer[2] & 0xff) << 16) | ((pBuffer[3] & 0xff) << 24);
+}
+
+int CToolUnits::toInt16(const char* pBuffer)
+{
+ return (pBuffer[0] & 0xff) | (pBuffer[1] & 0xff) << 8;
+}
+
+BOOL CToolUnits::getBit(const char c, int index)
+{
+ switch (index)
+ {
+ case 0:
+ return c & 0x01;
+ break;
+ case 1:
+ return c & 0x02;
+ break;
+ case 2:
+ return c & 0x04;
+ break;
+ case 3:
+ return c & 0x08;
+ break;
+ case 4:
+ return c & 0x10;
+ break;
+ case 5:
+ return c & 0x20;
+ break;
+ case 6:
+ return c & 0x40;
+ break;
+ case 7:
+ return c & 0x80;
+ break;
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+void CToolUnits::setBit(char* p, int index)
+{
+ int byteIndex = 0;
+ byte b = 0;
+ if (index >= 8) byteIndex = 1;
+ switch (index)
+ {
+ case 0:
+ case 8:
+ b = 0x1;
+ break;
+ case 1:
+ case 9:
+ b = 0x2;
+ break;
+ case 2:
+ case 0xA:
+ b = 0x4;
+ break;
+ case 3:
+ case 0xB:
+ b = 0x8;
+ break;
+ case 4:
+ case 0xC:
+ b = 0x10;
+ break;
+ case 5:
+ case 0xD:
+ b = 0x20;
+ break;
+ case 6:
+ case 0xE:
+ b = 0x40;
+ break;
+ case 7:
+ case 0xF:
+ b = 0x80;
+ break;
+ default:
+ break;
+ }
+
+ p[byteIndex] = b;
+}
+
+void CToolUnits::setDlgItemDouble(CWnd* pWnd, int nCtrlId, double value)
+{
+ CString strText;
+ strText.Format(_T("%.03f"), value);
+ pWnd->SetDlgItemText(nCtrlId, strText);
+}
+
+std::vector<CString> CToolUnits::GetFileNamesInDirectory(const CString& strFolderPath, const CString& strExtension)
+{
+ std::vector<CString> fileNames;
+
+ // 确保目录路径最后有反斜杠
+ CString strSearchPath = strFolderPath;
+ if (strSearchPath[strSearchPath.GetLength() - 1] != '\\') {
+ strSearchPath += '\\';
+ }
+
+ CString finalExtension = strExtension;
+ if (finalExtension.Find('.') == -1) {
+ finalExtension = '.' + finalExtension;
+ }
+ strSearchPath += "*" + finalExtension;
+
+ std::unique_ptr<CFileFind> finder = std::make_unique<CFileFind>();
+ BOOL bWorking = finder->FindFile(strSearchPath);
+
+ // 遍历文件夹
+ while (bWorking) {
+ bWorking = finder->FindNextFile();
+ if (!finder->IsDirectory()) {
+ CString fileName = finder->GetFileName();
+ int dotPos = fileName.ReverseFind('.');
+ if (dotPos != -1) {
+ fileName = fileName.Left(dotPos);
+ }
+ fileNames.push_back(fileName);
+ }
+ }
+
+ return fileNames;
+}
+
+std::string CToolUnits::getRecipePath()
+{
+ return getCurrentExePath() + "\\Recipe";
+}
+
+std::string CToolUnits::getCurrentTimeString()
+{
+ struct tm ltm;
+ time_t now = time(0);
+ localtime_s(<m, &now); // 使用安全的 localtime_s 函数
+
+ char buffer[256];
+ sprintf_s(buffer, sizeof(buffer), "%04d-%02d-%02d %02d:%02d:%02d",
+ ltm.tm_year + 1900, ltm.tm_mon + 1, ltm.tm_mday,
+ ltm.tm_hour, ltm.tm_min, ltm.tm_sec);
+
+ return std::string(buffer);
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/BoounionPLC/ToolUnits.h b/SourceCode/Bond/BoounionPLC/ToolUnits.h
new file mode 100644
index 0000000..9e8fdfb
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/ToolUnits.h
@@ -0,0 +1,32 @@
+#pragma once
+#include <string>
+
+class CToolUnits
+{
+public:
+ CToolUnits();
+ ~CToolUnits();
+
+public:
+ static std::string timeToString(ULONGLONG time);
+ static std::string timeToString2(ULONGLONG time);
+ static std::string timeToString3(ULONGLONG time);
+ static ULONGLONG stringToTime(const char* pszTime);
+ static CString& floatToString1(float value, CString& strOut);
+ static CString& floatToString3(float value, CString& strOut);
+ static ULONGLONG getTimestamp();
+ static void createDir(const char* pszDir);
+ static BOOL copyTextToClipboard(CWnd* pWnd, const CString& strText);
+ static std::string getCurrentExePath();
+ static bool isFile(const std::string& path);
+ static bool isDirectory(const std::string& path);
+ static int toInt32(const char* pBuffer);
+ static int toInt16(const char* pBuffer);
+ static BOOL getBit(const char c, int index);
+ static void setBit(char* p, int index);
+ static void setDlgItemDouble(CWnd* pWnd, int nCtrlId, double value);
+ static std::vector<CString> GetFileNamesInDirectory(const CString& strFolderPath, const CString& strExtension);
+ static std::string getRecipePath();
+ static std::string getCurrentTimeString();
+};
+
diff --git a/SourceCode/Bond/BoounionPLC/TopToolbar.cpp b/SourceCode/Bond/BoounionPLC/TopToolbar.cpp
index 0fbbb05..72b0cc3 100644
--- a/SourceCode/Bond/BoounionPLC/TopToolbar.cpp
+++ b/SourceCode/Bond/BoounionPLC/TopToolbar.cpp
@@ -29,6 +29,7 @@
DDX_Control(pDX, IDC_BUTTON_ADD, m_btnAdd);
DDX_Control(pDX, IDC_BUTTON_DELETE, m_btnDelete);
DDX_Control(pDX, IDC_BUTTON_SETTINGS, m_btnSettings);
+ DDX_Control(pDX, IDC_BUTTON_ALARM, m_btnAlarm);
DDX_Control(pDX, IDC_BUTTON_OPERATOR, m_btnOperator);
}
@@ -51,6 +52,7 @@
InitBtn(m_btnAdd, "Add_blue_32.ico", "Add_Gray_32.ico");
InitBtn(m_btnDelete, "delete_blue_32.ico", "delete_Gray_32.ico");
InitBtn(m_btnSettings, "Settings_High_32.ico", "Settings_Gray_32.ico");
+ InitBtn(m_btnAlarm, "Alarm_o_32.ico", "Alarm_Gray_32.ico");
InitBtn(m_btnOperator, "Operator_High_32.ico", "Operator_Gray_32.ico");
HMENU hMenu = LoadMenu(AfxGetInstanceHandle(), MAKEINTRESOURCEA(IDR_MENU_OPEATOR));
m_btnOperator.SetMenu(hMenu);
@@ -123,6 +125,11 @@
x += BTN_WIDTH;
x += 2;
+ pItem = GetDlgItem(IDC_BUTTON_ALARM);
+ pItem->MoveWindow(x, y, BTN_WIDTH, nBthHeight);
+ x += BTN_WIDTH;
+ x += 2;
+
x = rcClient.right - 5 - BTN_WIDTH - 20;
pItem = GetDlgItem(IDC_BUTTON_OPERATOR);
pItem->MoveWindow(x, y, BTN_WIDTH + 20, nBthHeight);
@@ -170,6 +177,7 @@
case IDC_BUTTON_ADD:
case IDC_BUTTON_DELETE:
case IDC_BUTTON_SETTINGS:
+ case IDC_BUTTON_ALARM:
GetParent()->SendMessage(ID_MSG_TOOLBAR_BTN_CLICKED, 0, LOWORD(wParam));
break;
}
diff --git a/SourceCode/Bond/BoounionPLC/TopToolbar.h b/SourceCode/Bond/BoounionPLC/TopToolbar.h
index 17dd1b9..17f93df 100644
--- a/SourceCode/Bond/BoounionPLC/TopToolbar.h
+++ b/SourceCode/Bond/BoounionPLC/TopToolbar.h
@@ -33,6 +33,7 @@
CBlButton m_btnAdd;
CBlButton m_btnDelete;
CBlButton m_btnSettings;
+ CBlButton m_btnAlarm;
CBlButton m_btnOperator;
diff --git a/SourceCode/Bond/BoounionPLC/stdafx.h b/SourceCode/Bond/BoounionPLC/stdafx.h
index d43089c..3d75ce0 100644
--- a/SourceCode/Bond/BoounionPLC/stdafx.h
+++ b/SourceCode/Bond/BoounionPLC/stdafx.h
@@ -40,6 +40,24 @@
#include "..\McLibrarySDK\include\McLib.h"
+// 数据库模块
+#include "..\DatabaseSDK\include\Database.h"
+#include "..\DatabaseSDK\include\MySQLDatabase.h"
+#include "..\DatabaseSDK\include\SQLiteDatabase.h"
+
+#if defined(_WIN64)
+#if defined(_DEBUG)
+#pragma comment(lib, "..\\DatabaseSDK\\lib\\x64\\Debug\\DatabaseEx.lib")
+#else
+#pragma comment(lib, "..\\DatabaseSDK\\lib\\x64\\Release\\DatabaseEx.lib")
+#endif
+#else
+#if defined(_DEBUG)
+#pragma comment(lib, "..\\DatabaseSDK\\lib\\Win32\\Debug\\DatabaseEx.lib")
+#else
+#pragma comment(lib, "..\\DatabaseSDK\\lib\\Win32\\Release\\DatabaseEx.lib")
+#endif
+#endif
#ifdef _UNICODE
diff --git a/SourceCode/Bond/x64/BoounionPLC/Debug/Res/alarm_gray_32.ico b/SourceCode/Bond/x64/BoounionPLC/Debug/Res/alarm_gray_32.ico
new file mode 100644
index 0000000..59e5228
--- /dev/null
+++ b/SourceCode/Bond/x64/BoounionPLC/Debug/Res/alarm_gray_32.ico
Binary files differ
diff --git a/SourceCode/Bond/x64/BoounionPLC/Debug/Res/alarm_o_32.ico b/SourceCode/Bond/x64/BoounionPLC/Debug/Res/alarm_o_32.ico
new file mode 100644
index 0000000..279b80c
--- /dev/null
+++ b/SourceCode/Bond/x64/BoounionPLC/Debug/Res/alarm_o_32.ico
Binary files differ
--
Gitblit v1.9.3