1. 程式人生 > 其它 >Qt編寫物聯網管理平臺30-使用者登入退出

Qt編寫物聯網管理平臺30-使用者登入退出

一、前言

一個使用者登入介面,是一個完整的應用系統,尤其是客戶端系統必備的一個功能模組,傳統的登入處理一般都是和本地的使用者資訊進行比對,而現代的登入系統一般是傳送請求到伺服器進行驗證,無論何種方式,都是需要去使用者資訊表找到對應的使用者資訊,取出密碼進行驗證,再多一點的話就是順帶把對應的使用者許可權也拉過去。

為了使得多個系統共用一套使用者登入使用者退出的介面和程式碼,特意提煉出了共同點,作為通用的使用者登入退出模組,放在core_form模組中,這樣後期有更新或者BUG修復,只需要更改這個通用模組就行,陸續寫過很多系統,都設計到使用者登入退出處理邏輯,追求極致簡單原則,羅列下通用的使用者登入退出需要的功能點。

  • 下拉選擇使用者名稱稱。
  • 密碼框密文顯示。
  • 提供自動登入複選框,等使用者登入成功以後記住,下次啟動後自動以最後的使用者資訊登入。
  • 提供記住密碼複選框,等使用者登入成功以後記住,下次啟動後自動自動填入該使用者的密碼。
  • 軟體標題自定義,可外部引數傳入。
  • 密碼為空校驗。
  • 三次密碼錯誤提示檢驗。
  • 內建超級密碼,防止管理員忘記密碼。
  • 登入日誌記錄儲存到資料庫。
  • 密碼不區分大小寫。
  • 使用者驗證通過,啟動主窗體。
  • 使用者退出後發出全域性退出事件訊號通知退出,以便收到該訊號的地方做處理。

二、功能特點

2.1 軟體模組

  1. 裝置監控模組,包括資料監控(表格形式展示)、裝置面板(面板形式展示)、地圖監控(地圖形式展示)、曲線監控(曲線形式展示)。
  2. 資料查詢模組,包括報警記錄、執行記錄、操作記錄。
  3. 系統設定模組,包括基本設定、埠管理、控制器管理、探測器管理、報警聯動、型別設定等。
  4. 其他設定模組,包括使用者管理、地圖管理、位置調整、組態設計、裝置除錯等。

2.2 基礎功能

  1. 裝置資料採集,支援串列埠、網路,串列埠可設定串列埠號、波特率,網路可設定IP地址、通訊埠。
  2. 每個埠支援採集週期時間,預設1秒鐘一個裝置。
  3. 支援設定通訊超時次數,預設3次。
  4. 支援最大重連時間,用於重新讀取離線的裝置。
  5. 控制器資訊,能夠新增控制器名稱,選擇控制器地址、控制器型號,設定該控制器下面的探測器數量。
  6. 探測器資訊,能夠新增位號、探測器型號、氣體種類、氣體符號、高報值、低報值、緩衝值、清零值、是否啟用、報警聲音、背景地圖、儲存週期、數值換算小數點位數、報警延時時間、報警的型別(HH,LL,HL)等。
  7. 型別管理可配置控制器型號、探測器型號、氣體種類、氣體符號等。
  8. 地圖支援匯入和刪除,所有的探測器在地圖上的位置可自由拖動儲存。
  9. 埠資訊、控制器資訊、探測器資訊、型別資訊、使用者資訊等,都支援匯入、匯出、匯出到excel、列印。
  10. 執行記錄、報警記錄、操作記錄,都支援多條件組合查詢,比如時間段、控制器、探測器等,所有記錄支援匯出到excel/pdf和列印。
  11. 執行記錄、報警記錄、操作記錄都可刪除指定時間範圍內的資料。
  12. 系統設定可選擇對應表最大儲存記錄數,自動清理早期資料,留出足夠的空間儲存重要的資料。
  13. 報警簡訊轉發,支援多個接收手機號碼,可設定傳送間隔,比如即時傳送或者6個小時傳送一次所有的報警資訊,簡訊內容過長,自動拆分多條簡訊。
  14. 報警郵件轉發,支援多個接收郵箱,可設定傳送間隔,比如即時傳送或者6個小時傳送一次所有的報警資訊,支援附件傳送。
  15. 設定軟體的中文標題、英文標題、logo路徑、版權所有等。
  16. 開關設定開機執行、報警聲音、自動登入、記住密碼等。
  17. 報警聲音可設定播放次數,介面風格樣式提供18套面板檔案選擇。
  18. 使用者管理,包括使用者許可權配置,不同使用者可以有不同模組的許可權。
  19. 使用者登入和使用者退出,可以記住密碼和自動登入,超過三次報錯提示並關閉程式。
  20. 四種監控模式,裝置面板監控、地圖監控、表格資料監控、曲線資料監控,可自由切換,四種模式下都實時展示採集到的資料,報警閃爍等。
  21. 報警繼電器聯動,一個位號可以跨串列埠聯動多個模組和繼電器號,支援多對多。

