Jelajahi Sumber

新增功能: 1. 工卡登录; 2. 人脸识别

xj 4 bulan lalu
induk
melakukan
c4c181e04c

+ 4 - 0
CMakeLists.txt

@@ -2,6 +2,10 @@ cmake_minimum_required(VERSION 3.16)
 
 project(LOTO)
 
+# # 强制制定C和C++编译器
+# set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc CACHE PATH "C Compiler" FORCE)
+# set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-g++ CACHE PATH "C++ Compiler" FORCE)
+
 set(CMAKE_AUTOUIC ON)
 set(CMAKE_AUTOMOC ON)
 set(CMAKE_AUTORCC ON)

+ 7 - 6
src/CMakeLists.txt

@@ -66,17 +66,16 @@ qt_add_qml_module(${PROJECT_NAME}
         qml/components/MBlurCard.qml
     SOURCES
         httpclient/HttpClient.h httpclient/HttpClient.cpp
+        httpclient/HttpPasswordLogin.h httpclient/HttpPasswordLogin.cpp
+        httpclient/HttpCardLogin.h httpclient/HttpCardLogin.cpp
     SOURCES
         interactive/InteractiveTask.h interactive/InteractiveTask.cpp
+        interactive/InteractiveData.h interactive/InteractiveData.cpp
+        interactive/InteractiveHttp.h interactive/InteractiveHttp.cpp
+        interactive/InteractiveFace.h interactive/InteractiveFace.cpp
     SOURCES
         usr/config.h usr/config.cpp
         usr/define.h
-
-        httpclient/HttpPasswordLogin.h httpclient/HttpPasswordLogin.cpp
-
-        interactive/InteractiveData.h interactive/InteractiveData.cpp
-        interactive/InteractiveHttp.h interactive/InteractiveHttp.cpp
-        # interactive/InteractiveFace.h interactive/InteractiveFace.cpp
 )
 
 qt_add_resources(${PROJECT_NAME} "resources"
@@ -142,6 +141,8 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
     Qt6::Multimedia
 )
 
+install(FILES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${PROJECT_NAME}
+        DESTINATION "/opt/Loto/Debug")
 
 
 

+ 119 - 0
src/httpclient/HttpCardLogin.cpp

@@ -0,0 +1,119 @@
+#include "HttpCardLogin.h"
+
+#include "config.h"
+#include "../interactive/InteractiveData.h"
+#include "../interactive/InteractiveHttp.h"
+
+#include <QEvent>
+#include <QKeyEvent>
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <unistd.h>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <cstring>
+
+HttpCardLogin::HttpCardLogin(QObject *parent)
+    : QThread(parent)
+{
+    m_pManager = new QNetworkAccessManager(this);
+    m_timer = new QTimer(this);
+    connect(m_timer, &QTimer::timeout, this, &HttpCardLogin::updateTime);
+}
+
+void HttpCardLogin::run()
+{
+    if (m_cardNfc.length() > 0) {
+        httpRequestCardLogin();
+    }
+}
+
+void HttpCardLogin::httpRequestCardLogin()
+{
+    QJsonObject jsonRoot;
+    QDateTime currentDateTime = QDateTime::currentDateTime();
+    qint64 timestampSeconds = currentDateTime.toMSecsSinceEpoch();
+
+    QString url = Config()->usernameLogin_url;
+    jsonRoot.insert("cardNfc", this->m_cardNfc);
+
+    QJsonDocument jsonDoc(jsonRoot);
+    QByteArray jsonData = jsonDoc.toJson(QJsonDocument::Compact);
+    qDebug() << "json=" << QString::fromUtf8(jsonData);
+
+    emit signalPostRequestData(timestampSeconds, url, jsonData, NULL, m_token);
+}
+
+void HttpCardLogin::slotHttpResponseCardLogin(QByteArray data)
+{
+    QJsonParseError error;
+    QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
+    if (error.error == QJsonParseError::NoError)
+    {
+        if(!(jsonDoc.isNull() || jsonDoc.isEmpty()))
+        {
+            QJsonObject rootObj = jsonDoc.object();
+            if(rootObj.contains("code"))
+            {
+                if(rootObj.value("code").toInt() == 200)
+                {
+                    if(rootObj.contains("token"))
+                    {
+                        QJsonValue value = rootObj.value("token");
+                        if(value.type() == QJsonValue::String)
+                        {
+                            GetInteractiveData()->m_token = value.toString();
+                            InteractiveHttp::strToken = value.toString();
+                            m_token = value.toString();
+                            QString username = "未知用户";
+                            if(rootObj.contains("nickName"))
+                            {
+                                QJsonValue name = rootObj.value("nickName");
+                                if(name.type() == QJsonValue::String)
+                                {
+                                    username = name.toString();
+                                }
+                            }
+                            if(rootObj.contains("userName"))
+                            {
+                                QJsonValue username = rootObj.value("userName");
+                                if(username.type() == QJsonValue::String)
+                                {
+                                    Config()->username = username.toString();
+                                }
+                            }
+                            if(rootObj.contains("userId"))
+                            {
+                                QJsonValue userId = rootObj.value("userId");
+                                if(userId.type() == QJsonValue::String)
+                                {
+                                    Config()->userId = userId.toString();
+                                }
+                            }
+                            Config()->username = username;
+                            emit signalLoginReturnStat(0, "登录成功");
+                            emit signalLoginReturnParam(username, 0);
+                            m_threadstatus = false;
+                        }
+                        else{
+                            emit signalLoginReturnStat(-3, "登录失败");
+                        }
+                    }
+                }
+                else{
+                    emit signalLoginReturnStat(-2, "用户不存在");
+                }
+            }
+        }
+    }
+    else{
+        emit signalLoginReturnStat(-3, "登录失败");
+    }
+}
+
+void HttpCardLogin::updateTime()
+{
+    m_timer->stop();
+}

