初步建立导航结构

main
wuyize 2023-06-21 21:33:52 +08:00
parent 1e1d10777d
commit baf3888bf3
21 changed files with 546 additions and 165 deletions

View File

@ -4,6 +4,7 @@ project(AicsKnowledgeBase LANGUAGES CXX)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 20)
find_package(Qt6 COMPONENTS Quick REQUIRED) find_package(Qt6 COMPONENTS Quick REQUIRED)
@ -22,7 +23,7 @@ foreach (filepath ${QML_PATHS})
endforeach (filepath) endforeach (filepath)
# #
file(GLOB_RECURSE RES_PATHS res/*.png res/*.jpg res/*.svg res/*.ico res/*.ttf res/*.webp res/qmldir) file(GLOB_RECURSE RES_PATHS res/*.png res/*.jpg res/*.svg res/*.ico res/*.ttf res/*.webp qmldir)
foreach (filepath ${RES_PATHS}) foreach (filepath ${RES_PATHS})
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" filename ${filepath}) string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" filename ${filepath})
list(APPEND resource_files ${filename}) list(APPEND resource_files ${filename})

View File

@ -10,9 +10,10 @@ Window {
FluApp.init(app); FluApp.init(app);
FluTheme.darkMode = FluDarkMode.System; FluTheme.darkMode = FluDarkMode.System;
FluApp.routes = { FluApp.routes = {
"/login": "qrc:/AicsKnowledgeBase/qml/LoginWindow.qml",
"/": "qrc:/AicsKnowledgeBase/qml/MainWindow.qml" "/": "qrc:/AicsKnowledgeBase/qml/MainWindow.qml"
}; };
FluApp.initialRoute = "/"; FluApp.initialRoute = "/login";
FluApp.run(); FluApp.run();
} }
} }

View File

@ -0,0 +1,71 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Basic
import FluentUI
import org.wangwenx190.FramelessHelper
FluWindow {
property bool appBarVisible: true
function setHitTestVisible(com) {
framless_helper.setHitTestVisible(com)
}
function setTitleBarItem(com) {
framless_helper.setTitleBarItem(com)
}
id: window
//color: "transparent"
FluAppBar {
id: title_bar
title: window.title
visible: appBarVisible
anchors {
left: parent.left
right: parent.right
top: parent.top
}
}
/*FluIconButton {
id: refreshButton
height: 30
iconSize: 13
iconSource: FluentIcons.Sync
width: 30
z: 8
onClicked: {
showSuccess("reload")
loader.reload()
}
anchors {
top: title_bar.bottom
}
}*/
FramelessHelper {
id: framless_helper
onReady: {
setTitleBarItem(title_bar)
moveWindowToDesktopCenter()
setHitTestVisible(title_bar.minimizeButton())
setHitTestVisible(title_bar.maximizeButton())
setHitTestVisible(title_bar.closeButton())
//setHitTestVisible(refreshButton)
title_bar.maximizeButton.visible = true
//if (blurBehindWindowEnabled)
// window.backgroundVisible = false
window.show()
}
}
/* FluRemoteLoader {
id: loader
anchors.fill: parent
source: "file:///D:\\Courses\\Qt\\AicsKnowledgeBase_client\\AicsKnowledgeBase\\qml\\LoginPage.qml"
}*/
}

View File

@ -1,98 +0,0 @@
import QtQuick
import FluentUI
import QtQuick.Controls
import QtQuick.Window
import QtQuick.Layouts
import org.wangwenx190.FramelessHelper
import AicsKB.HttpClient
Row {
anchors.fill: parent
Rectangle {
id: introdutcitonItem
height: parent.height
width: parent.width * 0.5
color: "#f3fbff"
//color: "transparent"
Image {
anchors.fill: parent
fillMode: Image.PreserveAspectFit
source: "qrc:/AicsKnowledgeBase/res/login_background.webp"
}
}
ColumnLayout {
id: loginRect
width: parent.width * 0.5
height: parent.height
FluPivot {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
Layout.margins: 20
height: 200
FluPivotItem {
id: loginItem
title: "登录"
function login(s)
{
showSuccess(s);
}
contentItem: Column {
anchors.margins: {
top: 10
}
anchors.top: parent.top
spacing: 12
FluTextBox {
anchors.left: parent.left
anchors.right: parent.right
id: account
placeholderText: "用户名"
}
FluPasswordBox {
anchors.left: parent.left
anchors.right: parent.right
id: password
placeholderText: "密码"
}
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
FluCheckBox {
Layout.alignment: Qt.AlignLeft
//anchors.left: parent.left
text: "记住密码"
}
FluTextButton {
Layout.alignment: Qt.AlignRight
//anchors.right: parent.right
text: "忘记密码?"
}
}
FluFilledButton {
anchors.horizontalCenter: parent.horizontalCenter
normalColor: FluColors.Green.normal
text: "登录"
onClicked: {
HttpClient.doGetRequest("https://quic.aiortc.org/", loginItem, "login");
}
}
}
}
FluPivotItem {
title: "注册"
// Rectangle{
// anchors.fill: parent
// color: "blue"
// }
}
}
}
}