2.3 特色功能

  1. 通訊協議支援modbus_com、modbus_tcp_rtu,後期拓展mqtt等協議。
  2. 資料來源除了真實的硬體裝置採集,還可選資料庫採集,這樣使用者可以安排其他程式設計師比如java程式設計師將前端採集好的資料放到資料庫,本系統直接從資料庫採集即可。資料庫採集模式可以作為通用的系統使用,更適合多人多系統協作。
  3. 智慧跳過超時的裝置,加快對線上裝置的採集速度,當裝置數量很多的時候尤其有用。
  4. 對智慧跳過的超時的裝置,在設定的重連時間自動採集一次,以便探測裝置是否又重新上線。
  5. 每個探測器可控是否啟用,不啟用則不會採集,也不會在介面顯示,相當於執行階段臨時關閉。
  6. 探測器可設定緩衝值和報警延時時間,在該值附近波動產生的報警,不計入報警,只有持續處於報警值且超過報警延時時間才算真正報警,這樣可以規避很多波動導致的誤報。
  7. 探測器可設定儲存週期,按照設定的時間來儲存一條執行記錄,可以按照重要程度對重要性高的設定儲存週期短一些,不重要的設定大一些,這樣可以節省不少的儲存空間,也保證了重要的資料及時儲存。
  8. 探測器可設定清零值,在一些高精度高靈敏的裝置可能出廠的時候預設值未必是0,需要設定清零值來表示初始值。
  9. 探測器可設定小數點,用於計算後的真實資料控制小數點點位顯示,相當於除以10、除以100、除以1000,這樣大部分的探測器資料直接通過小數點位設定控制真實換算後的值,極個別的需要特殊轉換的可以在通訊協議中約定。
  10. 探測器報警的型別支援多種,有些裝置是高於某個值高報,低於某個值低報,而有些裝置是在最小值最大值範圍內是高報,低於最小值低報,高於最大值正常。這樣可以分情況處理,涵蓋各種報警型別。
  11. 原創資料匯入、匯出、列印機制,跨平臺不依賴任何元件,瞬間匯出資料。
  12. 匯出到excel的記錄支援所有excel、wps等表格檔案版本,不依賴excel等軟體。
  13. 高報顏色、低報顏色、正常顏色、預設值顏色等,都可以自由設定。
  14. 支援雲端資料同步,將本地採集到的資料實時同步到雲端。
  15. 支援網路轉發和網路接收,網路接收開啟後,軟體從udp接收資料進行解析。網路轉發支援多個目標IP,這樣就實現了本地採集的軟體,自由將資料轉到客戶端,隨時檢視採集到的資料。
  16. 自動記住使用者最後停留的介面以及其他配置資訊,重啟後自動應用。
  17. 報警自動切換到對應的地圖,探測器按鈕閃爍,表格資料對應顏色顯示。
  18. 雙擊探測器圖示,彈出對應探測器詳細資訊,可以根據需要定製回控操作。
  19. 資料庫支援多種,包括sqlite、mysql、sqlserver、postgresql、oracle、人大金倉等。
  20. 本地裝置採集到的資料實時上傳到雲端,以便手機APP或者web等其他方式提取。
  21. 自帶裝置模擬工具,支援不同型號的多個裝置資料模擬,同時還帶資料庫資料模擬,以便在沒有裝置的時候測試資料。
  22. 標準modbus協議,各種控制器型別、探測器型別、種類、符號等全部自定義,非常靈活和強大,通訊協議示例資料非常完整,通用各種modbus協議系統,適用於各種應用場景接入。
  23. 同時集成了串列埠通訊、網路通訊、資料庫通訊、資料匯入匯出列印、通訊協議解析、介面UI、全域性換膚等眾多元件和知識點,非常適合新手入門和進階。
  24. 支援xp、win7、win10、、win11、linux、mac、各種國產系統(UOS、中標麒麟、銀河麒麟等)、嵌入式linux等系統。
  25. 註釋完整,專案結構清晰,超級詳細完整的使用開發手冊,精確到每個程式碼檔案的功能說明,不斷持續迭代版本。

三、體驗地址

  1. 國內站點:https://gitee.com/feiyangqingyun
  2. 國際站點:https://github.com/feiyangqingyun
  3. 個人主頁:https://blog.csdn.net/feiyangqingyun
  4. 知乎主頁:https://www.zhihu.com/people/feiyangqingyun
  5. 產品主頁:https://blog.csdn.net/feiyangqingyun/article/details/97565652
  6. 線上文件:https://feiyangqingyun.gitee.io/qwidgetdemo/iotsystem/
  7. 體驗地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取碼:o05q 檔名:bin_iotsystem.zip。
  8. 文章導航:https://qtchina.blog.csdn.net/article/details/121330922

四、效果圖



五、相關程式碼

#include "frmlogin.h"
#include "ui_frmlogin.h"
#include "quihelper.h"
#include "dbquery.h"
#include "frmmain.h"

