|
@@ -0,0 +1,104 @@
|
|
|
+<!-- 知识引用组件 -->
|
|
|
+<template>
|
|
|
+ <!-- 知识引用列表 -->
|
|
|
+ <div v-if="segments && segments.length > 0" class="mt-10px p-10px rounded-8px bg-[#f5f5f5]">
|
|
|
+ <div class="text-14px text-[#666] mb-8px flex items-center">
|
|
|
+ <Icon icon="ep:document" class="mr-5px" /> 知识引用
|
|
|
+ </div>
|
|
|
+ <div class="flex flex-wrap gap-8px">
|
|
|
+ <div
|
|
|
+ v-for="(doc, index) in documentList"
|
|
|
+ :key="index"
|
|
|
+ class="p-8px px-12px bg-white rounded-6px cursor-pointer transition-all hover:bg-[#e6f4ff]"
|
|
|
+ @click="handleClick(doc)"
|
|
|
+ >
|
|
|
+ <div class="text-14px text-[#333] mb-4px">
|
|
|
+ {{ doc.title }}
|
|
|
+ <span class="text-12px text-[#999] ml-4px">({{ doc.segments.length }} 条)</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 知识引用详情弹窗 -->
|
|
|
+ <el-popover
|
|
|
+ v-model:visible="dialogVisible"
|
|
|
+ :width="600"
|
|
|
+ trigger="click"
|
|
|
+ placement="top-start"
|
|
|
+ :offset="55"
|
|
|
+ popper-class="knowledge-popover"
|
|
|
+ >
|
|
|
+ <template #reference>
|
|
|
+ <div ref="documentRef"></div>
|
|
|
+ </template>
|
|
|
+ <template #default>
|
|
|
+ <div class="text-16px font-bold mb-12px">{{ document?.title }}</div>
|
|
|
+ <div class="max-h-[60vh] overflow-y-auto">
|
|
|
+ <div
|
|
|
+ v-for="(segment, index) in document?.segments"
|
|
|
+ :key="index"
|
|
|
+ class="p-12px border-b-solid border-b-[#eee] last:border-b-0"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="block mb-8px px-8px py-2px bg-[#f5f5f5] rounded-4px text-12px text-[#666] w-fit"
|
|
|
+ >
|
|
|
+ 分段 {{ segment.id }}
|
|
|
+ </div>
|
|
|
+ <div class="text-14px leading-[1.6] text-[#333] mt-[10px]">
|
|
|
+ {{ segment.content }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-popover>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+const props = defineProps<{
|
|
|
+ segments: {
|
|
|
+ id: number
|
|
|
+ documentId: number
|
|
|
+ documentName: string
|
|
|
+ content: string
|
|
|
+ }[]
|
|
|
+}>()
|
|
|
+
|
|
|
+const document = ref<{
|
|
|
+ id: number
|
|
|
+ title: string
|
|
|
+ segments: {
|
|
|
+ id: number
|
|
|
+ content: string
|
|
|
+ }[]
|
|
|
+} | null>(null) // 知识库文档列表
|
|
|
+const dialogVisible = ref(false) // 知识引用详情弹窗
|
|
|
+const documentRef = ref<HTMLElement>() // 知识引用详情弹窗 Ref
|
|
|
+
|
|
|
+/** 按照 document 聚合 segments */
|
|
|
+const documentList = computed(() => {
|
|
|
+ if (!props.segments) return []
|
|
|
+
|
|
|
+ const docMap = new Map()
|
|
|
+ props.segments.forEach((segment) => {
|
|
|
+ if (!docMap.has(segment.documentId)) {
|
|
|
+ docMap.set(segment.documentId, {
|
|
|
+ id: segment.documentId,
|
|
|
+ title: segment.documentName,
|
|
|
+ segments: []
|
|
|
+ })
|
|
|
+ }
|
|
|
+ docMap.get(segment.documentId).segments.push({
|
|
|
+ id: segment.id,
|
|
|
+ content: segment.content
|
|
|
+ })
|
|
|
+ })
|
|
|
+ return Array.from(docMap.values())
|
|
|
+})
|
|
|
+
|
|
|
+/** 点击 document 处理 */
|
|
|
+const handleClick = (doc: any) => {
|
|
|
+ document.value = doc
|
|
|
+ dialogVisible.value = true
|
|
|
+}
|
|
|
+</script>
|