+ 45 - 0
src/httpclient/HttpCardLogin.h

@@ -0,0 +1,45 @@
+#ifndef HTTPCARDLOGIN_H
+#define HTTPCARDLOGIN_H
+#include <QThread>
+#include <QtQml/qqml.h>
+#include <QNetworkAccessManager>
+#include <QTimer>
+
+class HttpCardLogin : public QThread
+{
+    Q_OBJECT
+    QML_NAMED_ELEMENT(HttpCardLogin)
+
+    Q_PROPERTY(QString cardNfc READ cardNfc WRITE setCardNfc)
+public:
+    explicit HttpCardLogin(QObject *parent = nullptr);
+
+    QString cardNfc()
+    {
+        return this->m_cardNfc;
+    }
+    void setCardNfc(const QString& cardNfc)
+    {
+        m_cardNfc = cardNfc;
+    }
+protected:
+    void run() override;
+private:
+    void httpRequestCardLogin(void);
+public slots:
+    void slotHttpResponseCardLogin(QByteArray data);
+    void updateTime(void);
+signals:
+    void signalPostRequestData(quint64 id, QString postUrl, QByteArray data, QByteArray file, QString token);
+    void signalLoginReturnStat(int stat, QString str);
+    void signalLoginReturnParam(QString name, int auth);
+private:
+    QNetworkAccessManager *m_pManager;
+private:
+    bool m_threadstatus = true;
+    QTimer *m_timer;
+    QString m_cardNfc;
+    QString m_token;
+};
+
+#endif // HTTPCARDLOGIN_H

+ 4 - 1
src/httpclient/HttpClient.cpp

@@ -405,7 +405,10 @@ void HttpClient::slotPostRequestData(quint64 id, QString postUrl, QByteArray dat
         m_mutex.unlock();
         m_workStat = httpWorkStat::httpWorkSleep;
         if(m_postUrl == Config()->usernameLogin_url) {
-            emit signalResponseLoginData(bb);
+            emit signalResponsePasswordLoginData(bb);
+        }
+        else if (m_postUrl == Config()->cardLogin_url) {
+            emit signalResponseCardLoginData(bb);
         }
     }
     else if(!this->m_httpFile.isNull())

+ 2 - 1
src/httpclient/HttpClient.h

@@ -37,7 +37,8 @@ public slots:
     void slotGetRequestData(quint64 id, QString postUrl, QByteArray data, QString token);
     void slotSetThreadStop(void);
 signals:
-    void signalResponseLoginData(QByteArray res);
+    void signalResponsePasswordLoginData(QByteArray res);
+    void signalResponseCardLoginData(QByteArray res);
 public:
     static QString sToken;
 private:

+ 1 - 0
src/httpclient/HttpFaceLogin.cpp