View File

@ -0,0 +1,114 @@
import QtQuick
import FluentUI
import QtQuick.Controls
import QtQuick.Window
import QtQuick.Layouts
import org.wangwenx190.FramelessHelper
import AicsKB.HttpClient
AppFluWindow {
id: window
height: 420
title: "智能客服知识库"
width: 640
Row {
anchors.fill: parent
Rectangle {
id: introdutcitonItem
height: parent.height
width: parent.width * 0.5
color: "#f3fbff"
//color: "transparent"
Image {
anchors.fill: parent
fillMode: Image.PreserveAspectFit
source: "qrc:/AicsKnowledgeBase/res/login_background.webp"
}
}
Rectangle{
width: parent.width * 0.5
height: parent.height
color: "#f3f3f3"
ColumnLayout {
id: loginRect
anchors.fill: parent
FluPivot {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
Layout.margins: 20
height: 200
FluPivotItem {
id: loginItem
title: "登录"
function login(s) {
showSuccess(s)
}
contentItem: Column {
anchors.margins: {
top: 10
}
anchors.top: parent.top
spacing: 12
FluTextBox {
anchors.left: parent.left
anchors.right: parent.right
id: account
placeholderText: "用户名"
}
FluPasswordBox {
anchors.left: parent.left
anchors.right: parent.right
id: password
placeholderText: "密码"
}
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
FluCheckBox {
Layout.alignment: Qt.AlignLeft
//anchors.left: parent.left
text: "记住密码"
}
FluTextButton {
Layout.alignment: Qt.AlignRight
//anchors.right: parent.right
text: "忘记密码?"
}
}
FluFilledButton {
anchors.horizontalCenter: parent.horizontalCenter
//normalColor: FluColors.Green.normal
//normalColor: "#ffffff"
text: "登录"
onClicked: {
FluApp.navigate("/");
window.close();
//HttpClient.doGetRequest(
// "https://quic.aiortc.org/",
// loginItem, "login")
}
}
}
}
// FluPivotItem {
// title: ""
// Rectangle{
// anchors.fill: parent
// color: "blue"
// }
//}
}
}
}
}
}

View File

@ -5,50 +5,68 @@ import QtQuick.Controls
import QtQuick.Controls.Basic import QtQuick.Controls.Basic
import FluentUI import FluentUI
import org.wangwenx190.FramelessHelper import org.wangwenx190.FramelessHelper
import "qrc:///AicsKnowledgeBase/qml/global"
FluWindow { FluWindow {
property bool appBarVisible: true
function setHitTestVisible(com) {
framless_helper.setHitTestVisible(com)
}
function setTitleBarItem(com) {
framless_helper.setTitleBarItem(com)
}
id: window id: window
//color: "transparent" width: 1000
height: 420 height: 640
title: "智能客服知识库"
width: 640
FluAppBar { FluAppBar {
id: title_bar id: title_bar
title: window.title title: window.title
visible: appBarVisible
anchors { anchors {
left: parent.left left: parent.left
right: parent.right right: parent.right
top: parent.top top: parent.top
leftMargin: 35
} }
} }
/*FluIconButton {
id: refreshButton
height: 30
iconSize: 13
iconSource: FluentIcons.Sync
width: 30
z: 8
onClicked: { RowLayout {
showSuccess("reload") anchors.fill: parent
loader.reload()
FluNavigationView {
id: nav_view
Layout.fillHeight: true
Layout.preferredWidth: 400
Layout.bottomMargin: 4
z: 999
items: NavItems
footerItems: FooterItems
topPadding: 5
displayMode: FluNavigationView.Compact
logo: "qrc:/AicsKnowledgeBase/res/logo.png"
title: "智能客服知识库"
Behavior on rotation {
NumberAnimation {
duration: 167
}
}
transformOrigin: Item.Center
Component.onCompleted: {
NavItems.navigationView = nav_view
FooterItems.navigationView = nav_view
setCurrentIndex(0)
}
} }
anchors { FluArea {
top: title_bar.bottom Layout.fillHeight: true
Layout.fillWidth: true
paddings: 10
Layout.topMargin: 45
Layout.bottomMargin: 4
Layout.rightMargin: 4
FluText {
Layout.topMargin: 20
text: "Content"
}
} }
}*/ }
FramelessHelper { FramelessHelper {
id: framless_helper id: framless_helper
onReady: { onReady: {
@ -57,20 +75,12 @@ FluWindow {
setHitTestVisible(title_bar.minimizeButton()) setHitTestVisible(title_bar.minimizeButton())
setHitTestVisible(title_bar.maximizeButton()) setHitTestVisible(title_bar.maximizeButton())
setHitTestVisible(title_bar.closeButton()) setHitTestVisible(title_bar.closeButton())
//setHitTestVisible(refreshButton)
title_bar.maximizeButton.visible = true title_bar.maximizeButton.visible = true
//if (blurBehindWindowEnabled)
// window.backgroundVisible = false // window.backgroundVisible = false
window.show() window.show()
} }
} }
/* FluRemoteLoader {
id: loader
anchors.fill: parent
source: "file:///D:\\Courses\\Qt\\AicsKnowledgeBase_client\\AicsKnowledgeBase\\qml\\LoginPage.qml"
}*/
LoginPage {
anchors.fill: parent
}
} }

