Преглед изворни кода

消息 队列 和 一些自定义配置

zhuizhu пре 1 година
родитељ
комит
e9d6ed51b6
13 измењених фајлова са 550 додато и 10 уклоњено
  1. 2 0
      api/api.pri
  2. 56 0
      api/configapi.cpp
  3. 21 0
      api/configapi.h
  4. 24 0
      api/processapi.cpp
  5. 14 0
      api/processapi.h
  6. 7 0
      basemain.pro
  7. 147 0
      basemain_zh_CN.ts
  8. 44 5
      main.cpp
  9. 44 0
      messagequeue.cpp
  10. 52 0
      messagequeue.h
  11. 131 4
      processthread.cpp
  12. 7 0
      processthread.h
  13. 1 1
      updaterthread.cpp

+ 2 - 0
api/api.pri

@@ -1,4 +1,5 @@
 HEADERS += \
+    $$PWD/configapi.h \
     $$PWD/machine.h \
     $$PWD/processapi.h \
     $$PWD/student.h \
@@ -6,6 +7,7 @@ HEADERS += \
     $$PWD/tloginapi.h
 
 SOURCES += \
+    $$PWD/configapi.cpp \
     $$PWD/machine.cpp \
     $$PWD/processapi.cpp \
     $$PWD/student.cpp \

+ 56 - 0
api/configapi.cpp

@@ -0,0 +1,56 @@
+#include "configapi.h"
+
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonValue>
+#include <QNetworkAccessManager>
+#include <QUrlQuery>
+#include <basemainTr.h>
+
+#include <optional>
+
+#include "appevent.h"
+#include "qvariant.h"
+
+namespace TC {
+void critical(const QString &text, const QString &title = Tr::tr("Error"));
+std::optional<QJsonValue> sendRequest(QNetworkAccessManager::Operation op,
+                                      const QString &url,
+                                      const QByteArray &postData = QByteArray());
+
+static const QLatin1String scCode("code");
+static const QLatin1String scMessage("message");
+static const QLatin1String scData("data");
+static const QLatin1String scValue("value");
+
+ConfigApi::ConfigApi()
+    : url("/api/v1/sys/config/get_config_value")
+{}
+
+ConfigApi::ConfigApi(const QString &name)
+{
+    QUrl qurl("/api/v1/sys/config/get_config_value");
+    QUrlQuery query;
+    query.addQueryItem("name", name);
+    qurl.setQuery(query);
+    url = qurl.toString();
+}
+
+std::optional<QVariant> ConfigApi::get()
+{
+    std::optional<QJsonValue> responseData = sendRequest(QNetworkAccessManager::GetOperation, url);
+    if (!responseData.has_value()) {
+        return false;
+    }
+
+    const QJsonObject &object = responseData.value().toObject();
+
+    if (object.contains(scData)) {
+        const QJsonObject &data = object[scData].toObject();
+        if (data.contains(scValue)) {
+            return data[scValue].toVariant();
+        }
+    }
+    return std::nullopt;
+}
+} // namespace TC

+ 21 - 0
api/configapi.h

@@ -0,0 +1,21 @@
+#ifndef CONFIGAPI_H
+#define CONFIGAPI_H
+
+#include <QObject>
+#include "qvariant.h"
+#include <optional>
+namespace TC {
+class ConfigApi : public QObject
+{
+    Q_OBJECT
+public:
+    ConfigApi();
+    ConfigApi(const QString &name);
+
+    std::optional<QVariant> get();
+
+    QString url;
+    QByteArray sendData;
+};
+} // namespace TC
+#endif // CONFIGAPI_H

+ 24 - 0
api/processapi.cpp

@@ -1,5 +1,6 @@
 #include "processapi.h"
 
+#include "qjsonarray.h"
 #include "student.h"
 
 #include <QJsonDocument>
@@ -21,6 +22,7 @@ std::optional<QJsonValue> sendRequest(QNetworkAccessManager::Operation op,
 static const QLatin1String scCode("code");
 static const QLatin1String scMessage("message");
 static const QLatin1String scData("data");
+static const QLatin1String scList("list");
 
 ProcessApi::ProcessApi()
     : url("/api/v1/user_pid/addall")
@@ -67,4 +69,26 @@ bool ProcessApi::post()
     }
     return false;
 }