@@ -0,0 +1 @@
+#include "HttpFaceLogin.h"

+ 34 - 0
src/httpclient/HttpFaceLogin.h

@@ -0,0 +1,34 @@
+#ifndef HTTPFACELOGIN_H
+#define HTTPFACELOGIN_H
+#include <QThread>
+#include <QtQml/qqml.h>
+#include <QNetworkAccessManager>
+#include <QTimer>
+
+class HttpFaceLogin : public QThread
+{
+    Q_OBJECT
+    QML_NAMED_ELEMENT(HttpFaceLogin)
+
+public:
+    explicit HttpFaceLogin(QObject *parent = nullptr);
+
+protected:
+    void run() override;
+private:
+    void httpRequestFaceLogin(void);
+public slots:
+    void slotHttpResponseFaceLogin(QByteArray data);
+    void updateTime(void);
+signals:
+    void signalPostRequestData(quint64 id, QString postUrl, QByteArray data, QByteArray file, QString token);
+    void signalLoginReturnStat(int stat, QString str);
+    void signalLoginReturnParam(QString name, int auth);
+private:
+    QNetworkAccessManager *m_pManager;
+private:
+    bool m_threadstatus = true;
+    QTimer *m_timer;
+    QString m_token;
+};
+#endif // HTTPFACELOGIN_H

+ 0 - 1
src/httpclient/HttpPasswordLogin.cpp

@@ -35,7 +35,6 @@ void HttpPasswordLogin::httpRequestUsernameLogin()
     qDebug() << "json=" << QString::fromUtf8(jsonData);
 
     emit signalPostRequestData(timestampSeconds, url, jsonData, NULL, m_token);
-    m_threadstatus = false;
 }
 
 void HttpPasswordLogin::slotHttpResponseUsernameLogin(QByteArray data)

+ 0 - 1
src/httpclient/HttpPasswordLogin.h

@@ -46,7 +46,6 @@ signals:
 private:
     QNetworkAccessManager *m_pManager;
 private:
-    bool m_threadstatus = true;
     QTimer *m_timer;
     QString m_username;
     QString m_password;

+ 1 - 2
src/interactive/InteractiveData.h

@@ -1,6 +1,5 @@
 #ifndef INTERACTIVEDATA_H
 #define INTERACTIVEDATA_H
-
 #include <QMap>
 #include <QList>
 #include <QVector>
@@ -9,7 +8,7 @@
 #include <QReadWriteLock>
 #include <QReadLocker>
 #include <QWriteLocker>
-#include <QtQml/qqml.h>
+#include <QtQml>
 
 #define MATERIALS_TYPE_ALL "0"
 

+ 247 - 0
src/interactive/InteractiveFace.cpp

