1. 程式人生 > 其它 >Qt編寫物聯網管理平臺31-使用者許可權管理

Qt編寫物聯網管理平臺31-使用者許可權管理

一、前言

隨著需求的不斷變化,功能的增多,在使用者資訊這塊,除了需要使用者登入退出驗證以外,還需要有個簡單的使用者許可權邏輯處理,比如限定某些使用者只有檢視許可權,沒有刪除記錄、清空記錄、系統設定的許可權,與之相對應的就是使用者資訊表中,儲存有該使用者具備哪些許可權,當該使用者登入成功以後,對應的許可權應用到各個介面邏輯中,一般都是在觸發了對應的顯示或者單擊後處理,比如不具備刪除記錄許可權,則在對應的刪除記錄程式碼中過濾處理,判斷當前登入的使用者是否具備該許可權,不具備則彈出提示,不做處理。還有一個就是切換介面的時候,沒有到該介面的許可權彈出提示,並仍然停留在上一個介面。

在十幾年的從業生涯中,最開始程式設計的時候,也做過簡單的許可權管理,思路極其簡單那就是根據使用者型別寫死,比如某個使用者是管理員型別,則具備所有許可權,某個使用者是操作員型別,則不能有刪除記錄、使用者管理的許可權。好處是容易理解,邏輯簡單到爆,缺點是程式碼寫死,不能動態控制某個擁有某個模組的許可權。暫且將這種處理叫做v0.1版本。

為了能夠更進一步的拓展功能,後面修改過使用者許可權管理,暫且稱為v0.2版本。在使用者資訊表中增加了一個使用者許可權欄位,字串表示 1|0|1 之類的,按照順序約定對應位是哪個模組,1表示有該模組的許可權,0表示沒有許可權,相對於v0.1版本的時候,可以控制不同模組的許可權,相對靈活一些,但是還是不夠通用,對約定的要求極其嚴格。

於是來到了現在的v0.3版本,索性增加了7個使用者許可權欄位,對應使用者7種模組許可權,至於該種許可權是對應哪個模組,填入對應的字串名稱就行,這樣可以做一個通用的許可權校驗功能,不用使用者許可權驗證程式碼寫的到處都是,使用者擁有該名稱的許可權則通過,不具備則彈出提示,一般常規的許可權就有系統設定、刪除記錄、使用者管理。

二、功能特點

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 "userhelper.h"
#include "quihelper.h"

QString UserHelper::CurrentUserName = "admin";
QString UserHelper::CurrentUserPwd = "admin";
QString UserHelper::CurrentUserType = QString::fromUtf8("管理員");
QList<bool> UserHelper::UserPermission = QList<bool>() << true << true << true << true << true << true << true;
QStringList UserHelper::PermissionName = QStringList() << QString::fromUtf8("系統設定|刪除記錄|模組A|模組B|模組C|模組D|模組E").split("|");

int UserHelper::UserInfo_Count = 0;
QList<QString> UserHelper::UserInfo_UserName = QList<QString>();
QList<QString> UserHelper::UserInfo_UserPwd = QList<QString>();
QList<QString> UserHelper::UserInfo_UserType = QList<QString>();
QList<QString> UserHelper::UserInfo_Permission1 = QList<QString>();
QList<QString> UserHelper::UserInfo_Permission2 = QList<QString>();
QList<QString> UserHelper::UserInfo_Permission3 = QList<QString>();
QList<QString> UserHelper::UserInfo_Permission4 = QList<QString>();
QList<QString> UserHelper::UserInfo_Permission5 = QList<QString>();
QList<QString> UserHelper::UserInfo_Permission6 = QList<QString>();
QList<QString> UserHelper::UserInfo_Permission7 = QList<QString>();