+
+ProcessNameApi::ProcessNameApi()
+    : url("/api/v1/process/listwithmachine")
+{}
+
+QJsonArray ProcessNameApi::get()
+{
+    std::optional<QJsonValue> responseData = sendRequest(QNetworkAccessManager::GetOperation,
+                                                         url,
+                                                         sendData);
+    if (!responseData.has_value()) {
+        return QJsonArray();
+    }
+    QJsonValue data;
+    const QJsonObject object = responseData.value().toObject();
+
+    if (object.contains(scList)) {
+        return object.value(scList).toArray();
+    }
+    return QJsonArray();
+}
+
 } // namespace TC

+ 14 - 0
api/processapi.h

@@ -18,5 +18,19 @@ public:
     QString url;
     QByteArray sendData;
 };
+
+class ProcessNameApi : public QObject
+{
+    Q_OBJECT
+public:
+    ProcessNameApi();
+
+    QJsonArray get();
+
+    QString url;
+    QByteArray sendData;
+};
+
+// is_prompt
 } // namespace TC
 #endif // PROCESSAPI_H

+ 7 - 0
basemain.pro

@@ -13,6 +13,7 @@ include($$PWD/qtsingleapplication/qtsingleapplication.pri)
 SOURCES += \
         appevent.cpp \
         main.cpp \
+        messagequeue.cpp \
         processmodel.cpp \
         processmonitor.cpp \
         processthread.cpp \
@@ -28,6 +29,7 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
 HEADERS += \
     appevent.h \
     basemainTr.h \
+    messagequeue.h \
     processmodel.h \
     processmonitor.h \
     processthread.h \
@@ -41,3 +43,8 @@ DESTDIR     = $$PWD/bin
 CONFIG(debug, debug|release) {
     TARGET = $$join(TARGET,,,d)
 }
+
+
+CONFIG += lrelease
+CONFIG += embed_translations
+TRANSLATIONS += basemain_zh_CN.ts

+ 147 - 0
basemain_zh_CN.ts

@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="zh_CN">
+<context>
+    <name>MachineCode</name>
+    <message>
+        <location filename="api/configapi.cpp" line="16"/>
+        <location filename="api/machine.cpp" line="15"/>
+        <location filename="api/processapi.cpp" line="17"/>
+        <location filename="api/tapi.cpp" line="55"/>
+        <location filename="api/tloginapi.cpp" line="14"/>
+        <source>Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="31"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="32"/>
+        <source>General Server Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="33"/>
+        <source>Invalid Request</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="34"/>
+        <source>Token Expired</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="35"/>
+        <source>Database Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="36"/>
+        <source>Username Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="37"/>
+        <source>Invalid Phone Format</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="38"/>
+        <source>Password Requirements Not Met</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="39"/>
+        <source>Phone Already Registered</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="40"/>
+        <source>Incorrect Credentials</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="41"/>
+        <source>Get Phone Code Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="42"/>
+        <source>Phone Code Exists</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="43"/>
+        <source>Phone Code Not Found</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="44"/>
+        <source>Correct Verification Code</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="45"/>
+        <source>Update Login Password Failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="46"/>
+        <source>Real Name Verification Failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="47"/>
+        <source>VIP Expiration Time Failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="67"/>
+        <source>information</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="api/tapi.cpp" line="120"/>
+        <location filename="api/tapi.cpp" line="124"/>
+        <source>Server Error</source>
+        <translation>服务器错误</translation>
+    </message>
+    <message>
+        <location filename="processthread.cpp" line="43"/>
+        <source>%1days%2hours%3minutes%4seconds</source>
+        <translation>%1天%2时%3分%4秒</translation>
+    </message>
+    <message>
+        <location filename="processthread.cpp" line="121"/>
+        <source>Tips</source>
+        <translation type="unfinished">提示</translation>
+    </message>
+</context>
+<context>
+    <name>MessageQueue</name>
+    <message>
+        <location filename="messagequeue.cpp" line="35"/>
+        <source>Tips</source>
+        <translation type="unfinished">提示</translation>
+    </message>
+</context>
+<context>
+    <name>ProcessThread</name>
+    <message>
+        <source>program %1 run time :%2</source>
+        <translation type="vanished">进程 %1 运行时间 :%2</translation>
+    </message>
+    <message>
+        <source>program %1 %3 run time :%2</source>
+        <translation type="obsolete">进程 %1 %3 运行时间 :%2</translation>
+    </message>
+    <message>
+        <location filename="processthread.cpp" line="203"/>
+        <source>Program %1 has been used for %2 minutes%3</source>
+        <oldsource>Program %1 has been used for %2 minutes, %3</oldsource>
+        <translation type="unfinished">程序%1已使用%2分钟%3</translation>
+    </message>
+</context>
+</TS>

+ 44 - 5
main.cpp