@@ -0,0 +1,247 @@
+#include "InteractiveFace.h"
+
+#include <QMediaDevices>
+#include <QRandomGenerator>
+#include <QTimerEvent>
+#include <QPainter>
+#include <QFont>
+#include <QPen>
+
+InteractiveFace* InteractiveFace::pInstance = nullptr;
+
+InteractiveFace::InteractiveFace(QObject *parent)
+    : QQuickImageProvider(QQuickImageProvider::Image)
+{
+    if (hasCamera())
+    {
+        // initCamera();
+    }
+    // 图像取1s 10帧
+    m_timerId = startTimer(100);
+}
+
+InteractiveFace::~InteractiveFace()
+{
+
+}
+
+QString InteractiveFace::getImageUrl()
+{
+    // image://InteractiveFaceImage/(0-9999)
+    return QString("image://") +
+           QString(INTERACTIVE_FACE_IMAGE_URL) +
+           QString("/") +
+           // 取随机数,确保图片刷新(Qt机制,两次url地址相同,图片不会显示)
+           QString::number(QRandomGenerator::global()->bounded(10000));
+}
+
+InteractiveFace *InteractiveFace::instance()
+{
+    if (!pInstance) {
+        pInstance = new InteractiveFace(nullptr);
+    }
+    return pInstance;
+}
+
+InteractiveFace *InteractiveFace::create(QQmlEngine *, QJSEngine *)
+{
+    return instance();
+}
+
+void InteractiveFace::setCameraImageGatherCallBack(QJSValue callback)
+{
+    m_imageGatherCallback = callback;
+}
+
+void InteractiveFace::setCameraImageAppearCallBack(QJSValue callback)
+{
+    m_imageAppearCallback = callback;
+}
+
+void InteractiveFace::setCameraImageRemainCallBack(QJSValue callback)
+{
+    m_imageRemainCallback = callback;
+}
+
+void InteractiveFace::setCameraImageCallBack(QJSValue gatherCallback, QJSValue appearCallback, QJSValue remainCallback)
+{
+    m_imageGatherCallback = gatherCallback;
+    m_imageAppearCallback = appearCallback;
+    m_imageRemainCallback = remainCallback;
+}
+
+void InteractiveFace::setCallBackFaceStatus(QJSValue isAppearCallback)
+{
+    m_isAppearCallback = isAppearCallback;
+}
+
+void InteractiveFace::cameraImagePlay()
+{
+    if (!hasCamera())
+    {
+        return;
+    }
+
+
+    if (!m_camera.isActive())
+    {
+        cameraPlay();
+        m_laseEpoch = 0;
+        m_laseCount = 0;
+
+        m_FrameId = 0;
+    }
+}
+
+void InteractiveFace::cameraImageStop()
+{
+    if (!hasCamera())
+    {
+        return;
+    }
+
+    cameraStop();
+}
+
+QImage InteractiveFace::getImage()
+{
+    QMutexLocker locker(&m_mutex);
+    return m_image.copy();
+}
+
+QImage InteractiveFace::requestImage(const QString &, QSize *, const QSize &)
+{
+    return m_image;
+}
+
+void InteractiveFace::timerEvent(QTimerEvent *event)
+{
+    if (event->timerId() == m_timerId)
+    {
+        if (!hasCamera())
+        {
+            return;
+        }
+
+        if (m_camera.isActive())
+        {
+            QMutexLocker locker(&m_mutex);
+            QVideoFrame currentFormat = m_videoSink.videoFrame();
+
+            QImage image;       // 图像
+            QPainter painter;   // 画笔
+
+            // 过滤无效帧, 前10帧不做处理
+            if(++m_FrameId <= 30)
+            {
+                m_image = image.copy();
+                if (m_imageGatherCallback.isCallable())
+                {
+                    QJSValueList args;
+                    args << getImageUrl();
+                    m_imageGatherCallback.call(args);
+                }
+                return;
+            }
+
+            if (currentFormat.isValid())
+            {
+                if (currentFormat.map(QVideoFrame::ReadOnly))
+                {
+                    image = currentFormat.toImage();
+                    // image = image.scaled(QSize(800, 600), Qt::KeepAspectRatio, Qt::SmoothTransformation);
+                }
+                currentFormat.unmap();
+            }
+
+            if (!image.isNull())
+            {
+                // image底部框
+                painter.begin(&image);
+                painter.setRenderHint(QPainter::Antialiasing);
+                painter.setFont(QFont("Arial", 24));
+                painter.setBrush(QColor(255, 255, 255, 127));
+                painter.setPen(Qt::NoPen);
+                painter.drawRect(QRect(0, image.height() - 50, image.width(), 50));
+
+                // TODO: 绘制人脸区域
+                // QImage convertedImage = image.convertToFormat(QImage::Format_RGB888);
+
+                painter.end();
+
+                m_image = image.copy();
+
+                if (m_imageGatherCallback.isCallable())
+                {
+                    QJSValueList args;
+                    args << getImageUrl();
+                    m_imageGatherCallback.call(args);
+                }
+            }
+        }
+    }
+}
+
+void InteractiveFace::initCamera()
+{
+    m_camera.setCameraDevice(QMediaDevices::defaultVideoInput());
+
+    QCameraDevice device = QMediaDevices::defaultVideoInput();
+    QList<QCameraFormat> formats = device.videoFormats();
+    // 选择最适合的格式
+    for (auto &format : formats)
+    {
+        // qDebug() << "fps---" << format.maxFrameRate() << format.resolution().width() << format.resolution().height();
+        if (format.maxFrameRate() >= 10.0 && format.resolution().width() % 4 == 0)
+        {
+            m_camera.setCameraFormat(format);
+            break;
+        }
+    }
+    m_session.setCamera(&m_camera);
+    m_session.setVideoSink(&m_videoSink);
+}
+
+void InteractiveFace::destroyCamera()
+{
+
+}
+
+bool InteractiveFace::hasCamera()
+{
+    return !QMediaDevices::videoInputs().isEmpty();
+}
+
+void InteractiveFace::cameraPlay()
+{
+    // 如果相机不是播放状态
+    if (!m_camera.isActive())
+    {
+        QCameraDevice cameraDevice = QMediaDevices::defaultVideoInput();
+        if (cameraDevice.isNull())
+        {
+            qWarning() << "系统中没有检测到任何摄像机设备";
+            return;
+        }
+
+        m_camera.setCameraDevice(cameraDevice);
+
+        m_session.setCamera(&m_camera);
+        m_session.setVideoSink(&m_videoSink);
+
+        m_camera.start();
+    }
+}
+
+void InteractiveFace::cameraStop()
+{
+    if (m_camera.isActive())
+    {
+        m_camera.stop();
+        m_camera.setActive(false);
+        m_camera.setCameraDevice(QCameraDevice());
+
+        m_session.setCamera(nullptr);
+        m_session.setVideoSink(nullptr);
+    }
+}

