main
yang.yongquan 2023-07-06 17:21:57 +08:00
commit f40c6b2865
7 changed files with 209 additions and 242 deletions

View File

@ -38,6 +38,7 @@ Item {
Component { Component {
id: fileListItemHeader id: fileListItemHeader
ColumnLayout { ColumnLayout {
id: topColumnLayout
function add(folderName, uuid) { function add(folderName, uuid) {
console.log(header.items) console.log(header.items)
header.items = header.items.concat([{ header.items = header.items.concat([{
@ -45,141 +46,6 @@ Item {
"uuid": uuid "uuid": uuid
}]) }])
} }
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)
})
}
}
}
}
RowLayout {
id: fileListItemHeaderItem
width: ListView.view.width
height: 48
// back to folder button
FluIconButton {
Layout.alignment: Qt.AlignVCenter
id: backButton
width: 24
height: 24
iconSource: FluentIcons.ForwardCall
onClicked: {
if (header.count() > 0) {
header.items = header.items.slice(
0, header.count() - 1)
}
fileListItemHeaderItem.update()
}
}
FluBreadcrumbBar {
id: header
width: parent.width
height: parent.height
separator: ">"
items: []
onClickItem: function (model) {
if (model.index + 1 !== count()) {
items = items.slice(0, model.index + 1)
}
}
onItemsChanged: {
fileListItemHeaderItem.update()
}
}
function getType(suffix) {
if (suffix === "ppt" || suffix === "pptx")
return "PPT"
else if (suffix === "doc" || suffix === "docx")
return "WORD"
else if (suffix === "pdf")
return "PDF"
else if (suffix === "txt")
return "TXT"
else if (suffix === "xls" || suffix === "xlsx")
return "EXCEL"
else if (suffix === "zip" || suffix === "rar")
return "ZIP"
else if (suffix === "png" || suffix === "jpg"
|| suffix === "jpeg" || suffix === "gif")
return "IMAGE"
else if (suffix === "mp3" || suffix === "wav")
return "AUDIO"
else if (suffix === "mp4" || suffix === "avi"
|| suffix === "rmvb" || suffix === "rm"
|| suffix === "wmv" || suffix === "mkv")
return "VIDEO"
else
return "OTHER"
}
function update() { function update() {
var uuid = header.items.length var uuid = header.items.length
=== 0 ? "null" : header.items[header.items.length - 1].uuid === 0 ? "null" : header.items[header.items.length - 1].uuid
@ -196,7 +62,8 @@ Item {
"title": file.name, "title": file.name,
"uuid": file.id, "uuid": file.id,
"date"// cut time after 'T' "date"// cut time after 'T'
: file.createTime.substring(0, 10) : file.createTime.substring(0, 10),
"fuuid": uuid
} }
if (file.knowledgeFileAttribute === null) { if (file.knowledgeFileAttribute === null) {
modelItem.type = "folder" modelItem.type = "folder"
@ -225,6 +92,107 @@ Item {
listView.currentIndex = -1 listView.currentIndex = -1
}) })
} }
function getType(suffix) {
if (suffix === "ppt" || suffix === "pptx")
return "PPT"
else if (suffix === "doc" || suffix === "docx")
return "WORD"
else if (suffix === "pdf")
return "PDF"
else if (suffix === "txt")
return "TXT"
else if (suffix === "xls" || suffix === "xlsx")
return "EXCEL"
else if (suffix === "zip" || suffix === "rar")
return "ZIP"
else if (suffix === "png" || suffix === "jpg"
|| suffix === "jpeg" || suffix === "gif")
return "IMAGE"
else if (suffix === "mp3" || suffix === "wav")
return "AUDIO"
else if (suffix === "mp4" || suffix === "avi"
|| suffix === "rmvb" || suffix === "rm"
|| suffix === "wmv" || suffix === "mkv")
return "VIDEO"
else
return "OTHER"
}
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 => {
var param = {
"name": text,
"parentId": header.items[header.items.length
- 1].uuid
}
Request.post(
"/knowledge",
JSON.stringify(param))
}
}
Image {
source: "qrc:/AicsKnowledgeBase/res/createFolder.png"
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
dialog.open()
}
}
}
UploadButton {
header: header
}
}
RowLayout {
id: fileListItemHeaderItem
width: ListView.view.width
height: 48
// back to folder button
FluIconButton {
Layout.alignment: Qt.AlignVCenter
id: backButton
width: 24
height: 24
iconSource: FluentIcons.ForwardCall
onClicked: {
if (header.count() > 0) {
header.items = header.items.slice(
0, header.count() - 1)
}
topColumnLayout.update()
}
}
FluBreadcrumbBar {
id: header
width: parent.width
height: parent.height
separator: ">"
items: []
onClickItem: function (model) {
if (model.index + 1 !== count()) {
items = items.slice(0, model.index + 1)
}
}
onItemsChanged: {
topColumnLayout.update()
}
}
} }
} }
} }
@ -238,6 +206,7 @@ Item {
FileListItem { FileListItem {
id: fileListItem id: fileListItem
uuid: model.uuid uuid: model.uuid
fuuid: model.fuuid
width: parent.width width: parent.width
height: parent.height height: parent.height
title: model.title title: model.title
@ -256,6 +225,9 @@ Item {
emit: search(tag) emit: search(tag)
console.log(tag) console.log(tag)
} }
onRefresh: {
listView.headerItem.update()
}
} }
function doubleClicked() { function doubleClicked() {
listView.currentIndex = index listView.currentIndex = index
@ -275,6 +247,7 @@ Item {
isDir: true isDir: true
brief: "This is a test file" brief: "This is a test file"
type: "FOLDER" type: "FOLDER"
fuuid: "1"
} }
ListElement { ListElement {
uuid: "2" uuid: "2"
@ -286,6 +259,7 @@ Item {
date: "2020-09-09" date: "2020-09-09"
pageView: 100 pageView: 100
stars: 10 stars: 10
fuuid: "1"
} }
ListElement { ListElement {
uuid: "3" uuid: "3"
@ -297,6 +271,7 @@ Item {
pageView: 100 pageView: 100
size: 10200000022 size: 10200000022
stars: 10 stars: 10
fuuid: "1"
} }
} }
} }