View File

@ -0,0 +1,36 @@
pragma Singleton
import QtQuick
import FluentUI
FluObject {
property var navigationView
FluPaneItemSeparator{}
FluPaneItem {
title: "我的收藏"
icon: FluentIcons.FavoriteList
onTap: {
navigationView.push("qrc:/AicsKnowledgeBase/qml/page/FavoritePage.qml")
}
}
FluPaneItem {
title: "浏览历史"
icon: FluentIcons.History
onTap: {
navigationView.push("qrc:/AicsKnowledgeBase/qml/page/HistoryPage.qml")
}
}
FluPaneItem {
title: "已下载"
icon: FluentIcons.Download
onTap: {
navigationView.push("qrc:/AicsKnowledgeBase/qml/page/LocalPage.qml")
}
}
}

View File

@ -0,0 +1,53 @@
pragma Singleton
import QtQuick
import FluentUI
FluObject {
property var navigationView
FluPaneItem {
title: "探索"
icon: FluentIcons.Home
onTap: {
navigationView.push("qrc:/AicsKnowledgeBase/qml/page/HomePage.qml")
}
}
FluPaneItem {
title: "全部"
icon: FluentIcons.FileExplorer
onTap: {
navigationView.push("qrc:/AicsKnowledgeBase/qml/page/FilePage.qml")
}
}
FluPaneItem {
title: "文档"
icon: FluentIcons.Document
onTap: {
navigationView.push("qrc:/AicsKnowledgeBase/qml/page/DocumentPage.qml")
}
}
FluPaneItem {
title: "视频"
icon: FluentIcons.Movies
onTap: {
navigationView.push("qrc:/AicsKnowledgeBase/qml/page/VideoPage.qml")
}
}
FluPaneItem {
title: "音频"
icon: FluentIcons.Audio
onTap: {
navigationView.push("qrc:/AicsKnowledgeBase/qml/page/AudioPage.qml")
}
}
function startPageByItem(data) {
navigationView.startPageByItem(data)
}
}

View File

@ -0,0 +1,2 @@
singleton NavItems 1.0 NavItems.qml
singleton FooterItems 1.0 FooterItems.qml

View File

@ -0,0 +1,21 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Basic
import FluentUI
FluArea{
property string url: ''
Layout.fillWidth: true
Layout.fillHeight: true
paddings: 10
Layout.topMargin: 20
FluText{
Layout.topMargin: 20
text:"Audio"
}
}

View File

@ -0,0 +1,21 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Basic
import FluentUI
FluArea{
property string url: ''
Layout.fillWidth: true
Layout.fillHeight: true
paddings: 10
Layout.topMargin: 20
FluText{
Layout.topMargin: 20
text:"Document"
}
}

View File

@ -0,0 +1,22 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Basic
import FluentUI
FluArea{
property string url: ''
Layout.fillWidth: true
Layout.fillHeight: true
paddings: 10
Layout.topMargin: 20
FluText{
Layout.topMargin: 20
text: "Favorite"
}
}

View File

@ -0,0 +1,22 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Basic
import FluentUI
FluArea{
property string url: ''
Layout.fillWidth: true
Layout.fillHeight: true
paddings: 10
Layout.topMargin: 20
FluText{
Layout.topMargin: 20
text: "File"
}
}

View File

@ -0,0 +1,22 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Basic
import FluentUI
FluArea{
property string url: ''
Layout.fillWidth: true
Layout.fillHeight: true
paddings: 10
Layout.topMargin: 20
FluText{
Layout.topMargin: 20
text: "History"
}
}

View File

@ -0,0 +1,31 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Basic
import FluentUI
FluArea{
property string url: ''
Layout.fillWidth: true
Layout.fillHeight: true
paddings: 10
Layout.topMargin: 20
FluText{
Layout.topMargin: 20
text:"Home"
}
}
//FluScrollablePage{
// Rectangle {
// Layout.fillWidth: true
// height: 200
// color: "red"
// }
//}

