From 81624c2b5e166cb465b8528760f9600c2e806c42 Mon Sep 17 00:00:00 2001 From: wuyize Date: Thu, 6 Jul 2023 14:14:24 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AicsKnowledgeBase/qml/component/FileList.qml | 42 +---- .../qml/component/FileListItem.qml | 6 +- .../qml/component/UploadButton.qml | 146 ++++++++++++++++++ AicsKnowledgeBase/src/FileTransferManager.cpp | 93 ++++++++--- 4 files changed, 220 insertions(+), 67 deletions(-) create mode 100644 AicsKnowledgeBase/qml/component/UploadButton.qml diff --git a/AicsKnowledgeBase/qml/component/FileList.qml b/AicsKnowledgeBase/qml/component/FileList.qml index e992e3e..a5ae3b8 100644 --- a/AicsKnowledgeBase/qml/component/FileList.qml +++ b/AicsKnowledgeBase/qml/component/FileList.qml @@ -44,46 +44,10 @@ Item { "uuid": uuid }]) } - FluButton { - Layout.alignment: Qt.AlignRight - text: "上传" - onClicked: function () { - console.log("click") - fileDialog.open() - } - FileDialog { - id: fileDialog - onAccepted: function () { - let name = FileTransferManager.getFileName(selectedFile) - const size = FileTransferManager.getFileSize( - selectedFile) - const md5 = FileTransferManager.getFileMd5(selectedFile) - if (size <= 0 || md5 === '') - return - var body = { - "name": name, - "brief": "brief", - "size": size, - "md5": md5, - "tags": [], - "parentId": header.items.length - !== 0 ? header.items[header.items.length - 1].uuid : null - } - console.log("begin") - console.log(JSON.stringify(body)) - Request.post("knowledge/file", JSON.stringify(body), - function (res, data) { - console.log(res) - console.log(data) - FileTransferManager.upload( - selectedFile, data.id, - data.ticket, name) - }, function (res, data) { - console.log(res) - }) - } - } + UploadButton { + header: header } + RowLayout { id: fileListItemHeaderItem width: ListView.view.width diff --git a/AicsKnowledgeBase/qml/component/FileListItem.qml b/AicsKnowledgeBase/qml/component/FileListItem.qml index 7516c72..2eaab06 100644 --- a/AicsKnowledgeBase/qml/component/FileListItem.qml +++ b/AicsKnowledgeBase/qml/component/FileListItem.qml @@ -39,13 +39,13 @@ FluArea { Image { id: icon source: type ? "qrc:/AicsKnowledgeBase/res/" + type + ".png" : "" - Layout.preferredHeight: 32 - Layout.preferredWidth: 32 + Layout.preferredHeight: 24 + Layout.preferredWidth: 24 } FluText { id: title font.bold: true - font.pointSize: 15 + font.pointSize: 12 text: fileItem.title } } diff --git a/AicsKnowledgeBase/qml/component/UploadButton.qml b/AicsKnowledgeBase/qml/component/UploadButton.qml new file mode 100644 index 0000000..200c825 --- /dev/null +++ b/AicsKnowledgeBase/qml/component/UploadButton.qml @@ -0,0 +1,146 @@ +import QtQuick 2.15 +import QtQuick.Layouts +import FluentUI +import QtQuick.Dialogs +import "qrc:///AicsKnowledgeBase/qml/global" +import SignalFileOperation 1.0 +import AicsKB.FileTransferManager + +FluButton { + property var header + property var currentSelectedFile: null + + Layout.alignment: Qt.AlignRight + text: "上传" + onClicked: function () { + console.log("click") + fileDialog.open() + } + FileDialog { + id: fileDialog + onAccepted: function () { + currentSelectedFile = selectedFile + popup.open() + } + onRejected: currentSelectedFile = null + } + + FluPopup { + id: popup + focus: true + Rectangle { + id: layout_content + anchors.fill: parent + implicitWidth: Window.window == null ? 400 : Math.min( + Window.window.width, 400) + + implicitHeight: text_title.height + text_message.height + layout_actions.height + color: 'transparent' + radius: 5 + FluText { + id: text_title + font: FluTextStyle.TitleLarge + text: "上传知识文件" + topPadding: 20 + leftPadding: 20 + rightPadding: 20 + wrapMode: Text.WrapAnywhere + anchors { + top: parent.top + left: parent.left + right: parent.right + } + } + FluText { + id: text_message + font: FluTextStyle.Body + wrapMode: Text.WrapAnywhere + text: "content" + topPadding: 14 + leftPadding: 20 + rightPadding: 20 + bottomPadding: 14 + anchors { + top: text_title.bottom + left: parent.left + right: parent.right + } + } + Rectangle { + id: layout_actions + height: 68 + radius: 5 + color: FluTheme.dark ? Qt.rgba( + 32 / 255, 32 / 255, 32 / 255, + blurBackground ? blurOpacity - 0.4 : 1) : Qt.rgba( + 243 / 255, 243 / 255, 243 / 255, + blurBackground ? blurOpacity - 0.4 : 1) + anchors { + top: text_message.bottom + left: parent.left + right: parent.right + } + RowLayout { + anchors { + centerIn: parent + margins: spacing + fill: parent + } + spacing: 15 + FluButton { + id: negative_btn + Layout.fillWidth: true + Layout.fillHeight: true + text: "取消" + onClicked: { + popup.close() + } + } + FluFilledButton { + id: positive_btn + Layout.fillWidth: true + Layout.fillHeight: true + text: "上传" + onClicked: { + popup.close() + let name = FileTransferManager.getFileName( + currentSelectedFile) + const size = FileTransferManager.getFileSize( + currentSelectedFile) + const md5 = FileTransferManager.getFileMd5( + currentSelectedFile) + if (size <= 0 || md5 === '') + return + var body = { + "name": name, + "brief": "brief", + "size": size, + "md5": md5, + "tags": [], + "parentId": currentParentId() + } + console.log("begin") + console.log(JSON.stringify(body)) + Request.post("knowledge/file", + JSON.stringify(body), + function (res, data) { + console.log(res) + console.log(data) + FileTransferManager.upload( + currentSelectedFile, + data.id, data.ticket, + name) + }, function (res, data) { + console.log(res) + }) + } + } + } + } + } + } + + function currentParentId() { + return header.items.length !== 0 ? header.items[header.items.length - 1].uuid : null + } +} diff --git a/AicsKnowledgeBase/src/FileTransferManager.cpp b/AicsKnowledgeBase/src/FileTransferManager.cpp index 2f68638..592df5c 100644 --- a/AicsKnowledgeBase/src/FileTransferManager.cpp +++ b/AicsKnowledgeBase/src/FileTransferManager.cpp @@ -30,6 +30,24 @@ struct FileUploading : FileItem std::unordered_map uploadingMap; std::mutex uploadingMapMutex; +CURL *initCurlWithCommonOptions() +{ + CURL *curl = curl_easy_init(); + if (!curl) { + qCritical() << "CURL INIT FAILED!"; + return nullptr; + } + curl_easy_setopt(curl, CURLOPT_VERBOSE, true); + curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3000); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true); + curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https"); + //curl_easy_setopt(easy_handle, CURLOPT_SSL_VERIFYPEER, 0L); + //curl_easy_setopt(easy_handle, CURLOPT_SSL_VERIFYHOST, 0L);//不验证证书和HOST + return curl; +} + + size_t writeDataFunc(const void *ptr, size_t size, size_t nmemb, void *obj) { auto buf = (FileDownloading *) obj; @@ -41,9 +59,8 @@ size_t writeDataFunc(const void *ptr, size_t size, size_t nmemb, void *obj) size_t readDataFunc(void *ptr, size_t size, size_t nmemb, void *obj) { auto buf = (FileUploading *) obj; - auto readSize = size * nmemb; - buf->file.read(reinterpret_cast(ptr), readSize); - return readSize; + buf->file.read(reinterpret_cast(ptr), size * nmemb); + return buf->file.gcount(); } static int xferinfo(void *p, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) @@ -113,25 +130,18 @@ static size_t writeDataCallback(void *contents, size_t size, size_t nmemb, void } CURLcode -httpGet(const std::string &url, std::string &response, long httpVersion = CURL_HTTP_VERSION_3ONLY, int timeout = 3000) +httpGet(const std::string &url, std::string &response) { CURLcode res; // 获取easy handle - CURL *easy_handle = curl_easy_init(); + CURL *easy_handle = initCurlWithCommonOptions(); if (!easy_handle) return CURLE_FAILED_INIT; - // 设置easy handle属性 - curl_easy_setopt(easy_handle, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(easy_handle, CURLOPT_HTTP_VERSION, httpVersion); 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"); - //curl_easy_setopt(easy_handle, CURLOPT_SSL_VERIFYPEER, 0L); - //curl_easy_setopt(easy_handle, CURLOPT_SSL_VERIFYHOST, 0L);//不验证证书和HOST + // 执行数据请求 res = curl_easy_perform(easy_handle); curl_easy_cleanup(easy_handle); @@ -148,12 +158,40 @@ FileTransferManager::FileTransferManager(QObject *parent) qDebug() << "HTTP3 FAILED"; } +bool uploadComplete(const QString &fileId, const QString &ticket) +{ + CURLcode res; + auto curlHandle = initCurlWithCommonOptions(); + if (!curlHandle) return false; + + curl_httppost *formpost = nullptr; + curl_httppost *lastptr = nullptr; + curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "ticket", + CURLFORM_COPYCONTENTS, ticket.toStdString().c_str(), + CURLFORM_END); + + curl_easy_setopt(curlHandle, CURLOPT_URL, (baseUrl + "File/" + fileId.toStdString() + "/complete").c_str()); + curl_easy_setopt(curlHandle, CURLOPT_HTTPPOST, formpost); + + res = curl_easy_perform(curlHandle); + curl_easy_cleanup(curlHandle); + curl_formfree(formpost); + return res == CURLE_OK; +} + void FileTransferManager::upload(const QUrl &fileUrl, const QString &fileId, const QString &ticket, const QString &fileName) { qDebug() << fileUrl.fileName(); QtConcurrent::run([fileUrl, fileId, ticket, fileName] { + std::string resData; + if (CURLE_OK != httpGet("File/" + fileId.toStdString() + "/status", resData)) + return false; + + qDebug() << resData.c_str(); + auto resJson = QJsonDocument::fromJson(resData.c_str()); + //if(!resJson["isCompleted"].toBool()) auto fileSize = QFileInfo(fileUrl.toLocalFile()).size(); @@ -176,7 +214,7 @@ FileTransferManager::upload(const QUrl &fileUrl, const QString &fileId, const QS } CURLcode res; - fileUploading.curlHandle = curl_easy_init(); + fileUploading.curlHandle = initCurlWithCommonOptions(); if (!fileUploading.curlHandle) return false; @@ -194,27 +232,33 @@ FileTransferManager::upload(const QUrl &fileUrl, const QString &fileId, const QS CURLFORM_END); curl_formadd(&formpost, &lastptr, - CURLFORM_COPYNAME, "data", + CURLFORM_COPYNAME, "file", + CURLFORM_FILENAME, fileName.toLocal8Bit().toStdString().c_str(), CURLFORM_STREAM, &fileUploading, CURLFORM_CONTENTLEN, fileSize, CURLFORM_END); - curl_easy_setopt(fileUploading.curlHandle, CURLOPT_URL, (baseUrl + fileId.toStdString()).c_str()); - curl_easy_setopt(fileUploading.curlHandle, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(fileUploading.curlHandle, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(fileUploading.curlHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3ONLY); + curl_easy_setopt(fileUploading.curlHandle, CURLOPT_URL, (baseUrl + "File/" + fileId.toStdString()).c_str()); curl_easy_setopt(fileUploading.curlHandle, CURLOPT_HTTPPOST, formpost); curl_easy_setopt(fileUploading.curlHandle, CURLOPT_READFUNCTION, readDataFunc); curl_easy_setopt(fileUploading.curlHandle, CURLOPT_NOPROGRESS, false); curl_easy_setopt(fileUploading.curlHandle, CURLOPT_XFERINFOFUNCTION, uploadInfo); curl_easy_setopt(fileUploading.curlHandle, CURLOPT_XFERINFODATA, &fileUploading); + curl_easy_setopt(fileUploading.curlHandle, CURLOPT_WRITEFUNCTION, writeDataCallback); + std::string response; + curl_easy_setopt(fileUploading.curlHandle, CURLOPT_WRITEDATA, (void *) &response); qDebug() << "Begin Upload"; + qDebug() << ticket.toStdString().c_str(); + qDebug() << std::to_string(fileSize).c_str(); + + res = curl_easy_perform(fileUploading.curlHandle); if (res == CURLE_OK) qDebug() << "Upload Success"; else qDebug() << "Upload Failed"; + qDebug() << response.c_str(); curl_easy_cleanup(fileUploading.curlHandle); curl_formfree(formpost); fileUploading.file.close(); @@ -223,6 +267,8 @@ FileTransferManager::upload(const QUrl &fileUrl, const QString &fileId, const QS uploadingMap.erase(fileId); uploadingMapMutex.unlock(); + if (res == CURLE_OK) + uploadComplete(fileId, ticket); }); } @@ -231,11 +277,10 @@ curl_off_t getHttpFileSize(const std::string &url) { curl_off_t fileLength = 0; - CURL *handle = curl_easy_init(); + CURL *handle = initCurlWithCommonOptions(); curl_easy_setopt(handle, CURLOPT_URL, url.c_str()); curl_easy_setopt(handle, CURLOPT_HEADER, 0); //只需要header头 curl_easy_setopt(handle, CURLOPT_NOBODY, 1); //不需要body - curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L); if (curl_easy_perform(handle) == CURLE_OK) curl_easy_getinfo(handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &fileLength); @@ -261,7 +306,7 @@ bool httpDownload(const std::string &url, const FileItem &item) FileDownloading &obj = iter->second; - obj.curlHandle = curl_easy_init(); + obj.curlHandle = initCurlWithCommonOptions(); if (!obj.curlHandle) return false; obj.totalSize = fileSize;//原始文件大小 @@ -273,10 +318,8 @@ bool httpDownload(const std::string &url, const FileItem &item) return false; } - curl_easy_setopt(obj.curlHandle, CURLOPT_VERBOSE, 0L); curl_easy_setopt(obj.curlHandle, CURLOPT_HEADER, 0); curl_easy_setopt(obj.curlHandle, CURLOPT_NOSIGNAL, 1L); - curl_easy_setopt(obj.curlHandle, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(obj.curlHandle, CURLOPT_URL, url.c_str()); curl_easy_setopt(obj.curlHandle, CURLOPT_WRITEDATA, (void *) &obj); curl_easy_setopt(obj.curlHandle, CURLOPT_WRITEFUNCTION, writeDataFunc); @@ -377,7 +420,7 @@ void FileTransferManager::resume(const QString &fileId) qDebug() << "Start Get"; std::string resData; - if (CURLE_OK != httpGet("File/" + fileId.toStdString() + "/status", resData, CURL_HTTP_VERSION_1_1)) + if (CURLE_OK != httpGet("File/" + fileId.toStdString() + "/status", resData)) return; qDebug() << resData.c_str(); From c5b7ee4a63cfb8b8c09b9a0b179e5441c44bca80 Mon Sep 17 00:00:00 2001 From: wuyize Date: Thu, 6 Jul 2023 14:32:25 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=8E=A5=E5=85=A5=E4=B8=8B=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AicsKnowledgeBase/qml/page/ContentPage.qml | 4 +--- AicsKnowledgeBase/src/FileTransferManager.cpp | 7 ++----- AicsKnowledgeBase/src/FileTransferManager.h | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/AicsKnowledgeBase/qml/page/ContentPage.qml b/AicsKnowledgeBase/qml/page/ContentPage.qml index fccba38..5e248c2 100644 --- a/AicsKnowledgeBase/qml/page/ContentPage.qml +++ b/AicsKnowledgeBase/qml/page/ContentPage.qml @@ -193,9 +193,7 @@ FluArea { } onClicked: { emit: content_area.download(content_area.knowledgeFileId) - // FileTransferManager.download(content_area.knowledgeFileId) - FileTransferManager.download( - "4973c59e-3ba1-41f2-a57e-3b53c2b5e2a4") + FileTransferManager.download(content_area.knowledgeFileId) } } } diff --git a/AicsKnowledgeBase/src/FileTransferManager.cpp b/AicsKnowledgeBase/src/FileTransferManager.cpp index 592df5c..35888fc 100644 --- a/AicsKnowledgeBase/src/FileTransferManager.cpp +++ b/AicsKnowledgeBase/src/FileTransferManager.cpp @@ -339,11 +339,8 @@ bool httpDownload(const std::string &url, const FileItem &item) return res == CURLE_OK; } -void FileTransferManager::download(QString fileId) +void FileTransferManager::download(const QString& fileId) { - static int _fileId = 0; - //fileId = QString::number(_fileId++); - QtConcurrent::run([fileId, this] { qDebug() << "Start Get"; @@ -364,7 +361,7 @@ void FileTransferManager::download(QString fileId) FileTransferListModel::instance().insertItem(item); });*/ - auto fileUrl = "https://curl.se/download/curl-8.1.2.zip"; + auto fileUrl = "File/" + fileId.toStdString(); /* curl_slist *headers = nullptr; diff --git a/AicsKnowledgeBase/src/FileTransferManager.h b/AicsKnowledgeBase/src/FileTransferManager.h index 256aec0..2f2406a 100644 --- a/AicsKnowledgeBase/src/FileTransferManager.h +++ b/AicsKnowledgeBase/src/FileTransferManager.h @@ -24,7 +24,7 @@ public: Q_INVOKABLE QString getFileMd5(const QUrl& fileUrl); Q_INVOKABLE void upload(const QUrl& fileUrl, const QString& fileId, const QString& ticket, const QString &fileName); - Q_INVOKABLE void download(QString fileId); + Q_INVOKABLE void download(const QString& fileId); Q_INVOKABLE void pause(const QString& fileId); Q_INVOKABLE void resume(const QString& fileId); From fea5bd698d89fb5ead08082c3763e6d160343658 Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Thu, 6 Jul 2023 15:10:13 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B0=E5=BB=BA?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=A4=B9=E9=9D=99=E6=80=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AicsKnowledgeBase/qml/component/FileList.qml | 109 ++++++++++------ .../qml/component/InputDialog.qml | 122 ++++++++++++++++++ AicsKnowledgeBase/res/createFolder.png | Bin 0 -> 5546 bytes 3 files changed, 194 insertions(+), 37 deletions(-) create mode 100644 AicsKnowledgeBase/qml/component/InputDialog.qml create mode 100644 AicsKnowledgeBase/res/createFolder.png diff --git a/AicsKnowledgeBase/qml/component/FileList.qml b/AicsKnowledgeBase/qml/component/FileList.qml index e992e3e..11e348c 100644 --- a/AicsKnowledgeBase/qml/component/FileList.qml +++ b/AicsKnowledgeBase/qml/component/FileList.qml @@ -2,6 +2,7 @@ import QtQuick 2.15 import QtQuick.Layouts import FluentUI import QtQuick.Dialogs +import QtQuick.Controls import "qrc:///AicsKnowledgeBase/qml/global" import SignalFileOperation 1.0 import AicsKB.FileTransferManager @@ -44,43 +45,76 @@ Item { "uuid": uuid }]) } - FluButton { - Layout.alignment: Qt.AlignRight - text: "上传" - onClicked: function () { - console.log("click") - fileDialog.open() - } - FileDialog { - id: fileDialog - onAccepted: function () { - let name = FileTransferManager.getFileName(selectedFile) - const size = FileTransferManager.getFileSize( - selectedFile) - const md5 = FileTransferManager.getFileMd5(selectedFile) - if (size <= 0 || md5 === '') - return - var body = { - "name": name, - "brief": "brief", - "size": size, - "md5": md5, - "tags": [], - "parentId": header.items.length - !== 0 ? header.items[header.items.length - 1].uuid : null + RowLayout { + Layout.preferredWidth: parent.width + Item { + Layout.alignment: Qt.AlignRight + height: 28 + width: 28 + InputDialog { + id: dialog + title: "新建文件夹" + buttonFlags: FluContentDialog.PositiveButton + | FluContentDialog.NegativeButton + negativeText: "取消" + positiveText: "确定" + message: "请输入文件夹名称" + onPositiveClicked: text => { + console.log(text) + } + } + + Image { + source: "qrc:/AicsKnowledgeBase/res/createFolder.png" + anchors.fill: parent + } + MouseArea { + anchors.fill: parent + onClicked: { + dialog.open() + } + } + } + FluButton { + Layout.alignment: Qt.AlignRight + text: "上传" + onClicked: function () { + console.log("click") + fileDialog.open() + } + FileDialog { + id: fileDialog + onAccepted: function () { + let name = FileTransferManager.getFileName( + selectedFile) + const size = FileTransferManager.getFileSize( + selectedFile) + const md5 = FileTransferManager.getFileMd5( + selectedFile) + if (size <= 0 || md5 === '') + return + var body = { + "name": name, + "brief": "brief", + "size": size, + "md5": md5, + "tags": [], + "parentId": header.items.length !== 0 ? header.items[header.items.length - 1].uuid : null + } + console.log("begin") + console.log(JSON.stringify(body)) + Request.post("knowledge/file", + JSON.stringify(body), + function (res, data) { + console.log(res) + console.log(data) + FileTransferManager.upload( + selectedFile, data.id, + data.ticket, name) + }, function (res, data) { + console.log(res) + }) } - console.log("begin") - console.log(JSON.stringify(body)) - Request.post("knowledge/file", JSON.stringify(body), - function (res, data) { - console.log(res) - console.log(data) - FileTransferManager.upload( - selectedFile, data.id, - data.ticket, name) - }, function (res, data) { - console.log(res) - }) } } } @@ -151,6 +185,7 @@ Item { === 0 ? "null" : header.items[header.items.length - 1].uuid Request.get("/knowledge/" + uuid, function (response) { var data = JSON.parse(response) + console.log(response) console.log(data.knowledgeFileAttribute) fileListModel.clear() var files = data.children @@ -186,7 +221,7 @@ Item { } fileListModel.append(modelItem) } - console.log(fileListModel) + console.log(fileListModel.count) listView.currentIndex = -1 }) } diff --git a/AicsKnowledgeBase/qml/component/InputDialog.qml b/AicsKnowledgeBase/qml/component/InputDialog.qml new file mode 100644 index 0000000..ef60cda --- /dev/null +++ b/AicsKnowledgeBase/qml/component/InputDialog.qml @@ -0,0 +1,122 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import QtQuick.Window +import FluentUI + +FluPopup { + id: popup + property string title: "Title" + property string message: "Message" + property string neutralText: "Neutral" + property string negativeText: "Negative" + property string positiveText: "Positive" + signal neutralClicked + signal negativeClicked + signal positiveClicked(string text) + enum ButtonFlag { + NegativeButton = 1, + NeutralButton = 2, + PositiveButton = 4 + } + property int buttonFlags: FluContentDialog.NegativeButton | FluContentDialog.PositiveButton + property var minWidth: { + if (Window.window == null) + return 400 + return Math.min(Window.window.width, 400) + } + focus: true + Rectangle { + id: layout_content + anchors.fill: parent + implicitWidth: minWidth + implicitHeight: text_title.height + text_message.height + layout_actions.height + color: 'transparent' + radius: 5 + FluText { + id: text_title + font: FluTextStyle.TitleLarge + text: title + topPadding: 20 + leftPadding: 20 + rightPadding: 20 + wrapMode: Text.WrapAnywhere + anchors { + top: parent.top + left: parent.left + right: parent.right + } + } + FluTextBox { + id: text_message + font: FluTextStyle.Body + wrapMode: Text.WrapAnywhere + placeholderText: message + topPadding: 14 + leftPadding: 20 + rightPadding: 20 + bottomPadding: 14 + anchors { + top: text_title.bottom + left: parent.left + right: parent.right + } + } + Rectangle { + id: layout_actions + height: 68 + radius: 5 + color: FluTheme.dark ? Qt.rgba( + 32 / 255, 32 / 255, 32 / 255, + blurBackground ? blurOpacity - 0.4 : 1) : Qt.rgba( + 243 / 255, 243 / 255, 243 / 255, + blurBackground ? blurOpacity - 0.4 : 1) + anchors { + top: text_message.bottom + left: parent.left + right: parent.right + } + RowLayout { + anchors { + centerIn: parent + margins: spacing + fill: parent + } + spacing: 15 + FluButton { + id: neutral_btn + Layout.fillWidth: true + Layout.fillHeight: true + visible: popup.buttonFlags & FluContentDialog.NeutralButton + text: neutralText + onClicked: { + popup.close() + neutralClicked() + } + } + FluButton { + id: negative_btn + Layout.fillWidth: true + Layout.fillHeight: true + visible: popup.buttonFlags & FluContentDialog.NegativeButton + text: negativeText + onClicked: { + popup.close() + negativeClicked() + } + } + FluFilledButton { + id: positive_btn + Layout.fillWidth: true + Layout.fillHeight: true + visible: popup.buttonFlags & FluContentDialog.PositiveButton + text: positiveText + onClicked: { + popup.close() + positiveClicked(text_message.text) + } + } + } + } + } +} diff --git a/AicsKnowledgeBase/res/createFolder.png b/AicsKnowledgeBase/res/createFolder.png new file mode 100644 index 0000000000000000000000000000000000000000..1cac6e80eec9a990561024d16272eb0746e65da3 GIT binary patch literal 5546 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