@@ -1,13 +1,19 @@
 #include <QApplication>
 #include <QCoreApplication>
 
+#include <QCommandLineParser>
 #include <QDebug>
 #include <QDir>
+#include <QLocale>
 #include <QProcess>
 #include <QSettings>
+#include <QTranslator>
 
+#include "messagequeue.h"
 #include "processthread.h"
 #include "qdatetime.h"
+#include "qmessagebox.h"
+#include "qobject.h"
 #include "qtsingleapplication.h"
 #include "updaterthread.h"
 
@@ -72,17 +78,50 @@ int main(int argc, char *argv[])
         return 0;
     }
     QDir dir;
-    dir.mkdir("log");          // 创建日志目录
-    addToStartup();            // 开机启动
+    dir.mkdir("log"); // 创建日志目录
+    addToStartup();   // 开机启动
 
     // redirectOutputToLogFile(); // 日志
+    a.setApplicationVersion("1.1.2");
+    a.setQuitOnLastWindowClosed(false);
 
-    a.setApplicationVersion("0.0.2");
+    QCommandLineParser parser;
+    parser.addHelpOption();
+    parser.addVersionOption();
+
+    QCommandLineOption debugOption("debug", "Enable debug mode");
+    parser.addOption(debugOption);
+    parser.process(a);
+
+    QTranslator translator;
+    const QStringList uiLanguages = QLocale::system().uiLanguages();
+    for (const QString &locale : uiLanguages) {
+        const QString baseName = "basemain_" + QLocale(locale).name();
+        if (translator.load(":/i18n/" + baseName)) {
+            a.installTranslator(&translator);
+            break;
+        }
+    }
 
     UpdaterThread thread;
-    thread.start();
     ProcessThread Process;
-    Process.start();
 
+    MessageQueue messageQueue;
+
+    QObject::connect(&Process, &ProcessThread::messageBox, &messageQueue, &MessageQueue::addMessage);
+    // QObject::connect(&Process, &ProcessThread::messageBox, [](const QString &text) {
+    //     QMetaObject::invokeMethod(
+    //         QApplication::instance(),
+    //         [text]() {
+    //             QMessageBox messageBox;
+    //             messageBox.setWindowModality(Qt::NonModal);
+    //             messageBox.setText(text);
+    //             messageBox.exec();
+    //         },
+    //         Qt::QueuedConnection);
+    // });
+    QObject::connect(&Process, &ProcessThread::finished, &Process, &QObject::deleteLater);
+    thread.start();
+    Process.start();
     return a.exec();
 }

+ 44 - 0
messagequeue.cpp

@@ -0,0 +1,44 @@
+#include "messagequeue.h"
+#include "qdebug.h"
+
+#include <QApplication>
+#include <QMessageBox>
+
+void MessageQueue::processQueue()
+{
+    if (isProcessing || messageQueue.isEmpty()) {
+        return;
+    }
+
+    isProcessing = true;
+    QString currentMessage = messageQueue.dequeue();
+
+    QVariant messageBoxPointX = this->messageBoxPointX;
+    QVariant messageBoxPointY = this->messageBoxPointY;
+    QVariant messageTitle = this->messageTitle;
+    qDebug() << "currentMessage" << currentMessage;
+    // 在主线程中显示消息框
+    QMetaObject::invokeMethod(
+        QApplication::instance(),
+        [this, currentMessage, messageBoxPointX, messageBoxPointY, messageTitle]() {
+            bool isokX = false;
+            bool isokY = false;
+            int x = messageBoxPointX.toInt(&isokX);
+            int y = messageBoxPointY.toInt(&isokY);
+            qDebug() << x << y << isokX << isokY;
+            QMessageBox *messageBox = new QMessageBox;
+            if (isokX && isokY) {
+                messageBox->move(x, y);
+            }
+            QString title = messageTitle.toString();
+            if (title.isEmpty()) {
+                title = tr("Tips");
+            }
+            messageBox->setWindowModality(Qt::NonModal);
+            messageBox->setText(currentMessage);
+            messageBox->setWindowTitle(title);
+            connect(messageBox, &QMessageBox::finished, this, &MessageQueue::onMessageBoxClosed);
+            messageBox->show();
+        },
+        Qt::QueuedConnection);
+}

+ 52 - 0
messagequeue.h

