|
@@ -1,7 +1,7 @@
|
|
|
<script setup lang="ts">
|
|
|
import { AResultRecord } from '@/hooks/web/useSSE'
|
|
|
-import PDFLink from '@/views/OaSystem/aiQA/components/PDFLink.vue'
|
|
|
import ResultMessageView from '@/views/OaSystem/aiQA/components/ResultMessageView.vue'
|
|
|
+import PDFView from '@/components/PDF/PDFView.vue'
|
|
|
|
|
|
interface AResultProps {
|
|
|
data: AResultRecord
|
|
@@ -9,19 +9,82 @@ interface AResultProps {
|
|
|
|
|
|
const props = defineProps<AResultProps>()
|
|
|
const { data } = toRefs(props)
|
|
|
+// 格式化处理pdf文件
|
|
|
+const pdfFiles = computed(() => {
|
|
|
+ return (data?.value?.result?.['0']?.docs ?? [])?.map((text) => {
|
|
|
+ // 提取索引号(假设索引号是第一个方括号中的数字)
|
|
|
+ const indexMatch = text.match(/\[\[(\d+)\]\]/)
|
|
|
+ const index = indexMatch != null ? indexMatch[1] : null
|
|
|
+ // 提取名称和链接(Markdown格式的链接)
|
|
|
+ const linkMatch = text.match(/\[(.*?)\]\((.*?)\)/)
|
|
|
+ const name = linkMatch != null ? `[${linkMatch[1]}]` : null
|
|
|
+ const link = linkMatch != null ? linkMatch[2] : null
|
|
|
+ // 提取内容(链接之后的所有文本)
|
|
|
+ const contentStartIndex = text.indexOf('](') + 2 // 链接结束的位置
|
|
|
+ let content = text.slice(contentStartIndex).trim()
|
|
|
+ // 清理内容中的Markdown链接残留(如果有)
|
|
|
+ content = content.replace(/\]\(.*?\)/g, '').trim()
|
|
|
+ return {
|
|
|
+ index,
|
|
|
+ name,
|
|
|
+ link,
|
|
|
+ content
|
|
|
+ }
|
|
|
+ })
|
|
|
+})
|
|
|
+const dialogVisible = ref(false)
|
|
|
+const pdfIndex = ref<string>()
|
|
|
+const targetViewPdf = computed(() =>
|
|
|
+ pdfFiles.value?.find?.(({ index }) => String(index) === String(pdfIndex.value))
|
|
|
+)
|
|
|
+
|
|
|
+const handlePdfView = (fileIndex: string): void => {
|
|
|
+ if (pdfFiles.value?.some(({ index }) => String(index) === String(fileIndex))) {
|
|
|
+ pdfIndex.value = fileIndex
|
|
|
+ dialogVisible.value = true
|
|
|
+ } else {
|
|
|
+ console.log('未找到文件')
|
|
|
+ }
|
|
|
+}
|
|
|
+const handleClose = (): void => {
|
|
|
+ pdfIndex.value = undefined
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
<div class="a-result-body">
|
|
|
- <ResultMessageView :data="data?.result?.['3']?.choices?.[0]?.delta?.content" />
|
|
|
- <div class="result-files" v-if="(data?.result?.['0']?.docs?.length ?? 0) > 0">
|
|
|
+ <ResultMessageView
|
|
|
+ :data="data?.result?.['3']?.choices?.[0]?.delta?.content"
|
|
|
+ :handlePDFView="handlePdfView"
|
|
|
+ />
|
|
|
+ <div class="result-files" v-if="(pdfFiles?.length ?? 0) > 0">
|
|
|
<div class="label">【来源文件】:</div>
|
|
|
<div class="files-container">
|
|
|
- <div class="file" v-for="file in data?.result?.['0']?.docs" :key="file">
|
|
|
- <PDFLink :data="file" />
|
|
|
- </div>
|
|
|
+ <template v-for="file in pdfFiles" :key="file?.index">
|
|
|
+ <div v-if="file" class="file" @click="handlePdfView(file.index)">
|
|
|
+ <span>{{ file?.name ?? '' }}</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <!-- PDF预览弹窗 -->
|
|
|
+ <el-dialog
|
|
|
+ :title="targetViewPdf?.name ?? ''"
|
|
|
+ v-model="dialogVisible"
|
|
|
+ width="80%"
|
|
|
+ @close="handleClose"
|
|
|
+ append-to-body
|
|
|
+ destroy-on-close
|
|
|
+ >
|
|
|
+ <div class="pdf-view-body">
|
|
|
+ <PDFView
|
|
|
+ v-if="targetViewPdf?.link"
|
|
|
+ :url="targetViewPdf?.link"
|
|
|
+ :highLightContent="targetViewPdf?.content"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <template #footer></template>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -40,13 +103,24 @@ const { data } = toRefs(props)
|
|
|
flex-grow: 1;
|
|
|
|
|
|
.file {
|
|
|
+ cursor: pointer;
|
|
|
padding: 10px;
|
|
|
- color: #888;
|
|
|
+ color: #666;
|
|
|
margin-bottom: 10px;
|
|
|
background: #f1f9ff;
|
|
|
border-radius: 8px;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ text-decoration: underline;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+.pdf-view-body {
|
|
|
+ width: 100%;
|
|
|
+ height: 70vh;
|
|
|
+ overflow-y: auto;
|
|
|
+}
|
|
|
</style>
|