+ 97 - 0
src/interactive/InteractiveFace.h

@@ -0,0 +1,97 @@
+#ifndef INTERACTIVEFACE_H
+#define INTERACTIVEFACE_H
+#include <QQuickImageProvider>
+#include <QtQml>
+#include <QJSValue>
+#include <QMutex>
+#include <QImage>
+#include <QCamera>
+#include <QVideoSink>
+#include <QMediaCaptureSession>
+
+#define INTERACTIVE_FACE_IMAGE_URL "InteractiveFaceImage"
+
+class InteractiveFace : public QQuickImageProvider
+{
+    Q_OBJECT
+    QML_SINGLETON
+    QML_NAMED_ELEMENT(InteractiveFace)
+
+private:
+    InteractiveFace(QObject *parent = nullptr);
+    ~InteractiveFace();
+
+    // 获取图像url
+    QString getImageUrl();
+public:
+    static InteractiveFace* pInstance;
+    static InteractiveFace* instance();
+    static InteractiveFace* create(QQmlEngine*, QJSEngine*);
+
+    // 设置图像采集回调
+    Q_INVOKABLE void setCameraImageGatherCallBack(QJSValue callback);
+    // 设置发现人脸回调
+    Q_INVOKABLE void setCameraImageAppearCallBack(QJSValue callback);
+    // 设置人脸停留回调(5s)
+    Q_INVOKABLE void setCameraImageRemainCallBack(QJSValue callback);
+    // 回调函数设置
+    Q_INVOKABLE void setCameraImageCallBack(QJSValue gatherCallback, QJSValue appearCallback, QJSValue remainCallback);
+
+    // 发现人脸状态
+    Q_INVOKABLE void setCallBackFaceStatus(QJSValue isAppearCallback);
+
+    // 相机图像播放 (采集)
+    Q_INVOKABLE void cameraImagePlay();
+    // 相机图像停止 (采集)
+    Q_INVOKABLE void cameraImageStop();
+
+    // 获取图像
+    QImage getImage();
+protected:
+    QImage requestImage(const QString &, QSize *, const QSize &);
+
+    void timerEvent(QTimerEvent *event);
+private:
+    // 初始化相机
+    void initCamera();
+    // 销毁相机
+    void destroyCamera();
+
+    // 判断电脑上是否存在摄像头
+    bool hasCamera();
+
+
+    void cameraPlay();
+    void cameraStop();
+
+public:
+    QMutex m_mutex;
+
+private:
+    int m_timerId;      // 当前定时器ID
+    int m_FrameId;      // 帧过滤
+
+
+    QImage m_image;     // 图像
+
+    QCamera m_camera;   // 照相机
+
+    QVideoSink m_videoSink;         // 视频接收器
+    QMediaCaptureSession m_session; // 媒体连接器
+
+    // 记录信息
+    qint32 m_laseCount = 0;
+    qint64 m_laseEpoch = 0;
+
+    QJSValue m_imageGatherCallback; // 图像采集回调
+    QJSValue m_imageAppearCallback; // 发现人脸回调
+    QJSValue m_imageRemainCallback; // 人脸停留回调
+
+
+    QJSValue m_isAppearCallback;
+};
+
+inline InteractiveFace* GetInteractiveFace() {
+    return InteractiveFace::instance();
+}
+#endif // INTERACTIVEFACE_H