@@ -0,0 +1,52 @@
+#ifndef MESSAGEQUEUE_H
+#define MESSAGEQUEUE_H
+
+#include <QObject>
+#include <QQueue>
+#include <QVariant>
+#include "qdebug.h"
+
+class MessageQueue : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit MessageQueue(QObject *parent = nullptr)
+        : QObject(parent)
+        , isProcessing(false)
+    {}
+
+    // 向队列中添加消息
+    void addMessage(const QString &text,
+                    const QVariant &messageBoxPointX,
+                    const QVariant &messageBoxPointY,
+                    const QVariant &messageTitle)
+    {
+        qDebug() << text << messageBoxPointX << messageBoxPointY << messageTitle;
+        this->messageBoxPointX = messageBoxPointX;
+        this->messageBoxPointY = messageBoxPointY;
+        this->messageTitle = messageTitle;
+        messageQueue.enqueue(text);
+        processQueue();
+    }
+
+private:
+    QQueue<QString> messageQueue;
+    bool isProcessing;
+
+    // 处理队列中的消息
+    void processQueue();
+
+    QVariant messageBoxPointX;
+    QVariant messageBoxPointY;
+    QVariant messageTitle;
+private slots:
+    // 当消息框关闭时,继续处理队列中的下一个消息
+    void onMessageBoxClosed()
+    {
+        isProcessing = false;
+        processQueue();
+    }
+};
+
+#endif // MESSAGEQUEUE_H

+ 131 - 4
processthread.cpp

@@ -1,12 +1,19 @@
 #include "processthread.h"
+#include "api/configapi.h"
 #include "appevent.h"
 #include "processmodel.h"
 #include "qjsonarray.h"
 #include "qjsonobject.h"
 #include <cwf/sqldatabasestorage.h>
+#include <optional>
 
 #include "api/processapi.h"
 #include "qjsonvalue.h"
+#include "qlist.h"
+#include "qmessagebox.h"
+#include "qnamespace.h"
+
+#include "basemainTr.h"
 
 CWF::SqlDatabaseStorage storage("QSQLITE", "localhost", "postgres", "postgres", "1234", 5432);
 
@@ -25,8 +32,32 @@ static qint64 fileTimeToUnixTimestamp(FILETIME ft)
     }
     return ull.QuadPart / 10000000LL;
 }
+QString convertSecondsToTimeFormat(int totalSeconds)
+{
+    int days = totalSeconds / (24 * 3600);           // 计算天数
+    int hours = (totalSeconds % (24 * 3600)) / 3600; // 计算小时
+    int minutes = (totalSeconds % 3600) / 60;        // 计算分钟
+    int seconds = totalSeconds % 60;                 // 计算秒数
 
-void sendExitTime(qint64 updataTime)
+    // 返回格式化后的字符串,并使用 tr() 标记可翻译的文本
+    return QString(Tr::tr("%1days%2hours%3minutes%4seconds"))
+        .arg(days)
+        .arg(hours)
+        .arg(minutes)
+        .arg(seconds);
+}
+///
+/// \brief 转换到分钟
+/// \param totalSeconds
+/// \return
+///
+QString convertSecondsToMinutesTimeFormat(int totalSeconds)
+{
+    // 只计算分钟
+    int minutes = totalSeconds / 60;
+    return QString::number(minutes);
+}
+void ProcessThread::sendExitTime(qint64 updataTime)
 {
     ProcessModel processModel{storage};
     // 在数据库 获取 不是这个更新日期的数据
@@ -77,8 +108,67 @@ void sendExitTime(qint64 updataTime)
         time = timeVariant.toLongLong();
     } else {
         // 服务器时间
+        TC::ConfigApi configApi("swrunTime");
+        std::optional<QVariant> value = configApi.get();
+        if (value.has_value()) {
+            time = value.value().toInt();
+        }
+    }
+
+    QVariant messageBoxPointX = QVariant();
+    QVariant messageBoxPointY = QVariant();
+    QVariant messageText = QVariant("");
+    QVariant messageTitle = QVariant(Tr::tr("Tips"));
+    {
+        TC::ConfigApi configApi("messageBoxPointX");
+        std::optional<QVariant> value = configApi.get();
+        if (value.has_value()) {
+            messageBoxPointX = value.value().toInt();
+        }
     }
+    {
+        TC::ConfigApi configApi("messageBoxPointY");
+        std::optional<QVariant> value = configApi.get();
+        if (value.has_value()) {
+            messageBoxPointY = value.value().toInt();
+        }
+    }
+    {
+        TC::ConfigApi configApi("messageText");
+        std::optional<QVariant> value = configApi.get();
+        if (value.has_value()) {
+            messageText = value.value().toString();
+        }
+    }
+    {
+        TC::ConfigApi configApi("messageTitle");
+        std::optional<QVariant> value = configApi.get();
+        if (value.has_value()) {
+            messageTitle = value.value().toString();
+        }
+    }
+
+    QMap<QString, QString> messageProcessName;
 
