perf: Assistant base

This commit is contained in:
fit2cloud-chenyw
2025-07-26 15:09:41 +08:00
parent 1e180950e8
commit d442c0638d
4 changed files with 119 additions and 206 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ import DashboardPreview from '@//views/dashboard/preview/SQPreviewSingle.vue'
import Dashboard from '@/views/dashboard/index.vue'
import Model from '@/views/system/model/Model.vue'
import Embedded from '@/views/system/embedded/index.vue'
import assistant from '@/views/embedded/assistant.vue'
import assistant from '@/views/embedded/index.vue'
import Member from '@/views/system/member/index.vue'
import Permission from '@/views/system/permission/index.vue'
import User from '@/views/system/user/User.vue'
+41 -40
View File
@@ -15,15 +15,16 @@
@on-click-side-bar-btn="hideSideBar"
/>
</el-aside>
<div v-if="!isAssistant && !chatListSideBarShow" class="hidden-sidebar-btn">
<div
v-if="isAssistant || !chatListSideBarShow"
class="hidden-sidebar-btn"
:class="{ 'assistant-popover-sidebar': isAssistant }"
>
<el-popover
:visible="isAssistant ? floatPopoverVisible : null"
:width="280"
placement="bottom-start"
popper-style="padding: 0;
height: 654px;
border: 1px solid rgba(222, 224, 227, 1);
border-radius: 6px;
"
:popper-style="{ ...defaultFloatPopoverStyle }"
>
<template #reference>
<el-button link type="primary" class="icon-btn" @click="showSideBar">
@@ -264,11 +265,11 @@
<template v-if="currentChat.datasource && currentChat.datasource_name">
{{ t('qa.selected_datasource') }}:
<img
v-if="currentChatEngineType"
style="margin-left: 4px; margin-right: 4px"
:src="currentChatEngineType"
width="16px"
height="16px"
v-if="currentChatEngineType"
alt=""
/>
<span class="name">
@@ -339,8 +340,14 @@ import { useAssistantStore } from '@/stores/assistant'
const props = defineProps<{
startChatDsId?: number
}>()
const floatPopoverVisible = ref(false)
const assistantStore = useAssistantStore()
const defaultFloatPopoverStyle = ref({
padding: '0',
height: '654px',
border: '1px solid rgba(222, 224, 227, 1)',
borderRadius: '6px',
})
const isAssistant = computed(() => assistantStore.getAssistant)
@@ -444,26 +451,6 @@ const currentChatEngineType = computed(() => {
return (dsTypeWithImg.find((ele) => currentChat.value.ds_type === ele.type) || {}).img
})
function toAssistantHistory(chat: Chat) {
currentChat.value = new ChatInfo(chat)
if (chat !== undefined && chat.id !== undefined && !loading.value) {
currentChatId.value = chat.id
loading.value = true
chatApi
.get(chat.id)
.then((res) => {
const info = chatApi.toChatInfo(res)
if (info) {
currentChat.value = info
onClickHistory(info)
}
})
.finally(() => {
loading.value = false
})
}
}
function onChatDeleted(id: number) {
console.log('deleted', id)
}
@@ -474,6 +461,10 @@ function onChatRenamed(chat: Chat) {
const chatListSideBarShow = ref<boolean>(true)
function hideSideBar() {
if (isAssistant.value) {
floatPopoverVisible.value = false
return
}
chatListSideBarShow.value = false
}
@@ -714,13 +705,6 @@ const handleCtrlEnter = (e: KeyboardEvent) => {
})
}
const getHistoryList = () => {
return chatList.value
}
const getCurrentChatId = () => {
return currentChatId.value
}
const inputRef = ref()
function clickInput() {
@@ -768,12 +752,24 @@ function stop(func?: (...p: any[]) => void, ...param: any[]) {
func(...param)
}
}
const showFloatPopover = () => {
if (isAssistant.value && !floatPopoverVisible.value) {
floatPopoverVisible.value = true
}
}
const assistantPrepareInit = () => {
if (!isAssistant.value) {
return
}
Object.assign(defaultFloatPopoverStyle.value, {
height: '100% !important',
inset: '0px auto auto 0px',
})
goEmpty()
}
defineExpose({
getHistoryList,
toAssistantHistory,
getCurrentChatId,
createNewChat,
showFloatPopover,
})
const hiddenChatCreatorRef = ref()
@@ -791,6 +787,7 @@ function jumpCreatChat() {
onMounted(() => {
getChatList(jumpCreatChat)
assistantPrepareInit()
})
</script>
@@ -800,7 +797,11 @@ onMounted(() => {
position: relative;
border-radius: 12px;
.assistant-popover-sidebar {
button {
display: none;
}
}
.hidden-sidebar-btn {
z-index: 1;
position: absolute;
+75 -163
View File
@@ -1,69 +1,33 @@
<template>
<div class="sqlbot-assistant-container">
<div class="head">
<div class="flex align-center">
<div class="head-img-div">
<img :src="AssistantGif" />
</div>
<h4>SQLBot 小助手</h4>
</div>
<div class="header">
<el-icon size="20" @click="openHistory">
<icon_sidebar_outlined></icon_sidebar_outlined>
</el-icon>
<img :src="LOGO" class="logo" width="30px" height="30px" alt="" />
<span class="tite">{{ $t('embedded.intelligent_customer_service') }}</span>
<el-tooltip
effect="dark"
:content="$t('embedded.new_conversation')"
placement="top"
@click="createChat"
>
<el-icon class="new-chat" size="20">
<icon_new_chat_outlined></icon_new_chat_outlined>
</el-icon>
</el-tooltip>
</div>
<chat-component v-if="!loading" ref="chatRef" class="sqlbot-chat-container" />
</div>
<div class="sqlbot-top-btn">
<el-icon style="cursor: pointer" @click="createChat">
<icon_new_chat_outlined />
</el-icon>
<el-icon style="cursor: pointer" @click="openHistory">
<history></history>
</el-icon>
</div>
<div class="sqlbot-history-container">
<el-drawer
v-model="drawer"
:append-to-body="false"
class="sqlbot-history-drawer"
modal-class="sqlbot-history-modal"
title=""
direction="ttb"
:with-header="false"
>
<div class="sqlbot-history-title">
<span>历史记录</span>
</div>
<div class="sqlbot-history-content">
<div v-if="!chatList.length" class="history-empty">
<span>暂无历史记录</span>
</div>
<div v-else class="sqlbot-chat-list-inner">
<el-scrollbar max-height="350px" class="sqlbot-chat-scroller">
<template v-for="chat in chatList" :key="chat.id">
<div
class="chat-list-item"
:class="{ 'is-active-chat': currentId === chat.id }"
@click="onClickHistory(chat)"
>
<span class="title">{{ chat.brief ?? 'Untitled' }}</span>
<!-- <div class="history-operate">
<el-icon @click="EditPen(chat)"><IconOpeEdit /></el-icon>
<el-icon @click="Delete(chat)"><IconOpeDelete /></el-icon>
</div> -->
</div>
</template>
</el-scrollbar>
</div>
</div>
</el-drawer>
<div class="drawer-assistant" @click="openHistory"></div>
</div>
</template>
<script setup lang="ts">
import { onBeforeMount, onBeforeUnmount, ref } from 'vue'
import ChatComponent from '@/views/chat/index.vue'
import AssistantGif from '@/assets/img/assistant.gif'
import history from '@/assets/svg/chart/history.svg'
import LOGO from '@/assets/embedded/LOGO.png'
import icon_sidebar_outlined from '@/assets/embedded/icon_sidebar_outlined.svg'
import icon_new_chat_outlined from '@/assets/svg/icon_new_chat_outlined.svg'
/* import IconOpeEdit from '@/assets/svg/operate/ope-edit.svg'
import IconOpeDelete from '@/assets/svg/operate/ope-delete.svg' */
import { useRoute } from 'vue-router'
import { assistantApi } from '@/api/assistant'
import { useAssistantStore } from '@/stores/assistant'
@@ -72,28 +36,14 @@ const assistantStore = useAssistantStore()
const route = useRoute()
const chatRef = ref()
const chatList = ref<Array<any>>([])
const drawer = ref(false)
const currentId = ref()
const createChat = () => {
chatRef.value?.createNewChat()
}
const openHistory = () => {
chatList.value = chatRef.value?.getHistoryList()
currentId.value = chatRef.value?.getCurrentChatId()
drawer.value = true
}
const onClickHistory = (chat: any) => {
chatRef.value?.toAssistantHistory(chat)
chatRef.value?.showFloatPopover()
}
/* const EditPen = (chat: any) => {
chatRef.value?.onChatRenamed(chat)
}
const Delete = (chat: any) => {
chatRef.value?.onChatDeleted(chat.id)
} */
const validator = ref({
id: '',
valid: false,
@@ -151,31 +101,58 @@ onBeforeUnmount(() => {
height: 100%;
width: 100%;
color: rgb(31, 35, 41);
.flex {
display: flex;
}
.head {
background: linear-gradient(90deg, #ebf1ff 24.34%, #e5fbf8 56.18%, #f2ebfe 90.18%);
position: fixed;
.header {
width: 100%;
left: 0;
top: 0;
z-index: 100;
height: 56px;
line-height: 56px;
box-sizing: border-box;
border-bottom: 1px solid #dee0e3;
.align-center {
align-items: center;
.head-img-div {
display: flex;
margin-left: 24px;
img {
width: 32px;
height: 32px;
background: #1cba9014;
height: 56px;
padding: 0 16px;
display: flex;
align-items: center;
position: fixed;
.logo {
margin: 0 8px 0 16px;
}
.title {
font-weight: 500;
font-size: 16px;
line-height: 24px;
}
.ed-icon {
position: relative;
cursor: pointer;
&::after {
content: '';
background-color: #1f23291a;
position: absolute;
border-radius: 6px;
width: 28px;
height: 28px;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
display: none;
}
&:hover {
&::after {
display: block;
}
}
}
.new-chat {
position: absolute;
right: 88px;
top: 17px;
}
}
.sqlbot-chat-container {
padding-top: 56px;
@@ -183,82 +160,17 @@ onBeforeUnmount(() => {
display: none;
}
}
}
.sqlbot-top-btn {
right: 85px;
z-index: 2009;
position: fixed;
top: 16px;
display: flex;
column-gap: 16px;
// right: 16px;
font-size: 22px;
i:first-child {
color: var(--primary-color);
}
}
.sqlbot-history-container {
width: 100%;
:deep(.sqlbot-history-modal) {
top: 56px !important;
}
:deep(.sqlbot-history-title) {
border-bottom: 1px solid #dee0e3;
padding: 16px 24px;
font-size: 14px;
font-weight: 500;
color: #1f2329;
}
:deep(.ed-drawer__body) {
padding: 0 !important;
}
:deep(.sqlbot-history-drawer) {
height: fit-content !important;
.sqlbot-history-content {
padding: 16px;
.history-empty {
height: 60px;
color: #8f959e !important;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
}
.is-active-chat {
background-color: #ebf1ff;
color: #3370ff;
font-weight: 500;
}
.chat-list-item {
display: flex;
align-items: center;
padding: 10px 8px;
font-size: 14px;
color: #1f2329;
justify-content: space-between;
.history-operate {
display: none;
}
&:hover {
cursor: pointer;
border-radius: 4px;
background: rgba(31, 35, 41, 0.1);
.history-operate {
padding-right: 16px;
display: flex;
column-gap: 16px;
align-items: center;
font-size: 18px;
i {
color: #8f959e;
&:hover {
color: #8f959e99;
}
}
}
}
}
}
.drawer-assistant {
height: 100%;
position: absolute;
left: 0;
top: 0;
width: 50%;
background: #f5f6f7;
box-shadow: 0px 6px 24px 0px #1f232914;
padding: 16px;
border-right: 1px solid #dee0e3;
display: none;
}
}
</style>
+2 -2
View File
@@ -426,9 +426,9 @@ const saveHandler = () => {
<el-button :class="[btnSelect === 'd' && 'is-active']" text @click="btnSelect = 'd'">
{{ t('embedded.embedded_assistant') }}
</el-button>
<el-button :class="[btnSelect === 'q' && 'is-active']" text @click="btnSelect = 'q'">
<!-- <el-button :class="[btnSelect === 'q' && 'is-active']" text @click="btnSelect = 'q'">
{{ t('embedded.embedded_page') }}
</el-button>
</el-button> -->
</div>
<div>
<el-input