+ 1 - 0
src/interactive/InteractiveTask.cpp

@@ -0,0 +1 @@
+#include "InteractiveTask.h"

+ 4 - 0
src/interactive/InteractiveTask.h

@@ -0,0 +1,4 @@
+#ifndef INTERACTIVETASK_H
+#define INTERACTIVETASK_H
+
+#endif // INTERACTIVETASK_H

+ 66 - 3
src/qml/Login.qml

@@ -6,16 +6,19 @@ import QtQuick.Shapes
 import "./components"
 import Loto
 
-Item {
+Rectangle {
     id: control
     objectName: '__Login__'
 
     focus: true
+    color: "transparent"
+    Keys.enabled: true
 
     property bool loginSuccess: false
     property bool showErrorLogin: false
     property int errorNoticeTimeout: 3
     property string errorNoticText: "用户名密码错误"
+    property bool isCardInput: true
 
     property color loginCardColor: "#0A1929"
     property color loginIconColor: "#40C7FF"
@@ -33,7 +36,7 @@ Item {
 
         Component.onCompleted: {
             httpPasswordLogin.signalPostRequestData.connect(httpClientThread.slotPostRequestData);
-            httpClientThread.signalResponseLoginData.connect(httpPasswordLogin.slotHttpResponseUsernameLogin);
+            httpClientThread.signalResponsePasswordLoginData.connect(httpPasswordLogin.slotHttpResponseUsernameLogin);
         }
     }
 
@@ -50,6 +53,65 @@ Item {
         }
     }
 
+    HttpCardLogin {
+        id: httpCardLogin
+
+        Component.onCompleted: {
+            httpCardLogin.signalPostRequestData.connect(httpClientThread.slotPostRequestData);
+            httpClientThread.signalResponseCardLoginData.connect(httpCardLogin.slotHttpResponseCardLogin);
+        }
+    }
+
+    Connections {
+        target: httpCardLogin
+        function onSignalLoginReturnStat(stat, data) {
+            if(stat === 0) {
+                loginSuccess = true
+            } else {
+                showErrorLogin = true;
+                errorNoticeTimeout = 3;
+                errorNoticText = data;
+            }
+        }
+    }
+
+    function setCardNfcByKey(value) {
+        switch(value)
+        {
+        case Qt.Key_0: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "0";break;
+        case Qt.Key_1: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "1";break;
+        case Qt.Key_2: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "2";break;
+        case Qt.Key_3: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "3";break;
+        case Qt.Key_4: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "4";break;
+        case Qt.Key_5: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "5";break;
+        case Qt.Key_6: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "6";break;
+        case Qt.Key_7: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "7";break;
+        case Qt.Key_8: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "8";break;
+        case Qt.Key_9: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "9";break;
+        case Qt.Key_A: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "A";break;
+        case Qt.Key_B: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "B";break;
+        case Qt.Key_C: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "C";break;
+        case Qt.Key_D: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "D";break;
+        case Qt.Key_E: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "E";break;
+        case Qt.Key_F: httpCardLogin.cardNfc = httpCardLogin.cardNfc + "F";break;
+        case Qt.Key_Return: {
+            console.log("card:" + httpCardLogin.cardNfc);
+            if (httpCardLogin.cardNfc.length > 0) {
+                httpCardLogin.start();
+                httpCardLogin.cardNfc = "";
+            }
+            return
+        }
+        }
+    }
+
+    Keys.onReleased: {
+        console.log(event.key);
+        if (isCardInput) {
+            setCardNfcByKey(event.key);
+        }
+    }
+
     property Component faceInputDelegate: Rectangle {
         id: faceInputRect
         width: control.width
@@ -244,6 +306,7 @@ Item {
                         onClicked: {
                             loginInput.visible = false;
                             loginInput.sourceComponent = null;
+                            control.isCardInput = true;     // 不使用用户名密码输入后,开启工卡登录对象监听键盘事件
                         }
                     }
                 }
@@ -407,7 +470,7 @@ Item {
             textColor: loginTextColor
 
             onClicked: {
-                // TODO: 弹出用户登录界面
+                control.isCardInput = false;    // 防止工卡登录对象使用键盘事件
                 loginInput.sourceComponent = passwordInputDelegate;
                 loginInput.visible = true;
             }