View File

@ -5,6 +5,7 @@ import QtQuick.Layouts
FluArea { FluArea {
id: fileItem id: fileItem
property string uuid property string uuid
property string fuuid: null
property string title property string title
property string brief property string brief
property string date property string date
@ -18,6 +19,46 @@ FluArea {
property int stars property int stars
property var colorList: ["blue", "green", "orange", "red", "yellow", "purple", "pink", "brown", "teal", "cyan", "gray", "darkgray"] property var colorList: ["blue", "green", "orange", "red", "yellow", "purple", "pink", "brown", "teal", "cyan", "gray", "darkgray"]
signal tagClicked(string tag) signal tagClicked(string tag)
signal refresh
FluMenu {
id: menu
FluMenuItem {
text: "重命名"
onClicked: {
dialog.open()
}
InputDialog {
id: dialog
title: "重命名"
buttonFlags: FluContentDialog.PositiveButton | FluContentDialog.NegativeButton
negativeText: "取消"
positiveText: "确定"
message: fileItem.title
onPositiveClicked: text => {
var param = {
"name": text,
"parentId": fuuid
}
Request.post("/knowledge",
JSON.stringify(param))
refresh()
}
}
}
FluMenuItem {
text: "移动至"
onClicked: {
refresh()
}
}
FluMenuItem {
text: "删除"
onClicked: {
Request.delete("/knowledge/" + uuid)
refresh()
}
}
}
ColumnLayout { ColumnLayout {
id: row id: row
@ -30,9 +71,15 @@ FluArea {
anchors.fill: parent anchors.fill: parent
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onDoubleClicked: { onDoubleClicked: {
fileItem.parent.doubleClicked() fileItem.parent.doubleClicked()
} }
onClicked: {
if (mouse.button === Qt.RightButton) {
menu.popup()
}
}
} }
RowLayout { RowLayout {
id: titleRow id: titleRow

View File

@ -112,6 +112,9 @@ Popup {
if (!paused) { if (!paused) {
console.log("pause") console.log("pause")
FileTransferManager.pause(fileId) FileTransferManager.pause(fileId)
} else {
FileTransferManager.download(fileId,
name, true)
} }
} }
} }

View File

@ -34,12 +34,12 @@ FluButton {
implicitWidth: Window.window == null ? 400 : Math.min( implicitWidth: Window.window == null ? 400 : Math.min(
Window.window.width, 400) Window.window.width, 400)
implicitHeight: text_title.height + text_message.height + layout_actions.height implicitHeight: text_title.height + content.height + layout_actions.height
color: 'transparent' color: 'transparent'
radius: 5 radius: 5
FluText { FluText {
id: text_title id: text_title
font: FluTextStyle.TitleLarge font: FluTextStyle.Title
text: "上传知识文件" text: "上传知识文件"
topPadding: 20 topPadding: 20
leftPadding: 20 leftPadding: 20
@ -51,11 +51,9 @@ FluButton {
right: parent.right right: parent.right
} }
} }
FluText {
id: text_message Row {
font: FluTextStyle.Body id: content
wrapMode: Text.WrapAnywhere
text: "content"
topPadding: 14 topPadding: 14
leftPadding: 20 leftPadding: 20
rightPadding: 20 rightPadding: 20
@ -65,7 +63,13 @@ FluButton {
left: parent.left left: parent.left
right: parent.right right: parent.right
} }
FluMultilineTextBox {
id: brief_textbox
width: parent.width - parent.leftPadding - parent.rightPadding
placeholderText: "请输入简介"
} }
}
Rectangle { Rectangle {
id: layout_actions id: layout_actions
height: 68 height: 68
@ -76,7 +80,7 @@ FluButton {
243 / 255, 243 / 255, 243 / 255, 243 / 255, 243 / 255, 243 / 255,
blurBackground ? blurOpacity - 0.4 : 1) blurBackground ? blurOpacity - 0.4 : 1)
anchors { anchors {
top: text_message.bottom top: content.bottom
left: parent.left left: parent.left
right: parent.right right: parent.right
} }
@ -113,7 +117,7 @@ FluButton {
return return
var body = { var body = {
"name": name, "name": name,
"brief": "brief", "brief": brief_textbox.text,
"size": size, "size": size,
"md5": md5, "md5": md5,
"tags": [], "tags": [],

View File

@ -78,17 +78,18 @@ FluArea {
function getType(suffix) { function getType(suffix) {
if (suffix === "md") if (suffix === "md")
return "MD" return "MD"
else if(suffix === "mp4" || suffix === "avi" else if (suffix === "mp4" || suffix === "avi" || suffix === "rmvb"
|| suffix === "rmvb" || suffix === "rm" || suffix === "rm" || suffix === "wmv" || suffix === "mkv")
|| suffix === "wmv" || suffix === "mkv")
return "VIDEO" return "VIDEO"
else return "OTHER" else
return "OTHER"
} }
function loadFile(knowledgeFileId) { function loadFile(knowledgeFileId) {
content_area.knowledgeFileId = knowledgeFileId content_area.knowledgeFileId = knowledgeFileId
console.log(knowledgeFileId) console.log(knowledgeFileId)
Request.get("knowledge/" + knowledgeFileId, function (response, data) { Request.get("knowledge/" + knowledgeFileId,
function (response, data) {
content_page.publishTime = data.createTime content_page.publishTime = data.createTime
content_page.title = data.name content_page.title = data.name
content_page.fileId = data.knowledgeFileAttribute.id content_page.fileId = data.knowledgeFileAttribute.id
@ -112,7 +113,6 @@ FluArea {
} }
content_page.favoriteCount = starers.length content_page.favoriteCount = starers.length
}) })
} }
Component.onCompleted: { Component.onCompleted: {
@ -215,7 +215,8 @@ FluArea {
} }
onClicked: { onClicked: {
emit: content_area.download(content_area.knowledgeFileId) emit: content_area.download(content_area.knowledgeFileId)
FileTransferManager.download(content_area.knowledgeFileId) FileTransferManager.download(content_page.fileId,
content_page.title)
} }
} }
} }

View File

@ -278,7 +278,7 @@ curl_off_t getHttpFileSize(const std::string &url)
curl_off_t fileLength = 0; curl_off_t fileLength = 0;
CURL *handle = initCurlWithCommonOptions(); CURL *handle = initCurlWithCommonOptions();
curl_easy_setopt(handle, CURLOPT_URL, url.c_str()); curl_easy_setopt(handle, CURLOPT_URL, (baseUrl + url).c_str());
curl_easy_setopt(handle, CURLOPT_HEADER, 0); //只需要header头 curl_easy_setopt(handle, CURLOPT_HEADER, 0); //只需要header头
curl_easy_setopt(handle, CURLOPT_NOBODY, 1); //不需要body curl_easy_setopt(handle, CURLOPT_NOBODY, 1); //不需要body
@ -292,14 +292,8 @@ curl_off_t getHttpFileSize(const std::string &url)
return fileLength; return fileLength;
} }
bool httpDownload(const std::string &url, const FileItem &item) bool httpDownload(const std::string &url, const std::string &savePath, const FileItem &item)
{ {
auto fileSize = getHttpFileSize(url);//获得文件大小。
if (fileSize == -1)
return false;
qDebug() << "FileSize: " << fileSize;
downloadingMapMutex.lock(); downloadingMapMutex.lock();
auto [iter, _] = downloadingMap.emplace(item.id, (FileDownloading) item); auto [iter, _] = downloadingMap.emplace(item.id, (FileDownloading) item);
downloadingMapMutex.unlock(); downloadingMapMutex.unlock();
@ -309,9 +303,8 @@ bool httpDownload(const std::string &url, const FileItem &item)
obj.curlHandle = initCurlWithCommonOptions(); obj.curlHandle = initCurlWithCommonOptions();
if (!obj.curlHandle) if (!obj.curlHandle)
return false; return false;
obj.totalSize = fileSize;//原始文件大小 obj.totalSize = item.totalSize;//原始文件大小
obj.file = std::ofstream("D:\\Downloads\\" + obj.name.toStdString() + ".zip", std::ios::binary); obj.file = std::ofstream(savePath, std::ios::binary | std::ios::app);
if (!obj.file.is_open()) { if (!obj.file.is_open()) {
qDebug() << "Open File Failed"; qDebug() << "Open File Failed";
curl_easy_cleanup(obj.curlHandle); curl_easy_cleanup(obj.curlHandle);
@ -320,7 +313,7 @@ bool httpDownload(const std::string &url, const FileItem &item)
curl_easy_setopt(obj.curlHandle, CURLOPT_HEADER, 0); curl_easy_setopt(obj.curlHandle, CURLOPT_HEADER, 0);
curl_easy_setopt(obj.curlHandle, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt(obj.curlHandle, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(obj.curlHandle, CURLOPT_URL, url.c_str()); curl_easy_setopt(obj.curlHandle, CURLOPT_URL, (baseUrl + url).c_str());
curl_easy_setopt(obj.curlHandle, CURLOPT_WRITEDATA, (void *) &obj); curl_easy_setopt(obj.curlHandle, CURLOPT_WRITEDATA, (void *) &obj);
curl_easy_setopt(obj.curlHandle, CURLOPT_WRITEFUNCTION, writeDataFunc); curl_easy_setopt(obj.curlHandle, CURLOPT_WRITEFUNCTION, writeDataFunc);
curl_easy_setopt(obj.curlHandle, CURLOPT_NOPROGRESS, false);//设为false 下面才能设置进度响应函数 curl_easy_setopt(obj.curlHandle, CURLOPT_NOPROGRESS, false);//设为false 下面才能设置进度响应函数
@ -339,42 +332,33 @@ bool httpDownload(const std::string &url, const FileItem &item)
return res == CURLE_OK; return res == CURLE_OK;
} }
void FileTransferManager::download(const QString& fileId) void FileTransferManager::download(const QString &fileId, const QString &fileName, bool resume)
{ {
QtConcurrent::run([fileId, this] { QtConcurrent::run([fileId, fileName, resume, this] {
qDebug() << "Start Get"; qDebug() << "Start Get";
std::string resData; std::string resData;
if (CURLE_OK != httpGet("File/" + fileId.toStdString() + "/status", resData)) if (CURLE_OK != httpGet("File/" + fileId.toStdString() + "/status", resData))
return; return;
qDebug() << resData.c_str(); qDebug() << resData.c_str();
auto resJson = QJsonDocument::fromJson(resData.c_str()); auto resJson = QJsonDocument::fromJson(resData.c_str());
//if(!resJson["isCompleted"].toBool()) if (!resJson["isCompleted"].toBool()) {
qDebug() << "File Not Completed";
return; return;
}
auto size = resJson["size"].toInteger();
std::string savePath = "D:\\Downloads\\" + fileName.toLocal8Bit().toStdString();
/* int size = resJson["size"].toInt(); qDebug() << savePath.c_str();
FileItem item{fileId, resJson["md5"].toString(), 0, size}; QFileInfo fileInfo(QString::fromLocal8Bit(savePath.c_str()));
QTimer::singleShot(0, qApp, [this, item]() { int64_t completedSize = fileInfo.exists() ? fileInfo.size() : 0;
FileItem item{true, fileId, fileName, completedSize, size};
if (!resume)
QTimer::singleShot(0, qApp, [item]() {
FileTransferListModel::instance().insertItem(item); FileTransferListModel::instance().insertItem(item);
});*/ });
auto fileUrl = "File/" + fileId.toStdString();
/* curl_slist *headers = nullptr;
headers = curl_slist_append(headers, "Range: bytes=0-");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);*/
int64_t size = getHttpFileSize(fileUrl);
FileItem item{true, fileId, fileId, 0, size};
auto res = httpDownload(fileUrl, item);
auto fileUrl = std::format("File/{}?rangeStart={}&rangeEnd={}", fileId.toStdString(), completedSize, size);
auto res = httpDownload(fileUrl, savePath, item);
qDebug() << "End Get" << res; qDebug() << "End Get" << res;
}); });
@ -410,52 +394,6 @@ int64_t FileTransferManager::getFileSize(const QUrl &fileUrl)
return QFile(fileUrl.toLocalFile()).size(); return QFile(fileUrl.toLocalFile()).size();
} }
void FileTransferManager::resume(const QString &fileId)
{
QtConcurrent::run([fileId, this] {
qDebug() << "Start Get";
std::string resData;
if (CURLE_OK != httpGet("File/" + fileId.toStdString() + "/status", resData))
return;
qDebug() << resData.c_str();
return;
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]() {
FileTransferListModel::instance().insertItem(item);
});*/
auto fileUrl = "https://curl.se/download/curl-8.1.2.zip";
/* curl_slist *headers = nullptr;
headers = curl_slist_append(headers, "Range: bytes=0-");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);*/
int64_t size = getHttpFileSize(fileUrl);
FileItem item{true, fileId, fileId, 0, size};
QTimer::singleShot(0, qApp, [this, item]() {
FileTransferListModel::instance().insertItem(item);
});
auto res = httpDownload(fileUrl, item);
qDebug() << "End Get" << res;
});
}
QString FileTransferManager::getFileName(const QUrl &fileUrl) QString FileTransferManager::getFileName(const QUrl &fileUrl)
{ {
return fileUrl.fileName(); return fileUrl.fileName();

View File

@ -24,9 +24,8 @@ public:
Q_INVOKABLE QString getFileMd5(const QUrl& fileUrl); 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 upload(const QUrl& fileUrl, const QString& fileId, const QString& ticket, const QString &fileName);
Q_INVOKABLE void download(const QString& fileId); Q_INVOKABLE void download(const QString& fileId, const QString& fileName, bool resume = false);
Q_INVOKABLE void pause(const QString& fileId); Q_INVOKABLE void pause(const QString& fileId);
Q_INVOKABLE void resume(const QString& fileId);
private: private: