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(&ltm, &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