frmLogin::frmLogin(QWidget *parent) : QDialog(parent), ui(new Ui::frmLogin)
{
    ui->setupUi(this);
    this->initStyle();
    this->initTitle();
    this->initForm();
    this->initIcon();
    QUIHelper::setFormInCenter(this);
}

frmLogin::~frmLogin()
{
    delete ui;
}

void frmLogin::setBanner(const QString &image)
{
    QString qss = QString("border-image:url(%1);").arg(image);
    ui->labName->setStyleSheet(qss);
}

void frmLogin::initStyle()
{
    //初始化無邊框窗體
    QUIHelper::setFramelessForm(this, ui->widgetTitle, ui->labIco, ui->btnMenu_Close, false);
    //關聯關閉按鈕退出
    connect(ui->btnMenu_Close, SIGNAL(clicked()), this, SLOT(close()));
    connect(ui->btnClose, SIGNAL(clicked()), this, SLOT(close()));
    this->setBanner(":/image/bg_banner.jpg");
}

void frmLogin::initTitle()
{
    //設定標題並支援標題換行
    QString titleCn = AppConfig::TitleCn;
    if (titleCn.contains("\\n")) {
        titleCn.replace("\\n", "\n");
    }

    ui->labName->setText(titleCn);
    this->setWindowTitle(ui->labTitlex->text());
}

void frmLogin::initForm()
{
    //將對應使用者的密碼和型別存入連結串列,在使用者登入時對比,比從資料庫中查詢速度要快.
    ui->cboxUserName->addItems(UserHelper::UserInfo_UserName);
    //設定最後登入的使用者
    int index = ui->cboxUserName->findText(AppConfig::LastLoginer);
    ui->cboxUserName->setCurrentIndex(index);

    ui->txtUserPwd->setPlaceholderText("請輸入密碼");
    ui->txtUserPwd->setFocus();
    //設定按鈕預設回車鍵觸發
    ui->btnLogin->setDefault(true);

    //自動填入密碼
    if (AppConfig::AutoPwd) {
        ui->txtUserPwd->setText(UserHelper::UserInfo_UserPwd.at(index));
    }

    //設定是否否選自動登入+記住密碼
    ui->ckAutoPwd->setChecked(AppConfig::AutoPwd);
    ui->ckAutoLogin->setChecked(AppConfig::AutoLogin);

    //樣式改變更新按鈕圖示
    connect(AppEvent::Instance(), SIGNAL(changeStyle()), this, SLOT(initIcon()));
}

void frmLogin::initIcon()
{
    //圖片檔案不存在則設定為圖形字型
    QUIHelper::setIconBtn(ui->btnLogin, ":/image/btn_ok.png", 0xf00c);
    QUIHelper::setIconBtn(ui->btnClose, ":/image/btn_close.png", 0xf00d);
}

void frmLogin::on_btnLogin_clicked()
{
    //獲取填入的密碼,不區分大小寫,全部轉為大小比較
    QString userPwd = ui->txtUserPwd->text();
    userPwd = userPwd.toUpper();
    if (userPwd.isEmpty()) {
        QUIHelper::showMessageBoxError("密碼不能為空, 請重新輸入!", 3, true);
        ui->txtUserPwd->setFocus();
        return;
    }

    //密碼正確或者是超級密碼則表示成功
    int index = ui->cboxUserName->currentIndex();
    if ((userPwd == UserHelper::UserInfo_UserPwd.at(index).toUpper()) || userPwd == "A") {
        UserHelper::CurrentUserName = ui->cboxUserName->currentText();
        UserHelper::getUserInfo();
        DbQuery::addUserLog("使用者登入");

        //記錄當前使用者,寫入到配置檔案,下次啟動時顯示最後一次登入使用者名稱
        AppConfig::AutoPwd = ui->ckAutoPwd->isChecked();
        AppConfig::AutoLogin = ui->ckAutoLogin->isChecked();
        AppConfig::LastLoginer = UserHelper::CurrentUserName;
        AppConfig::writeConfig();

        //如果是密碼A則為超級管理員預設所有許可權都有
        if (userPwd == "A") {
            int count = UserHelper::UserPermission.count();
            for (int i = 0; i < count; ++i) {
                UserHelper::UserPermission[i] = true;
            }
        }

        //隱藏當前介面彈出主介面
        this->hide();
        frmMain *frm = new frmMain;
        frm->show();
    } else {
        //密碼錯誤計數
        static int errorCount = 0;
        errorCount++;
        if (errorCount >= 3) {
            errorCount = 0;
            QUIHelper::showMessageBoxError("密碼輸入錯誤次數超過三次, 系統將自動退出!", 5, true);
            exit(0);
        } else {
            QUIHelper::showMessageBoxError("密碼錯誤, 請重新輸入!", 3, true);
            ui->txtUserPwd->setFocus();
        }
    }
}

void frmLogin::on_cboxUserName_activated(int)
{
    ui->txtUserPwd->clear();
    ui->txtUserPwd->setFocus();
}