添加新建文件夹静态流程

main
karlis 2023-07-06 15:11:32 +08:00
commit eadca3e91f
8 changed files with 463 additions and 42 deletions

View File

@ -54,6 +54,13 @@ FluWindow {
}
}
StackView {
id: stack_view
Layout.fillHeight: true
Layout.fillWidth: true
}
ContentPage {
Layout.fillHeight: true
Layout.fillWidth: true

View File

@ -53,12 +53,12 @@ Item {
width: 28
InputDialog {
id: dialog
title: "新建文件夹"
title: "新建文件夹"
buttonFlags: FluContentDialog.PositiveButton
| FluContentDialog.NegativeButton
negativeText: "取消"
positiveText: "确定"
message: "请输入文件夹名称"
negativeText: "取消"
positiveText: "确定"
message: "请输入文件夹名称"
onPositiveClicked: text => {
console.log(text)
}
@ -77,7 +77,7 @@ Item {
}
FluButton {
Layout.alignment: Qt.AlignRight
text: "上传"
text: "上传"
onClicked: function () {
console.log("click")
fileDialog.open()

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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)
}
}
}

View File

@ -0,0 +1,230 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtWebEngine 1.2
import FluentUI
import AicsKB.FileTransferManager
import SignalFileOperation 1.0
import "qrc:///AicsKnowledgeBase/qml/page"
FluArea {
id: note_area
paddings: 0
backgroundColor: "#f9f9f9"
visible: false
property string type: ""
property string knowledgeFileId
property string isFile: false
property string knowledgeUrl : "aics/main/knowledge/"
signal download(string knowledgeFileId)
signal clickTags(string tagName)
// paddings: {
// top: 10
// right: 0
// bottom: 10
// left: 10
// }
Connections {
target: SignalFileOperation
function onOpen(file) {
}
}
FluScrollablePage {
id: note_page
anchors.fill: parent
leftPadding: 10
topPadding: 10
rightPadding: 10
bottomPadding: 0
property int likeCount: 0
property int favoriteCount: 0
property int shareCount: 0
property int browsCount: 555
property bool isLike: false
property bool isFavorite: false
property bool isDownload: false
property double fileSize: 455
property list<string> tags: ["tag1", "tag2", "tag3"]
property string publishTime: "2002-01-01"
property string brief: "这是一个简介"
function getType(suffix) {
if(suffix === "md")
return "md"
else if(suffix === "mp4" || suffix === "avi" || suffix === "rmvb" || suffix === "mkv")
return "video"
else return "other"
}
function loadFile(noteId) {
var fileUrl = knowledgeUrl+noteId
Request.get(fileUrl, function (response) {
var data = JSON.parse(response)
console.log(data.knowledgeFileAttribute)
publishTime = data.createTime
type = getType(data.knowledgeFileAttribute.suffix)
brief = data.knowledgeFileAttribute.brief
fileSize = data.knowledgeFileAttribute.size
browsCount = data.knowledgeFileAttribute.pageView
var tagString = ""
for (var j = 0; j < file.knowledgeFileAttribute.tags.length; j++) {
if (j != 0)
tagString = tagString + ","
tagString = tagString + file.knowledgeFileAttribute.tags[j].name
}
tags = tagString.split(",")
})
}
Item {
Layout.fillWidth: true
implicitHeight: 50
FluText {
id: text_title
padding: 10
text: "文章标题"
font {
pointSize: 15
bold: true
}
}
ColumnLayout {
id: layout_share
FluIconButton {
id: button_share
iconSize: 15
iconSource: FluentIcons.Share
text: content_page.shareCount.toString()
}
FluText {
id: text_share
text: note_page.shareCount
font.pointSize: 8
Layout.alignment: button_share.Center
Layout.topMargin: -5
}
anchors {
verticalCenter: text_title.verticalCenter
right: parent.right
}
}
ColumnLayout {
id: layout_favorite
FluIconButton {
id: button_favorite
iconSize: 15
iconSource: note_page.isFavorite ? FluentIcons.FavoriteStarFill : FluentIcons.FavoriteStar
onClicked: {
Request.put()
}
}
FluText {
id: text_favorite
text: note_page.favoriteCount
font.pointSize: 8
Layout.alignment: button_favorite.Center
Layout.topMargin: -5
}
anchors {
verticalCenter: text_title.verticalCenter
right: layout_share.left
}
}
ColumnLayout {
id: layout_like
FluIconButton {
id: button_like
iconSize: 15
iconSource: note_page.isLike ? FluentIcons.HeartFill : FluentIcons.Heart
}
FluText {
id: text_like
text: note_page.favoriteCount
font.pointSize: 8
Layout.alignment: button_like.Center
Layout.topMargin: -5
}
anchors {
verticalCenter: text_title.verticalCenter
right: layout_favorite.left
}
}
FluIconButton {
id: button_download
iconSize: 25
iconSource: note_page.isDownload ? FluentIcons.OEM : FluentIcons.Download
anchors {
verticalCenter: text_title.verticalCenter
right: layout_like.left
rightMargin: 20
}
onClicked: {
emit: content_area.download(content_area.knowledgeFileId)
FileTransferManager.download(content_area.knowledgeFileId)
}
}
}
FluArea {
Layout.fillWidth: true
implicitHeight: 100
ColumnLayout {
RowLayout {
FluText {
padding: 10
text: content_page.publishTime
}
FluText {
padding: 10
text: content_page.fileSize.toString() + "MB"
}
FluText {
padding: 10
text: content_page.browsCount.toString() + "浏览量"
}
}
FluText {
Layout.topMargin: -2
Layout.leftMargin: 10
text: content_page.brief
}
RowLayout {
Layout.topMargin: 2
Layout.leftMargin: 5
Repeater {
model: content_page.tags
delegate: Button {
Layout.margins: 2
text: "#" + content_page.tags[index]
background: Rectangle {
implicitHeight: 10
implicitWidth: 10
color: FluColors.Grey20
radius: 10
}
onClicked: {
emit: content_area.clickTags(text)
}
}
}
}
}
}
NoteEditPage {
id: md_edit_page
noteId: "255454"
Layout.fillWidth: true
implicitHeight: 400
}
}
}

View File

@ -30,6 +30,24 @@ struct FileUploading : FileItem
std::unordered_map<QString, FileUploading> 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<char *>(ptr), readSize);
return readSize;
buf->file.read(reinterpret_cast<char *>(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);
@ -296,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";
@ -321,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;
@ -377,7 +417,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();

View File

@ -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);