diff --git a/AicsKnowledgeBase/qml/MainWindow.qml b/AicsKnowledgeBase/qml/MainWindow.qml index ff9d053..0e18052 100644 --- a/AicsKnowledgeBase/qml/MainWindow.qml +++ b/AicsKnowledgeBase/qml/MainWindow.qml @@ -26,22 +26,6 @@ FluWindow { } } - RowLayout { - id: tool_bar - anchors.top: parent.top - anchors.right: parent.right - anchors.rightMargin: 140 - - height: 44 - - layoutDirection: Qt.RightToLeft - - // Rectangle{ - // anchors.fill: parent - // color: "red" - // } - } - RowLayout { anchors.fill: parent @@ -101,10 +85,7 @@ FluWindow { onReady: { setTitleBarItem(title_bar) moveWindowToDesktopCenter() - setHitTestVisible(title_bar.minimizeButton()) - setHitTestVisible(title_bar.maximizeButton()) - setHitTestVisible(title_bar.closeButton()) - setHitTestVisible(title_bar.transferButton()) + title_bar.setHitTestVisibleItems(framless_helper) title_bar.maximizeButton.visible = true // window.backgroundVisible = false window.show() diff --git a/AicsKnowledgeBase/qml/component/CustomAppBar.qml b/AicsKnowledgeBase/qml/component/CustomAppBar.qml index 8e9c4c3..56ead21 100644 --- a/AicsKnowledgeBase/qml/component/CustomAppBar.qml +++ b/AicsKnowledgeBase/qml/component/CustomAppBar.qml @@ -110,6 +110,15 @@ Rectangle { } } + FluIconButton { + id: btn_note + height: 32 + width: 32 + Layout.rightMargin: 10 + iconSource: FluentIcons.PenPalette + iconSize: 14 + } + Text { Layout.margins: { right: 10 @@ -204,7 +213,10 @@ Rectangle { return btn_close } - function transferButton() { - return btn_transfer + function setHitTestVisibleItems(frameless_helper) { + frameless_helper.setHitTestVisible(btn_minimize) + frameless_helper.setHitTestVisible(btn_maximize) + frameless_helper.setHitTestVisible(btn_close) + frameless_helper.setHitTestVisible(btn_transfer) } } diff --git a/AicsKnowledgeBase/qml/component/FileList.qml b/AicsKnowledgeBase/qml/component/FileList.qml index 72e2165..642a41b 100644 --- a/AicsKnowledgeBase/qml/component/FileList.qml +++ b/AicsKnowledgeBase/qml/component/FileList.qml @@ -156,33 +156,33 @@ Item { } ListModel { id: fileListModel - // ListElement { - // title: "File 1" - // isDir: true - // brief: "This is a test file" - // type: "FOLDER" - // } - // ListElement { - // uid: "2" - // title: "File 2" - // isDir: false - // brief: "This is a test file" - // size: 500 - // type: "WORD" - // date: "2020-09-09" - // pageView: 100 - // stars: 10 - // } - // ListElement { - // uid: "3" - // title: "File 3" - // isDir: false - // brief: "This is a test file" - // type: "PPT" - // date: "2020-09-09" - // pageView: 100 - // size: 10200000022 - // stars: 10 - // } + ListElement { + title: "File 1" + isDir: true + brief: "This is a test file" + type: "FOLDER" + } + ListElement { + uid: "2" + title: "File 2" + isDir: false + brief: "This is a test file" + size: 500 + type: "WORD" + date: "2020-09-09" + pageView: 100 + stars: 10 + } + ListElement { + uid: "3" + title: "File 3" + isDir: false + brief: "This is a test file" + type: "PPT" + date: "2020-09-09" + pageView: 100 + size: 10200000022 + stars: 10 + } } } diff --git a/AicsKnowledgeBase/qml/component/TransferListPopup.qml b/AicsKnowledgeBase/qml/component/TransferListPopup.qml index 371103f..dece83f 100644 --- a/AicsKnowledgeBase/qml/component/TransferListPopup.qml +++ b/AicsKnowledgeBase/qml/component/TransferListPopup.qml @@ -16,52 +16,29 @@ Popup { FluShadow {} } - contentItem: Item { - anchors.top: parent.top + contentItem: FluScrollablePage { + anchors.fill: parent + anchors.topMargin: 10 + ColumnLayout { + Layout.fillWidth: true + Layout.bottomMargin: -10 + Repeater { + model: FileTransferListModel + delegate: ColumnLayout { + Layout.bottomMargin: 10 + spacing: 10 + width: parent.width + Text { + text: name + } - ListModel //模型-提供数据 - { - id: itemModel - ListElement { - - name: "Apple" - progressValue: 0.1 - } - ListElement { - name: "Orange" - progressValue: 1 - } - ListElement { - name: "Banana" - progressValue: 0.6 - } - } - - Component //委托-提供一个展示数据的示例(如何展示一个模型中的数据) - { - id: itemDelegate - - ColumnLayout { - spacing: 10 - width: parent.width - Text { - Layout.topMargin: 10 - text: name - } - - FluProgressBar { - Layout.fillWidth: true - progress: progressValue - indeterminate: false + FluProgressBar { + Layout.fillWidth: true + progress: completedSize / totalSize + indeterminate: false + } } } } - - ListView //视图-设置委托和模型,根据委托提供的展示方式展示模型提供的数据 - { - anchors.fill: parent - model: itemModel - delegate: itemDelegate - } } } diff --git a/AicsKnowledgeBase/qml/page/ContentPage.qml b/AicsKnowledgeBase/qml/page/ContentPage.qml index 3b081f1..626fdfb 100644 --- a/AicsKnowledgeBase/qml/page/ContentPage.qml +++ b/AicsKnowledgeBase/qml/page/ContentPage.qml @@ -5,13 +5,14 @@ import QtQuick.Controls import QtQuick.Controls.Basic import QtWebEngine 1.2 import FluentUI +import AicsKB.FileTransferManager FluArea { id: content_area paddings: 0 backgroundColor: "#f9f9f9" property string type: "" - property int knowledgeFileId + property string knowledgeFileId signal download(string knowledgeFileId) signal clickTags(string tagName) @@ -134,6 +135,7 @@ FluArea { } onClicked: { emit: content_area.download(content_area.knowledgeFileId) + FileTransferManager.download(content_area.knowledgeFileId) } } } @@ -148,7 +150,7 @@ FluArea { id: video_view FluMediaPlayer { Layout.fillWidth: true - implicitHeight: 270 + implicitHeight: width * 9 / 16. } } Component { diff --git a/AicsKnowledgeBase/qml/page/SearchPage.qml b/AicsKnowledgeBase/qml/page/SearchPage.qml index 9117b62..df66917 100644 --- a/AicsKnowledgeBase/qml/page/SearchPage.qml +++ b/AicsKnowledgeBase/qml/page/SearchPage.qml @@ -4,6 +4,7 @@ import QtQuick.Window import QtQuick.Controls import QtQuick.Controls.Basic import FluentUI +import "qrc:///AicsKnowledgeBase/qml/component" FluArea { property string url: '' @@ -13,8 +14,102 @@ FluArea { Layout.topMargin: 20 paddings: 10 - FluText { - Layout.topMargin: 20 - text: "Search" + // FluText { + // Layout.topMargin: 20 + // text: "Search" + // } + /* + 按标题,内容搜索 + */ + ColumnLayout{ + RowLayout{ + width:parent.width + FluDropDownButton{ + id:select_model + Layout.alignment: Qt.AlignLeft + text:"标题" + items:[ + FluMenuItem{ + text:"标题" + onClicked: { + select_model.text = text + } + }, + FluMenuItem{ + text:"内容" + onClicked: { + select_model.text = text + } + }, + FluMenuItem{ + text:"标签" + onClicked: { + select_model.text = text + } + } + ] + } + + FluTextBox{ + //placeholderText:"" + Layout.fillWidth: true + + + } + FluIconButton{ + Layout.alignment: Qt.AlignRight + iconSource:FluentIcons.Search + } + } + //按文件类型 + RowLayout{ + width:parent.width + FluText{ + Layout.alignment: Qt.AlignLeft + text:"格式: " + } + FluCheckBox{ + id:selectAllFormat + text:"all" + Component.onCompleted:{ + clicked() + } + onClicked:{ + selectPDFAndWord.checked=true + selectVideo.checked=true + selectPPT.checked=true + } + } + FluCheckBox{ + id:selectPDFAndWord + text:"pdf/word" + onClicked:{ + selectAllFormat.checked = selectPDFAndWord.checked && selectPPT.checked && selectVideo.checked + } + } + FluCheckBox{ + id:selectPPT + text:"ppt" + onClicked:{ + selectAllFormat.checked = selectPDFAndWord.checked && selectPPT.checked && selectVideo.checked + } + } + + FluCheckBox{ + id:selectVideo + text:"video" + onClicked:{ + selectAllFormat.checked = selectPDFAndWord.checked && selectPPT.checked && selectVideo.checked + } + } + } + + + Rectangle{ + FileList{ + + } + } + } } diff --git a/AicsKnowledgeBase/src/FileTransferListModel.cpp b/AicsKnowledgeBase/src/FileTransferListModel.cpp new file mode 100644 index 0000000..b079988 --- /dev/null +++ b/AicsKnowledgeBase/src/FileTransferListModel.cpp @@ -0,0 +1,85 @@ +#include "FileTransferListModel.h" + +FileTransferListModel::FileTransferListModel(QObject *parent) + : QAbstractListModel(parent) +{ + m_roleName.insert(kIdRole, "fileId"); + m_roleName.insert(kNameRole, "name"); + m_roleName.insert(kCompletedSizeRole, "completedSize"); + m_roleName.insert(kTotalSizeRole, "totalSize"); + + m_data = { + {"v", "vivo", 1200, 2000}, + {"m", "meizu", 1300, 1500}, + {"a", "apple", 1400, 1400}, + }; + + +} + + +int FileTransferListModel::rowCount(const QModelIndex &parent) const +{ + // For list models only the root node (an invalid parent) should return the list's size. For all + // other (valid) parents, rowCount() should return 0 so that it does not become a tree model. + if (parent.isValid()) + return 0; + + return m_data.size(); +} + +QVariant FileTransferListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + switch (role) { + case kIdRole: + return m_data.value(index.row()).id; + case kNameRole: + return m_data.value(index.row()).name; + case kCompletedSizeRole: + return m_data.value(index.row()).completedSize; + case kTotalSizeRole: + return m_data.value(index.row()).totalSize; + default: + break; + } + + return QVariant(); + +} + +QHash FileTransferListModel::roleNames() const +{ + return m_roleName; +} + +QAbstractItemModel *FileTransferListModel::model() +{ + return this; +} + + + +void FileTransferListModel::insertItem(const FileItem &item) +{ + beginInsertRows(QModelIndex(), 0, 0); + m_data.push_front(item); + endInsertRows(); +} + +void FileTransferListModel::setItem(const FileItem &item) +{ + auto iter = std::find_if(m_data.begin(), m_data.end(), [&item](FileItem &i) { + return i.id == item.id; + }); + + if (iter != m_data.end()) { + int row = iter - m_data.begin(); + *iter = item; + emit dataChanged(createIndex(row, 0), createIndex(row, 0)); + } +} + + diff --git a/AicsKnowledgeBase/src/FileTransferListModel.h b/AicsKnowledgeBase/src/FileTransferListModel.h new file mode 100644 index 0000000..092e357 --- /dev/null +++ b/AicsKnowledgeBase/src/FileTransferListModel.h @@ -0,0 +1,47 @@ +#ifndef AICSKNOWLEDGEBASE_FILETRANSFERLISTMODEL_H +#define AICSKNOWLEDGEBASE_FILETRANSFERLISTMODEL_H + +#include + +struct FileItem +{ + QString id; + QString name; + int completedSize; + int totalSize; +}; + + +class FileTransferListModel : public QAbstractListModel +{ +Q_OBJECT + +public: + explicit FileTransferListModel(QObject *parent = nullptr); + + // Basic functionality: + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + QHash roleNames() const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + void insertItem(const FileItem &item); + + void setItem(const FileItem &item); + + Q_INVOKABLE QAbstractItemModel *model(); + + enum FileItemRole + { + kIdRole = Qt::UserRole + 1, + kNameRole, + kCompletedSizeRole, + kTotalSizeRole + }; +private: + QList m_data; + QHash m_roleName; +}; + +#endif // AICSKNOWLEDGEBASE_FILETRANSFERLISTMODEL_H diff --git a/AicsKnowledgeBase/src/FileTransferManager.cpp b/AicsKnowledgeBase/src/FileTransferManager.cpp index 9184507..ff98641 100644 --- a/AicsKnowledgeBase/src/FileTransferManager.cpp +++ b/AicsKnowledgeBase/src/FileTransferManager.cpp @@ -5,12 +5,59 @@ #include "FileTransferManager.h" #include #include +#include +#include -FileTransferManager::FileTransferManager(QObject *parent) : QObject(parent) +static const std::string baseUrl = "http://127.0.0.1:4523/m1/2914957-0-default/"; + +static size_t writeDataCallback(void *contents, size_t size, size_t nmemb, void *userp) +{ + try { + size_t realSize = size * nmemb; + static int current_index = 0; + int content_size = nmemb * size; + std::string result = std::string((char *) contents, content_size); + auto *pStr = (std::string *) userp; + if (pStr) { + (*pStr).append(result); + } + return realSize; + } + catch (...) {} + return 0; +} + +CURLcode httpGet(const std::string &url, std::string &response, int timeout = 3000) +{ + CURLcode res; + + // 获取easy handle + CURL *easy_handle = curl_easy_init(); + if (nullptr == easy_handle) { + curl_global_cleanup(); + return CURLE_FAILED_INIT; + } + // 设置easy handle属性 + //curl_easy_setopt(easy_handle, CURLOPT_HTTP_VERSION, (long) CURL_HTTP_VERSION_3ONLY); + curl_easy_setopt(easy_handle, CURLOPT_URL, (baseUrl + url).c_str()); + curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, writeDataCallback); + curl_easy_setopt(easy_handle, CURLOPT_TIMEOUT, timeout); + curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, (void *) &response); + curl_easy_setopt(easy_handle, CURLOPT_FOLLOWLOCATION, 1L); + //curl_easy_setopt(easy_handle, CURLOPT_DEFAULT_PROTOCOL, "https"); + // 执行数据请求 + res = curl_easy_perform(easy_handle); + curl_easy_cleanup(easy_handle); + return res; +} + +FileTransferManager::FileTransferManager(FileTransferListModel &model, QObject *parent) + : model(model), QObject(parent) { } + void FileTransferManager::upload(QUrl fileUrl) { qDebug() << fileUrl.fileName(); @@ -19,7 +66,7 @@ void FileTransferManager::upload(QUrl fileUrl) CURL *curl; CURLcode res; curl = curl_easy_init(); - if(curl) { + if (curl) { curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:4523/m1/2914957-0-default/"); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); @@ -49,3 +96,42 @@ void FileTransferManager::upload(QUrl fileUrl) curl_easy_cleanup(curl); } +void FileTransferManager::download(QString fileId) +{ + static int _fileId = 0; + fileId = QString::number(_fileId++); + + QtConcurrent::run([fileId, this] { + qDebug() << "Start Get"; + std::string resData; + if (CURLE_OK != httpGet(fileId.toStdString() + "/status", resData)) + return; + + qDebug() << resData.c_str(); + auto resJson = QJsonDocument::fromJson(resData.c_str()); + //if(!resJson["isCompleted"].toBool()) + // return; + + int size = resJson["size"].toInt(); + FileItem item{fileId, resJson["md5"].toString(), 0, size}; + QTimer::singleShot(0, qApp, [this, item]() { + model.insertItem(item); + }); + + while (item.completedSize < item.totalSize) { + item.completedSize += 1; + QTimer::singleShot(0, qApp, [this, item]() { + model.setItem(item); + }); + + using namespace std::chrono_literals; + std::this_thread::sleep_for(100ms); + } + + + qDebug() << "End Get"; + }); + + +} + diff --git a/AicsKnowledgeBase/src/FileTransferManager.h b/AicsKnowledgeBase/src/FileTransferManager.h index 21bb2c5..8c438c2 100644 --- a/AicsKnowledgeBase/src/FileTransferManager.h +++ b/AicsKnowledgeBase/src/FileTransferManager.h @@ -8,14 +8,20 @@ #include #include +#include "FileTransferListModel.h" -class FileTransferManager: public QObject +class FileTransferManager : public QObject { Q_OBJECT public: - explicit FileTransferManager(QObject *parent = nullptr); + explicit FileTransferManager(FileTransferListModel &model, QObject *parent = nullptr); + Q_INVOKABLE void upload(QUrl fileUrl); + Q_INVOKABLE void download(QString fileId); + +private: + FileTransferListModel &model; }; diff --git a/AicsKnowledgeBase/src/main.cpp b/AicsKnowledgeBase/src/main.cpp index c7f388e..731c748 100644 --- a/AicsKnowledgeBase/src/main.cpp +++ b/AicsKnowledgeBase/src/main.cpp @@ -7,13 +7,19 @@ #include #include #include +#include #include "HttpClient.h" #include "FileTransferManager.h" +#include "FileTransferListModel.h" FRAMELESSHELPER_USE_NAMESPACE int main(int argc, char *argv[]) { + if (CURLE_OK != curl_global_init(CURL_GLOBAL_DEFAULT)) + return CURLE_FAILED_INIT; + + //将样式设置为Basic,不然会导致组件显示异常 qputenv("QT_QUICK_CONTROLS_STYLE", "Basic"); @@ -38,8 +44,12 @@ int main(int argc, char *argv[]) QQmlApplicationEngine engine; FramelessHelper::Quick::registerTypes(&engine); + + FileTransferListModel fileTransferListModel; + engine.rootContext()->setContextProperty("FileTransferListModel", &fileTransferListModel); + auto httpClient = new HttpClient(engine); - auto fileTransferManager = new FileTransferManager(); + auto fileTransferManager = new FileTransferManager(fileTransferListModel); qmlRegisterSingletonInstance("AicsKB.HttpClient", 1, 0, "HttpClient", httpClient); qmlRegisterSingletonInstance("AicsKB.FileTransferManager", 1, 0, "FileTransferManager", @@ -56,6 +66,6 @@ int main(int argc, char *argv[]) auto result = QGuiApplication::exec(); httpClient->deleteLater(); fileTransferManager->deleteLater(); - + curl_global_cleanup(); return result; }