2025-08-05 15:08:07 +08:00
|
|
|
<template>
|
2025-09-17 16:02:08 +08:00
|
|
|
<div class="dialogue-wrap">
|
2025-08-05 15:08:07 +08:00
|
|
|
<div class="dialogue-answers">
|
|
|
|
|
<div class="dialogue-title">
|
2025-11-05 07:32:16 +03:00
|
|
|
<span>{{ t('chat.knowledgeBaseQandA') }}</span>
|
2025-08-05 15:08:07 +08:00
|
|
|
</div>
|
|
|
|
|
<InputField @send-msg="sendMsg"></InputField>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-09-17 16:02:08 +08:00
|
|
|
|
|
|
|
|
|
2025-11-05 07:32:16 +03:00
|
|
|
<t-dialog v-model:visible="selectVisible" :header="t('knowledgeBase.title')" :confirmBtn="{ content: t('chat.newChat'), theme: 'primary' }" :onConfirm="confirmSelect" :onCancel="() => selectVisible = false">
|
2025-09-17 16:02:08 +08:00
|
|
|
<t-form :data="{ kb: selectedKbId }">
|
2025-11-05 07:32:16 +03:00
|
|
|
<t-form-item :label="t('knowledgeBase.title')">
|
|
|
|
|
<t-select v-model="selectedKbId" :loading="kbLoading" :placeholder="t('knowledgeBase.selectKnowledgeBaseFirst')">
|
2025-09-17 16:02:08 +08:00
|
|
|
<t-option v-for="kb in kbList" :key="kb.id" :value="kb.id" :label="kb.name" />
|
|
|
|
|
</t-select>
|
|
|
|
|
</t-form-item>
|
|
|
|
|
</t-form>
|
|
|
|
|
</t-dialog>
|
2025-08-05 15:08:07 +08:00
|
|
|
</template>
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { ref, onUnmounted, watch } from 'vue';
|
2025-11-05 07:32:16 +03:00
|
|
|
import { useI18n } from 'vue-i18n';
|
2025-08-05 15:08:07 +08:00
|
|
|
import InputField from '@/components/Input-field.vue';
|
|
|
|
|
import EmptyKnowledge from '@/components/empty-knowledge.vue';
|
|
|
|
|
import { getSessionsList, createSessions, generateSessionsTitle } from "@/api/chat/index";
|
|
|
|
|
import { useMenuStore } from '@/stores/menu';
|
|
|
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
|
|
|
import useKnowledgeBase from '@/hooks/useKnowledgeBase';
|
2025-09-17 16:02:08 +08:00
|
|
|
import { listKnowledgeBases } from '@/api/knowledge-base';
|
2025-08-05 15:08:07 +08:00
|
|
|
|
2025-11-05 07:32:16 +03:00
|
|
|
const { t } = useI18n();
|
|
|
|
|
|
2025-08-05 15:08:07 +08:00
|
|
|
let { cardList } = useKnowledgeBase()
|
|
|
|
|
const router = useRouter();
|
2025-09-17 16:02:08 +08:00
|
|
|
const route = useRoute();
|
2025-08-05 15:08:07 +08:00
|
|
|
const usemenuStore = useMenuStore();
|
|
|
|
|
const sendMsg = (value: string) => {
|
|
|
|
|
createNewSession(value);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-17 16:02:08 +08:00
|
|
|
const selectVisible = ref(false)
|
|
|
|
|
const selectedKbId = ref<string>('')
|
|
|
|
|
const kbList = ref<Array<{ id: string; name: string }>>([])
|
|
|
|
|
const kbLoading = ref(false)
|
|
|
|
|
|
|
|
|
|
const ensureKbId = async (): Promise<string | null> => {
|
|
|
|
|
// 1) 优先使用当前路由上下文(如果来自某个知识库详情页)
|
|
|
|
|
const routeKb = (route.params as any)?.kbId as string
|
|
|
|
|
if (routeKb) return routeKb
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 3) 弹窗选择知识库(从接口拉取)
|
|
|
|
|
kbLoading.value = true
|
|
|
|
|
try {
|
|
|
|
|
const res: any = await listKnowledgeBases()
|
|
|
|
|
kbList.value = res?.data || []
|
|
|
|
|
if (kbList.value.length === 0) return null
|
|
|
|
|
selectedKbId.value = kbList.value[0].id
|
|
|
|
|
selectVisible.value = true
|
|
|
|
|
return null
|
|
|
|
|
} finally {
|
|
|
|
|
kbLoading.value = false
|
2025-08-05 15:08:07 +08:00
|
|
|
}
|
2025-09-17 16:02:08 +08:00
|
|
|
}
|
2025-08-05 15:08:07 +08:00
|
|
|
|
2025-09-17 16:02:08 +08:00
|
|
|
async function createNewSession(value: string) {
|
|
|
|
|
let knowledgeBaseId = await ensureKbId()
|
|
|
|
|
if (!knowledgeBaseId) {
|
|
|
|
|
// 等待用户在弹窗中选择
|
|
|
|
|
pendingValue.value = value
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-08-05 15:08:07 +08:00
|
|
|
|
2025-09-17 16:02:08 +08:00
|
|
|
createSessions({ knowledge_base_id: knowledgeBaseId }).then(async res => {
|
2025-08-05 15:08:07 +08:00
|
|
|
if (res.data && res.data.id) {
|
2025-09-17 16:02:08 +08:00
|
|
|
await getTitle(res.data.id, value)
|
2025-08-05 15:08:07 +08:00
|
|
|
} else {
|
|
|
|
|
// 错误处理
|
2025-11-05 07:32:16 +03:00
|
|
|
console.error(t('chat.createSessionFailed'));
|
2025-08-05 15:08:07 +08:00
|
|
|
}
|
|
|
|
|
}).catch(error => {
|
2025-11-05 07:32:16 +03:00
|
|
|
console.error(t('chat.createSessionError') + ':', error);
|
2025-08-05 15:08:07 +08:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-17 16:02:08 +08:00
|
|
|
const pendingValue = ref<string>('')
|
|
|
|
|
const confirmSelect = async () => {
|
|
|
|
|
if (!selectedKbId.value) return
|
|
|
|
|
const value = pendingValue.value
|
|
|
|
|
pendingValue.value = ''
|
|
|
|
|
selectVisible.value = false
|
|
|
|
|
createSessions({ knowledge_base_id: selectedKbId.value }).then(async res => {
|
|
|
|
|
if (res.data && res.data.id) {
|
|
|
|
|
await getTitle(res.data.id, value, selectedKbId.value)
|
|
|
|
|
} else {
|
2025-11-05 07:32:16 +03:00
|
|
|
console.error(t('chat.createSessionFailed'))
|
2025-09-17 16:02:08 +08:00
|
|
|
}
|
2025-11-05 07:32:16 +03:00
|
|
|
}).catch((e:any) => console.error(t('chat.createSessionError') + ':', e))
|
2025-09-17 16:02:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getTitle = async (session_id: string, value: string, kbId?: string) => {
|
|
|
|
|
const finalKbId = kbId || await ensureKbId();
|
|
|
|
|
if (!finalKbId) {
|
2025-11-05 07:32:16 +03:00
|
|
|
console.error(t('chat.unableToGetKnowledgeBaseId'));
|
2025-09-17 16:02:08 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-05 07:32:16 +03:00
|
|
|
let obj = { title: t('menu.newSession'), path: `chat/${finalKbId}/${session_id}`, id: session_id, isMore: false, isNoTitle: true }
|
2025-08-05 15:08:07 +08:00
|
|
|
usemenuStore.updataMenuChildren(obj);
|
|
|
|
|
usemenuStore.changeIsFirstSession(true);
|
|
|
|
|
usemenuStore.changeFirstQuery(value);
|
2025-09-17 16:02:08 +08:00
|
|
|
router.push(`/platform/chat/${finalKbId}/${session_id}`);
|
2025-08-05 15:08:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
<style lang="less" scoped>
|
|
|
|
|
.dialogue-wrap {
|
|
|
|
|
flex: 1;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
// position: relative;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dialogue-answers {
|
|
|
|
|
position: absolute;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-flow: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
:deep(.answers-input) {
|
|
|
|
|
position: static;
|
|
|
|
|
transform: translateX(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dialogue-title {
|
|
|
|
|
display: flex;
|
|
|
|
|
color: #000000;
|
|
|
|
|
font-family: "PingFang SC";
|
|
|
|
|
font-size: 28px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-bottom: 30px;
|
|
|
|
|
|
|
|
|
|
.icon {
|
|
|
|
|
display: flex;
|
|
|
|
|
width: 32px;
|
|
|
|
|
height: 32px;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
background: #FFF;
|
|
|
|
|
box-shadow: 0 0 2px -1px #0000001f;
|
|
|
|
|
margin-right: 12px;
|
|
|
|
|
|
|
|
|
|
.logo_img {
|
|
|
|
|
height: 24px;
|
|
|
|
|
width: 24px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 1250px) and (min-width: 1045px) {
|
|
|
|
|
.answers-input {
|
|
|
|
|
transform: translateX(-329px);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.t-textarea__inner) {
|
|
|
|
|
width: 654px !important;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 1045px) {
|
|
|
|
|
.answers-input {
|
|
|
|
|
transform: translateX(-250px);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.t-textarea__inner) {
|
|
|
|
|
width: 500px !important;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
|
|
.answers-input {
|
|
|
|
|
transform: translateX(-250px);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.t-textarea__inner) {
|
|
|
|
|
width: 340px !important;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@media (max-width: 600px) {
|
|
|
|
|
.answers-input {
|
|
|
|
|
transform: translateX(-250px);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.t-textarea__inner) {
|
|
|
|
|
width: 300px !important;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
</style>
|
|
|
|
|
<style lang="less">
|
|
|
|
|
.del-menu-popup {
|
|
|
|
|
z-index: 99 !important;
|
|
|
|
|
|
|
|
|
|
.t-popup__content {
|
|
|
|
|
width: 100px;
|
|
|
|
|
height: 40px;
|
|
|
|
|
line-height: 30px;
|
|
|
|
|
padding-left: 14px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
margin-top: 4px !important;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|