+    TC::ProcessNameApi processNameApi;
+    QJsonArray array = processNameApi.get();
+    for (const auto item : array) {
+        if (item.isObject()) {
+            const auto object = item.toObject();
+
+            const QString name = object["name"].toString();
+            const QString zhName = object["chinese_name"].toString();
+            if (object.contains("is_prompt")) {
+                if (object["is_prompt"].toInt() == 2) {
+                    messageProcessName[name] = zhName;
+                };
+            }
+        }
+    }
+    // messageProcessName["WeChat.exe"] = "WeChat.exe";
+
+    // 提示
+    // SELECT * FROM ProcessTime  WHERE (updataTime - lastAlertTime) > 1565;
     if (time > 0) {
         CWF::SqlQueryManager qry(storage);
         qry.select("*", processModel.getTableName())
@@ -86,9 +176,46 @@ void sendExitTime(qint64 updataTime)
         qry.prepare();
         QJsonObject jsonObject = qry.exec();
         QJsonArray jsonArray = qry.toJson();
+
+        const QStringList keys = messageProcessName.keys();
+
+        for (const auto &value : jsonArray) {
+            // SLDWORKS.exe
+
+            const QJsonObject object = value.toObject();
+            const QString processName = object["processName"].toString();
+            const qint64 runTime = object["exitTime"].toVariant().toLongLong()
+                                   - object["creationTime"].toVariant().toLongLong();
+
+            for (const QString &key : keys) {
+                if (processName.compare(key, Qt::CaseSensitivity::CaseInsensitive) == 0) {
+                    // QVariant messageBoxPointX = QVariant();
+                    // QVariant messageBoxPointY = QVariant();
+                    // QVariant messageText = QVariant("");
+                    // QVariant messageTitle = QVariant(Tr::tr("Tips"));
+                    // Program A has been used for 20 minutes, please exercise
+
+                    // const QString text = QString(tr("program %1 %3 run time :%2")
+                    //                                  .arg(messageProcessName[key])
+                    //                                  .arg(convertSecondsToTimeFormat(runTime))
+                    //                                  .arg(messageText.toString()));
+
+                    const QString text = QString(tr("Program %1 has been used for %2 minutes%3")
+                                                     .arg(messageProcessName[key])
+                                                     .arg(convertSecondsToMinutesTimeFormat(runTime))
+                                                     .arg(messageText.toString()));
+                    emit messageBox(text, messageBoxPointX, messageBoxPointY, messageTitle);
+                }
+            }
+
+            // 更新 lastAlertTime
+            ProcessModel processModel{storage};
+            processModel.buildFromJson(object);
+            // 更新 消息时间
+            processModel.setLastAlertTime(updataTime);
+            processModel.save();
+        }
     }
-    // 提示
-    // SELECT * FROM ProcessTime  WHERE (updataTime - lastAlertTime) > 1565;
 }
 
 bool ProcessThread::upDataProcessSql()
@@ -137,7 +264,7 @@ bool ProcessThread::upDataProcessSql()
                 processModel.save();
             }
         }
-        qDebug().noquote().nospace() << jsonObject << qry.toJson();
+        // qDebug().noquote().nospace() << jsonObject << qry.toJson();
 
         // jsonObject.insert("begin_time", object["creationTime"]);
         // jsonObject.insert("end_time", object["exitTime"]);

+ 7 - 0
processthread.h

@@ -11,12 +11,19 @@ class ProcessThread : public QThread
     Q_OBJECT
 public:
     explicit ProcessThread(QObject *parent = nullptr);
+Q_SIGNALS:
+
+    void messageBox(const QString &text,
+                    const QVariant &messageBoxPointX,
+                    const QVariant &messageBoxPointY,
+                    const QVariant &messageTitle);
 
 private:
     bool upDataProcessSql();
 
 protected:
     void run() override;
+    void sendExitTime(qint64 updataTime);
 
     ProcessMonitor processMonitor;
 };

+ 1 - 1
updaterthread.cpp

@@ -15,7 +15,7 @@ bool isNetworkAvailable()
     QEventLoop loop;
 
     // 进行一个简单的GET请求
-    QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("http://ping.stem993.cn/ping")));
+    QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("http://ver.stem993.cn/ping")));
 
     // 等待直到请求完成
     QObject::connect(reply, &QNetworkReply::finished, [&]() { loop.quit(); });