View File

@ -0,0 +1,22 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Basic
import FluentUI
FluArea{
property string url: ''
Layout.fillWidth: true
Layout.fillHeight: true
paddings: 10
Layout.topMargin: 20
FluText{
Layout.topMargin: 20
text: "Local"
}
}

View File

@ -0,0 +1,21 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Basic
import FluentUI
FluArea{
property string url: ''
Layout.fillWidth: true
Layout.fillHeight: true
paddings: 10
Layout.topMargin: 20
FluText{
Layout.topMargin: 20
text:"Video"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -3,6 +3,8 @@
// //
#include "HttpClient.h" #include "HttpClient.h"
#include <QtConcurrent/QtConcurrent>
#include <QDebug>
HttpClient::HttpClient(QQmlApplicationEngine &engine, QObject *parent) HttpClient::HttpClient(QQmlApplicationEngine &engine, QObject *parent)
: engine(engine), QObject(parent) : engine(engine), QObject(parent)
@ -11,28 +13,40 @@ HttpClient::HttpClient(QQmlApplicationEngine &engine, QObject *parent)
void HttpClient::doGetRequest(QString url, QObject *object, QString callback) void HttpClient::doGetRequest(QString url, QObject *object, QString callback)
{ {
CURL *curl; auto *watcher = new QFutureWatcher<CURLcode>;
CURLcode res; connect(watcher, &QFutureWatcher<CURLcode>::finished, this, [watcher, object, callback] {
auto res = watcher->future().result();
curl = curl_easy_init(); delete watcher;
if(curl) { qDebug() << (res == CURLE_OK ? "success" : "fail");
curl_easy_setopt(curl, CURLOPT_URL, url.toStdString().c_str());
/* Use HTTP/3 but fallback to earlier HTTP if necessary */
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION,
(long)CURL_HTTP_VERSION_3);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
QVariant r; QVariant r;
QMetaObject::invokeMethod(object, callback.toStdString().c_str(), QMetaObject::invokeMethod(object, callback.toStdString().c_str(),
Q_RETURN_ARG(QVariant, r), Q_RETURN_ARG(QVariant, r),
Q_ARG(QVariant, res==CURLE_OK? "success":"fail")); Q_ARG(QVariant, res == CURLE_OK ? "success" : "fail"));
});
/* always cleanup */ watcher->setFuture(QtConcurrent::run([url] {
curl_easy_cleanup(curl); qDebug() << "Start Get";
} CURL *curl;
CURLcode res;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.toStdString().c_str());
/* Use HTTP/3 but fallback to earlier HTTP if necessary */
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION,
(long) CURL_HTTP_VERSION_3);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
}
qDebug() << "End Get";
return res;
}));
} }

View File

@ -34,7 +34,7 @@ int main(int argc, char* argv[])
qmlRegisterSingletonInstance<HttpClient>("AicsKB.HttpClient", 1, 0, "HttpClient", httpClient); qmlRegisterSingletonInstance<HttpClient>("AicsKB.HttpClient", 1, 0, "HttpClient", httpClient);
const QUrl url(u"qrc:/AicsKnowledgeBase/qml/App.qml"_qs); const QUrl url(u"qrc:/AicsKnowledgeBase/qml/App.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject* obj, const QUrl& objUrl) { &app, [url](QObject* obj, const QUrl& objUrl) {
if (!obj && url == objUrl) if (!obj && url == objUrl)

View File

@ -1,16 +1,11 @@
# AicsKnowledgeBase # AicsKnowledgeBase
智能客服知识库 智能客服知识库
提供客服场景统一、便捷的知识管理,实现对客服常用知识的统一存储、更新; 提供客户快速检索,帮助客户解决在知识生产-管理-获取-应用流程中的需求 和问题,快速沉淀知识。 提供客服场景统一、便捷的知识管理,实现对客服常用知识的统一存储、更新; 提供客户快速检索,帮助客户解决在知识生产-管理-获取-应用流程中的需求 和问题,快速沉淀知识。
1、要求采用UDP协议、支持断点续传。 1. 要求采用UDP协议、支持断点续传。
2. 支持支持常见知识录入如pdf/word、ppt音视频等支持知识导入、导出。支持多级目录、多级标签整理知识。
2、支持支持常见知识录入如pdf/word、ppt音视频等支持知识导入、导出。支持多级目录、多级标签整理知识。 3. 支持常见知识的快速检索、热点知识分类呈现。
4. 能够基于某个知识内容进行知识分享、知识评论等。
3、支持常见知识的快速检索、热点知识分类呈现。
4、能够基于某个知识内容进行知识分享、知识评论等。
## 需求 ## 需求