void UserHelper::loadUserInfo()
{
    UserHelper::UserInfo_Count = 0;
    UserHelper::UserInfo_UserName.clear();
    UserHelper::UserInfo_UserPwd.clear();
    UserHelper::UserInfo_UserType.clear();
    UserHelper::UserInfo_Permission1.clear();
    UserHelper::UserInfo_Permission2.clear();
    UserHelper::UserInfo_Permission3.clear();
    UserHelper::UserInfo_Permission4.clear();
    UserHelper::UserInfo_Permission5.clear();
    UserHelper::UserInfo_Permission6.clear();
    UserHelper::UserInfo_Permission7.clear();

    QString column = "Permission1,Permission2,Permission3,Permission4,Permission5,Permission6,Permission7";
    QString sql = QString("select UserName,UserPwd,UserType,%1 from UserInfo").arg(column);
    QSqlQuery query;
    if (!query.exec(sql)) {
        qDebug() << TIMEMS << query.lastError().text() << sql;
        return;
    }

    while (query.next()) {
        QString userName = query.value(0).toString();
        QString userPwd = query.value(1).toString();
        QString userType = query.value(2).toString();
        QString permission1 = query.value(3).toString();
        QString permission2 = query.value(4).toString();
        QString permission3 = query.value(5).toString();
        QString permission4 = query.value(6).toString();
        QString permission5 = query.value(7).toString();
        QString permission6 = query.value(8).toString();
        QString permission7 = query.value(9).toString();

        UserHelper::UserInfo_Count++;
        UserHelper::UserInfo_UserName << userName;
        UserHelper::UserInfo_UserPwd << userPwd;
        UserHelper::UserInfo_UserType << userType;
        UserHelper::UserInfo_Permission1 << permission1;
        UserHelper::UserInfo_Permission2 << permission2;
        UserHelper::UserInfo_Permission3 << permission3;
        UserHelper::UserInfo_Permission4 << permission4;
        UserHelper::UserInfo_Permission5 << permission5;
        UserHelper::UserInfo_Permission6 << permission6;
        UserHelper::UserInfo_Permission7 << permission7;
    }
}

void UserHelper::clearUserInfo()
{
    QString sql = "delete from UserInfo where UserName!='admin'";
    DbHelper::execSql(sql);
}

void UserHelper::updateUserInfo(const QString &userName, const QString &userPwd)
{
    QString sql = QString("update UserInfo set UserPwd='%1' where UserName='%2'").arg(userPwd).arg(userName);
    DbHelper::execSql(sql);
}

void UserHelper::getUserInfo()
{
    UserHelper::getUserInfo(UserHelper::CurrentUserName, UserHelper::CurrentUserPwd, UserHelper::CurrentUserType, UserHelper::UserPermission);
}

void UserHelper::getUserInfo(const QString &userName, QString &userPwd, QString &userType, QList<bool> &permission)
{
    QString column = "Permission1,Permission2,Permission3,Permission4,Permission5,Permission6,Permission7";
    QString sql = QString("select UserPwd,UserType,%1 from UserInfo where UserName='%2'").arg(column).arg(userName);
    QSqlQuery query;
    if (!query.exec(sql)) {
        qDebug() << TIMEMS << query.lastError().text() << sql;
        return;
    }

    if (query.next()) {
        userPwd = query.value(0).toString();
        userType = query.value(1).toString();
        for (int i = 0; i < 7; ++i) {
            permission[i] = (query.value(i + 2).toString() == "啟用");
        }
    }

    //qDebug() << TIMEMS << UserHelper::CurrentUserName << UserHelper::CurrentUserPwd << UserHelper::CurrentUserType << UserHelper::UserPermission;
}

bool UserHelper::checkPermission(const QString &text)
{
    //從許可權模組名稱找到當前模組是否需要授權
    //可能對應按鈕的文字有空格要去掉再比較 比如許可權文字設定的是 使用者管理 而實際按鈕是 用 戶 管 理
    QString flag = text;
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
    flag.remove(QRegularExpression("\\s"));
#else
    flag.remove(QRegExp("\\s"));
#endif
    int index = UserHelper::PermissionName.indexOf(flag);
    if (index >= 0) {
        if (!UserHelper::UserPermission.at(index)) {
            QUIHelper::showMessageBoxError(QString("當前使用者沒有 [%1] 許可權!").arg(text), 3);
            return false;
        }
    }

    return true;
}