LAPTOP-SNT8I5JK\Boounion
2025-01-08 3970068b82a21617443fd99a152723e54289ecf2
1.继续移入相关文件,警告功能等;
已添加32个文件
已修改12个文件
4042 ■■■■■ 文件已修改
SourceCode/Bond/BoounionPLC/Alarm.cpp 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/Alarm.h 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/AlarmMonitor.cpp 255 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/AlarmMonitor.h 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/AlarmPopupDlg.cpp 329 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/AlarmPopupDlg.h 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/BoounionPLC.rc 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.filters 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/BoounionPLCDlg.cpp 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/BoounionPLCDlg.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/Common.h 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/Component.cpp 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/Component.h 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/Context.cpp 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/Context.h 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/DBManager/AlarmManager.cpp 235 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/DBManager/AlarmManager.h 142 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/DBManager/AxisManager.cpp 246 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/DBManager/AxisManager.h 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/DBManager/SystemLogManager.cpp 208 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/DBManager/SystemLogManager.h 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/DBManager/UserManager.cpp 542 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/DBManager/UserManager.h 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/Intent.cpp 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/Intent.h 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/McBool.cpp 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/McBool.h 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/McInt.cpp 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/McInt.h 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/McItem.cpp 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/McItem.h 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/McString.cpp 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/McString.h 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/PLC.cpp 330 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/PLC.h 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/Resource.h 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/ToolUnits.cpp 304 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/ToolUnits.h 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/TopToolbar.cpp 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/TopToolbar.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/stdafx.h 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/BoounionPLC/Debug/Res/alarm_gray_32.ico 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/BoounionPLC/Debug/Res/alarm_o_32.ico 补丁 | 查看 | 原始文档 | blame | 历史
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();
    }
}
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;
};
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;
}
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;
};
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);
        }
    });
}
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();
};
SourceCode/Bond/BoounionPLC/BoounionPLC.rc
Binary files differ
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>
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">
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();
}
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;
// å¯¹è¯æ¡†æ•°æ®
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
#define VIEW_TOOL_BTN_CLOSE                0x1016
/* å¹¿æ’­ä»£ç  */
#define BC_CODE_ALARM_ON                1
#define BC_CODE_ALARM_OFF                2
/* ç›‘控数据id */
#define MONITOR_ID_ALARM        1001
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;
}
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;
};
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;
}
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;
};
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());
}
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
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;
}
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
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 "δ֪";
    }
}
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
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);
}
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
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;
}
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;
};
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()
{
}
SourceCode/Bond/BoounionPLC/McBool.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
#pragma once
class CMcBool
{
public:
    CMcBool();
    ~CMcBool();
public:
    int m_nAddr;
    bool m_bValue;
};
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()
{
}
SourceCode/Bond/BoounionPLC/McInt.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
#pragma once
class CMcInt
{
public:
    CMcInt();
    ~CMcInt();
public:
    int m_nAddr;
    int m_nValue;
};
SourceCode/Bond/BoounionPLC/McItem.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
#include "stdafx.h"
#include "McItem.h"
CMcItem::CMcItem()
{
}
CMcItem::~CMcItem()
{
}
SourceCode/Bond/BoounionPLC/McItem.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
#pragma once
class CMcItem
{
public:
    CMcItem();
    ~CMcItem();
};
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()
{
}
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;
};
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);
        }
    }
}
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;
};
SourceCode/Bond/BoounionPLC/Resource.h
Binary files differ
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);
}
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();
};
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;
    }
SourceCode/Bond/BoounionPLC/TopToolbar.h
@@ -33,6 +33,7 @@
    CBlButton m_btnAdd;
    CBlButton m_btnDelete;
    CBlButton m_btnSettings;
    CBlButton m_btnAlarm;
    CBlButton m_btnOperator;
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
SourceCode/Bond/x64/BoounionPLC/Debug/Res/alarm_gray_32.ico
SourceCode/Bond/x64/BoounionPLC/Debug/Res/alarm_o_32.ico