mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 07:03:53 +08:00
update: 知识库页面复用弹窗、分页组件,同步修改样式
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 769 B |
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-dialog :title="title" :visible="dialogVisible" width="600px" class="knowledge-base-dialog" @close="handleClose">
|
||||
<CustomDialog :title="title" :visible.sync="dialogVisible" width="600px" class="knowledge-base-dialog" @close="handleClose" @confirm="handleSubmit">
|
||||
<el-form ref="knowledgeBaseForm" :model="form" :rules="rules" label-width="100px" size="medium">
|
||||
<el-form-item :label="$t('knowledgeBaseDialog.name')" prop="name">
|
||||
<el-input v-model="form.name" :placeholder="$t('knowledgeBaseDialog.namePlaceholder')" clearable></el-input>
|
||||
@@ -16,15 +16,12 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="handleClose">{{ $t('knowledgeBaseDialog.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">{{ $t('knowledgeBaseDialog.confirm') }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</CustomDialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Api from "@/apis/api";
|
||||
import CustomDialog from "./CustomDialog.vue";
|
||||
|
||||
export default {
|
||||
name: "KnowledgeBaseDialog",
|
||||
@@ -93,6 +90,9 @@ export default {
|
||||
}
|
||||
};
|
||||
},
|
||||
components: {
|
||||
CustomDialog
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
this.dialogVisible = val;
|
||||
|
||||
@@ -1351,6 +1351,7 @@ export default {
|
||||
'knowledgeFileUpload.confirmParse': 'Sind Sie sicher, dass Sie dieses Dokument parsen möchten?',
|
||||
'knowledgeFileUpload.nameRequired': 'Bitte Dokumentnamen eingeben',
|
||||
'knowledgeFileUpload.fileRequired': 'Bitte wählen Sie eine Datei zum Hochladen aus',
|
||||
'knowledgeFileUpload.fileSizeExceeded': 'Dateigröße darf 10MB nicht überschreiten!',
|
||||
'knowledgeFileUpload.getListFailed': 'Dokumentenliste konnte nicht abgerufen werden',
|
||||
'knowledgeFileUpload.parseCancelled': 'Parsen abgebrochen',
|
||||
'knowledgeFileUpload.deleteCancelled': 'Löschen abgebrochen',
|
||||
@@ -1384,6 +1385,7 @@ export default {
|
||||
'knowledgeFileUpload.comprehensiveSimilarity': 'Umfassende Ähnlichkeit',
|
||||
'knowledgeFileUpload.content': 'Inhalt:',
|
||||
'knowledgeFileUpload.testQuestionRequired': 'Bitte Testfrage eingeben',
|
||||
'knowledgeFileUpload.sourceDocument': 'Quelldokument',
|
||||
'knowledgeFileUpload.parsing': 'Analysiere...',
|
||||
'knowledgeBaseDialog.descriptionRequired': 'Bitte Wissensbasis-Beschreibung eingeben',
|
||||
|
||||
|
||||
@@ -1351,6 +1351,7 @@ export default {
|
||||
'knowledgeFileUpload.confirmParse': 'Are you sure you want to parse this document?',
|
||||
'knowledgeFileUpload.nameRequired': 'Please enter document name',
|
||||
'knowledgeFileUpload.fileRequired': 'Please select a file to upload',
|
||||
'knowledgeFileUpload.fileSizeExceeded': 'File size cannot exceed 10MB!',
|
||||
'knowledgeFileUpload.getListFailed': 'Failed to get document list',
|
||||
'knowledgeFileUpload.parseCancelled': 'Parse cancelled',
|
||||
'knowledgeFileUpload.deleteCancelled': 'Delete cancelled',
|
||||
@@ -1382,6 +1383,7 @@ export default {
|
||||
'knowledgeFileUpload.testResult': 'Test Result:',
|
||||
'knowledgeFileUpload.noRelatedSlices': 'No related slices found',
|
||||
'knowledgeFileUpload.comprehensiveSimilarity': 'Comprehensive Similarity',
|
||||
'knowledgeFileUpload.sourceDocument': 'Source Document',
|
||||
'knowledgeFileUpload.content': 'Content:',
|
||||
'knowledgeFileUpload.testQuestionRequired': 'Please enter test question',
|
||||
'knowledgeFileUpload.parsing': 'Parsing...',
|
||||
|
||||
@@ -1351,6 +1351,7 @@ export default {
|
||||
'knowledgeFileUpload.confirmParse': 'Tem certeza de que deseja analisar este documento?',
|
||||
'knowledgeFileUpload.nameRequired': 'Por favor, insira o nome do documento',
|
||||
'knowledgeFileUpload.fileRequired': 'Por favor, selecione um arquivo para enviar',
|
||||
'knowledgeFileUpload.fileSizeExceeded': 'O tamanho do arquivo não pode exceder 10MB!',
|
||||
'knowledgeFileUpload.getListFailed': 'Falha ao obter lista de documentos',
|
||||
'knowledgeFileUpload.parseCancelled': 'Análise cancelada',
|
||||
'knowledgeFileUpload.deleteCancelled': 'Exclusão cancelada',
|
||||
@@ -1384,6 +1385,7 @@ export default {
|
||||
'knowledgeFileUpload.comprehensiveSimilarity': 'Similaridade Geral',
|
||||
'knowledgeFileUpload.content': 'Conteúdo:',
|
||||
'knowledgeFileUpload.testQuestionRequired': 'Por favor, insira a pergunta de teste',
|
||||
'knowledgeFileUpload.sourceDocument': 'Documento de origem',
|
||||
'knowledgeFileUpload.parsing': 'Analisando...',
|
||||
'knowledgeBaseDialog.descriptionRequired': 'Por favor, insira a descrição da base de conhecimento',
|
||||
|
||||
|
||||
@@ -1351,6 +1351,7 @@ export default {
|
||||
'knowledgeFileUpload.confirmParse': 'Bạn có chắc chắn muốn phân tích cú pháp tài liệu này?',
|
||||
'knowledgeFileUpload.nameRequired': 'Vui lòng nhập tên tài liệu',
|
||||
'knowledgeFileUpload.fileRequired': 'Vui lòng chọn tệp để tải lên',
|
||||
'knowledgeFileUpload.fileSizeExceeded': 'Kích thước tệp không được vượt quá 10MB!',
|
||||
'knowledgeFileUpload.getListFailed': 'Không thể lấy danh sách tài liệu',
|
||||
'knowledgeFileUpload.parseCancelled': 'Đã hủy phân tích cú pháp',
|
||||
'knowledgeFileUpload.deleteCancelled': 'Đã hủy xóa',
|
||||
@@ -1384,6 +1385,7 @@ export default {
|
||||
'knowledgeFileUpload.comprehensiveSimilarity': 'Độ tương đồng toàn diện',
|
||||
'knowledgeFileUpload.content': 'Nội dung:',
|
||||
'knowledgeFileUpload.testQuestionRequired': 'Vui lòng nhập câu hỏi kiểm tra',
|
||||
'knowledgeFileUpload.sourceDocument': 'Tài liệu nguồn',
|
||||
'knowledgeFileUpload.parsing': 'Đang phân tích...',
|
||||
'knowledgeBaseDialog.descriptionRequired': 'Vui lòng nhập mô tả cơ sở kiến thức',
|
||||
|
||||
|
||||
@@ -1347,10 +1347,11 @@ export default {
|
||||
'knowledgeFileUpload.parseFailed': '文档解析失败',
|
||||
'knowledgeFileUpload.deleteSuccess': '文档删除成功',
|
||||
'knowledgeFileUpload.deleteFailed': '文档删除失败',
|
||||
'knowledgeFileUpload.confirmDelete': '确定要删除此文檔吗?',
|
||||
'knowledgeFileUpload.confirmDelete': '确定要删除此文档吗?',
|
||||
'knowledgeFileUpload.confirmParse': '确定要解析该文档吗?',
|
||||
'knowledgeFileUpload.nameRequired': '请输入文档名称',
|
||||
'knowledgeFileUpload.fileRequired': '请选择要上传的文件',
|
||||
'knowledgeFileUpload.fileSizeExceeded': '文件大小不能超过10MB!',
|
||||
'knowledgeFileUpload.getListFailed': '获取文档列表失败',
|
||||
'knowledgeFileUpload.parseCancelled': '已取消解析',
|
||||
'knowledgeFileUpload.deleteCancelled': '已取消删除',
|
||||
@@ -1382,6 +1383,7 @@ export default {
|
||||
'knowledgeFileUpload.testResult': '测试结果:',
|
||||
'knowledgeFileUpload.noRelatedSlices': '未找到相关切片',
|
||||
'knowledgeFileUpload.comprehensiveSimilarity': '综合相似度',
|
||||
'knowledgeFileUpload.sourceDocument': '来源文档',
|
||||
'knowledgeFileUpload.content': '内容:',
|
||||
'knowledgeFileUpload.testQuestionRequired': '请输入测试问题',
|
||||
'knowledgeBaseDialog.descriptionRequired': '请输入知识库描述',
|
||||
|
||||
@@ -1351,6 +1351,7 @@ export default {
|
||||
'knowledgeFileUpload.confirmParse': '確定要解析該文檔嗎?',
|
||||
'knowledgeFileUpload.nameRequired': '請輸入文檔名稱',
|
||||
'knowledgeFileUpload.fileRequired': '請選擇要上傳的文件',
|
||||
'knowledgeFileUpload.fileSizeExceeded': '文件大小不能超過10MB!',
|
||||
'knowledgeFileUpload.getListFailed': '獲取文檔列表失敗',
|
||||
'knowledgeFileUpload.parseCancelled': '已取消解析',
|
||||
'knowledgeFileUpload.deleteCancelled': '已取消删除',
|
||||
@@ -1384,6 +1385,7 @@ export default {
|
||||
'knowledgeFileUpload.comprehensiveSimilarity': '綜合相似度',
|
||||
'knowledgeFileUpload.content': '內容:',
|
||||
'knowledgeFileUpload.testQuestionRequired': '請輸入測試問題',
|
||||
'knowledgeFileUpload.sourceDocument': '來源文檔',
|
||||
'knowledgeFileUpload.parsing': '正在解析中...',
|
||||
'knowledgeBaseDialog.descriptionRequired': '請輸入知识库描述',
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="doc-section-header">
|
||||
<div class="doc-section-left">
|
||||
<div class="doc-section-title">{{`${$t('knowledgeBaseManagement.currentKnowledgeBaseDocuments')}(${kb?.name})`}}</div>
|
||||
<div class="doc-section-count" v-if="kb">{{ $t('knowledgeBaseManagement.totalDocuments', { total: documents.length }) }}</div>
|
||||
<div class="doc-section-count" v-if="kb">{{ $t('knowledgeBaseManagement.totalDocuments', { total }) }}</div>
|
||||
</div>
|
||||
<div class="doc-section-actions">
|
||||
<el-input
|
||||
@@ -61,7 +61,7 @@
|
||||
>
|
||||
{{ $t('knowledgeFileUpload.parse') }}
|
||||
</el-button>
|
||||
<el-button type="text" class="delete-btn" @click.stop="handleDelete(doc)">
|
||||
<el-button type="text" class="delete-btn" :loading="deleteLoadingMap[doc.id]" @click.stop="handleDelete(doc)">
|
||||
{{ $t('knowledgeBaseManagement.delete') }}
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -71,11 +71,20 @@
|
||||
<el-empty :description="$t('knowledgeBaseManagement.noData')"></el-empty>
|
||||
</div>
|
||||
</div>
|
||||
<CustomPagination
|
||||
:total="total"
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:page-size-options="pageSizeOptions"
|
||||
@page-change="handlePageChange"
|
||||
@size-change="handleSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Api from "@/apis/api";
|
||||
import CustomPagination from "@/components/CustomPagination.vue";
|
||||
|
||||
const iconMap = {
|
||||
pdf: require('@/assets/knowledge-base/pdf.png'),
|
||||
@@ -91,6 +100,7 @@ const iconMap = {
|
||||
|
||||
export default {
|
||||
name: 'LibraryItem',
|
||||
components: { CustomPagination },
|
||||
props: {
|
||||
kb: {
|
||||
type: Object,
|
||||
@@ -101,16 +111,23 @@ export default {
|
||||
return {
|
||||
documents: [],
|
||||
docLoading: false,
|
||||
deleteLoadingMap: {},
|
||||
searchDocName: '',
|
||||
total: 0,
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
pageSizeOptions: [10, 20, 50, 100],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
kb: {
|
||||
handler(newKb) {
|
||||
if (newKb && newKb.datasetId) {
|
||||
this.currentPage = 1;
|
||||
this.fetchDocuments();
|
||||
} else {
|
||||
this.documents = [];
|
||||
this.total = 0;
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
@@ -121,8 +138,8 @@ export default {
|
||||
if (!this.kb || !this.kb.datasetId) return;
|
||||
this.docLoading = true;
|
||||
const params = {
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
page: this.currentPage,
|
||||
page_size: this.pageSize,
|
||||
name: this.searchDocName
|
||||
};
|
||||
Api.knowledgeBase.getDocumentList(
|
||||
@@ -132,10 +149,12 @@ export default {
|
||||
this.docLoading = false;
|
||||
if (data && data.code === 0) {
|
||||
this.documents = data.data.list || [];
|
||||
this.total = data.data.total || 0;
|
||||
this.fetchSliceCountsForDocuments();
|
||||
} else {
|
||||
this.$message.error(data?.msg || '获取文档列表失败');
|
||||
this.documents = [];
|
||||
this.total = 0;
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
@@ -146,11 +165,24 @@ export default {
|
||||
this.$message.error('获取文档列表失败');
|
||||
}
|
||||
this.documents = [];
|
||||
this.total = 0;
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
handleSearch() {
|
||||
this.currentPage = 1;
|
||||
this.fetchDocuments();
|
||||
},
|
||||
|
||||
handlePageChange(page) {
|
||||
this.currentPage = page;
|
||||
this.fetchDocuments();
|
||||
},
|
||||
|
||||
handleSizeChange(size) {
|
||||
this.pageSize = size;
|
||||
this.currentPage = 1;
|
||||
this.fetchDocuments();
|
||||
},
|
||||
|
||||
@@ -173,14 +205,20 @@ export default {
|
||||
type: 'warning'
|
||||
}
|
||||
).then(() => {
|
||||
this.$set(this.deleteLoadingMap, doc.id, true);
|
||||
Api.knowledgeBase.deleteDocument(this.kb.datasetId, doc.id, (res) => {
|
||||
this.$set(this.deleteLoadingMap, doc.id, false);
|
||||
if (res.data && res.data.code === 0) {
|
||||
if (this.documents.length === 1 && this.currentPage > 1) {
|
||||
this.currentPage--;
|
||||
}
|
||||
this.fetchDocuments();
|
||||
this.$message.success(this.$t('knowledgeFileUpload.deleteSuccess'));
|
||||
} else {
|
||||
this.$message.error(res.data?.msg || this.$t('knowledgeFileUpload.deleteFailed'));
|
||||
}
|
||||
}, () => {
|
||||
this.$set(this.deleteLoadingMap, doc.id, false);
|
||||
this.$message.error(this.$t('knowledgeFileUpload.deleteFailed'));
|
||||
});
|
||||
}).catch(() => {});
|
||||
@@ -301,7 +339,7 @@ export default {
|
||||
|
||||
getProgressText(doc) {
|
||||
const code = doc.parseStatusCode;
|
||||
if (code === 3) return '✓';
|
||||
if (code === 3) return '100%';
|
||||
if (code === 1) {
|
||||
if (doc.chunkNum && doc.totalChunkNum) {
|
||||
return Math.round((doc.chunkNum / doc.totalChunkNum) * 100) + '%';
|
||||
@@ -377,13 +415,12 @@ export default {
|
||||
|
||||
.doc-section-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.doc-search-input {
|
||||
width: 200px;
|
||||
margin-left: 8px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* ========== Document Grid ========== */
|
||||
@@ -399,7 +436,7 @@ export default {
|
||||
}
|
||||
|
||||
.doc-card {
|
||||
height: 120px;
|
||||
max-height: 120px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 18px;
|
||||
|
||||
@@ -117,20 +117,18 @@
|
||||
/>
|
||||
|
||||
<!-- Slice Dialog -->
|
||||
<el-dialog
|
||||
<CustomDialog
|
||||
:title="`${$t('knowledgeFileUpload.viewSlices')} - ${currentDocumentName}`"
|
||||
:visible.sync="sliceDialogVisible"
|
||||
width="900px"
|
||||
:close-on-click-modal="false"
|
||||
width="1200px"
|
||||
:footer="false"
|
||||
>
|
||||
<div class="slice-management">
|
||||
<div v-loading="sliceLoading" class="slice-content-container">
|
||||
<div v-if="sliceList.length > 0" class="slice-cards-container">
|
||||
<div v-for="(slice, index) in sliceList" :key="index" class="slice-card">
|
||||
<div class="slice-header-info">
|
||||
<p><strong>{{ $t('knowledgeFileUpload.slice') }} {{ (sliceCurrentPage - 1) * slicePageSize + index + 1 }}</strong></p>
|
||||
</div>
|
||||
<div class="slice-card-content">
|
||||
<span class="clice-index">{{ $t('knowledgeFileUpload.slice') }} {{ (sliceCurrentPage - 1) * slicePageSize + index + 1 }}</span>
|
||||
<div class="content-text">{{ slice.content }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -140,30 +138,31 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="slice-pagination">
|
||||
<el-select v-model="slicePageSize" @change="handleSliceSizeChange" class="slice-page-size-select">
|
||||
<el-option v-for="item in [10, 20, 50]" :key="item" :label="`${item}${$t('knowledgeFileUpload.itemsPerPage')}`" :value="item"></el-option>
|
||||
</el-select>
|
||||
<button class="slice-page-btn" :disabled="sliceCurrentPage === 1" @click="sliceCurrentPage = 1; fetchSlices()">{{ $t('knowledgeBaseManagement.firstPage') }}</button>
|
||||
<button class="slice-page-btn" :disabled="sliceCurrentPage === 1" @click="sliceCurrentPage--; fetchSlices()">{{ $t('knowledgeBaseManagement.prevPage') }}</button>
|
||||
<button v-for="page in sliceVisiblePages" :key="page" class="slice-page-btn" :class="{ active: page === sliceCurrentPage }" @click="sliceCurrentPage = page; fetchSlices()">{{ page }}</button>
|
||||
<button class="slice-page-btn" :disabled="sliceCurrentPage >= slicePageCount" @click="sliceCurrentPage++; fetchSlices()">{{ $t('knowledgeBaseManagement.nextPage') }}</button>
|
||||
<span class="slice-total-text"> {{ $t('knowledgeBaseManagement.totalRecords', { total: sliceTotal }) }}</span>
|
||||
<CustomPagination
|
||||
:total="parseInt(sliceTotal)"
|
||||
:current-page="sliceCurrentPage"
|
||||
:page-size="slicePageSize"
|
||||
:page-size-options="[10, 20, 50]"
|
||||
@size-change="handleSliceSizeChange"
|
||||
@page-change="handleSlicePageChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</CustomDialog>
|
||||
|
||||
<!-- Upload Dialog -->
|
||||
<el-dialog
|
||||
<CustomDialog
|
||||
:title="$t('knowledgeFileUpload.uploadDocument')"
|
||||
:visible.sync="uploadDialogVisible"
|
||||
width="800px"
|
||||
:close-on-click-modal="false"
|
||||
@close="handleUploadDialogClose"
|
||||
@confirm="handleBatchUploadSubmit"
|
||||
>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
action="#"
|
||||
:auto-upload="false"
|
||||
:show-file-list="false"
|
||||
:on-change="handleFileChange"
|
||||
multiple
|
||||
accept=".doc,.docx,.pdf,.txt,.md,.mdx,.csv,.xls,.xlsx,.ppt,.pptx"
|
||||
@@ -189,48 +188,61 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span slot="footer">
|
||||
<el-button @click="uploadDialogVisible = false">{{ $t('knowledgeFileUpload.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="handleBatchUploadSubmit" :loading="uploading" :disabled="selectedFilesList.length === 0">
|
||||
{{ $t('knowledgeFileUpload.confirm') }} ({{ selectedFilesList.length }})
|
||||
</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</CustomDialog>
|
||||
|
||||
<!-- Retrieval Test Dialog -->
|
||||
<el-dialog
|
||||
<CustomDialog
|
||||
:title="$t('knowledgeFileUpload.retrievalTest')"
|
||||
:visible.sync="retrievalTestDialogVisible"
|
||||
width="900px"
|
||||
:close-on-click-modal="false"
|
||||
:confirm-text="$t('knowledgeFileUpload.executeTest')"
|
||||
:confirmLoading="retrievalTestLoading"
|
||||
@confirm="runRetrievalTest"
|
||||
>
|
||||
<div class="retrieval-test-form">
|
||||
<el-form :model="retrievalTestForm" label-width="100px">
|
||||
<el-form-item :label="$t('knowledgeFileUpload.testQuestion')" required>
|
||||
<el-input
|
||||
v-model="retrievalTestForm.question"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
@keyup.enter.native="runRetrievalTest"
|
||||
clearable
|
||||
:placeholder="$t('knowledgeFileUpload.testQuestionPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div style="text-align: center; margin-top: 20px;">
|
||||
<el-button type="primary" @click="runRetrievalTest" :loading="retrievalTestLoading">{{ $t('knowledgeFileUpload.executeTest') }}</el-button>
|
||||
<el-button @click="retrievalTestDialogVisible = false">{{ $t('knowledgeFileUpload.cancel') }}</el-button>
|
||||
</div>
|
||||
<div v-if="retrievalTestResult" class="retrieval-test-result" style="margin-top: 20px;">
|
||||
<h4 style="margin-bottom: 12px;">{{ $t('knowledgeFileUpload.testResult') }}</h4>
|
||||
<div class="result-chunks">
|
||||
<div class="result-chunks" v-if="retrievalTestResult.chunks.length">
|
||||
<div v-for="(chunk, index) in retrievalTestResult.chunks" :key="index" class="result-chunk">
|
||||
<p><strong>{{ $t('knowledgeFileUpload.slice') }} {{ index + 1 }}</strong></p>
|
||||
<div style="margin: 8px 0; font-size: 12px; color: #409eff;">{{ $t('knowledgeFileUpload.comprehensiveSimilarity') }}: {{ (chunk.similarity || 0).toFixed(4) }}</div>
|
||||
<div class="chunk-content">{{ chunk.content }}</div>
|
||||
<div class="chunk-left">
|
||||
<div class="chunk-similarity">
|
||||
<p class="similarity-label">{{ $t('knowledgeFileUpload.comprehensiveSimilarity') }}</p>
|
||||
<p class="similarity-value">{{ (chunk.similarity || 0).toFixed(4) }}</p>
|
||||
<el-progress
|
||||
:percentage="Math.round((chunk.similarity || 0) * 100)"
|
||||
:stroke-width="6"
|
||||
:show-text="false"
|
||||
class="similarity-progress"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<div class="chunk-right">
|
||||
|
||||
<div class="chunk-content">
|
||||
<div class="chunk-right-header">
|
||||
<span class="chunk-source">{{ $t('knowledgeFileUpload.sourceDocument') }}:{{ chunk.document_keyword || '-' }}</span>
|
||||
<span class="chunk-index">{{ $t('knowledgeFileUpload.slice') }} {{ index + 1 }}</span>
|
||||
</div>
|
||||
<p>{{ chunk.content }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else :description="$t('knowledgeFileUpload.noSliceData')"></el-empty>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</CustomDialog>
|
||||
|
||||
<el-footer>
|
||||
<version-footer />
|
||||
@@ -245,9 +257,11 @@ import VersionFooter from "@/components/VersionFooter.vue";
|
||||
import KnowledgeBaseDialog from "@/components/KnowledgeBaseDialog.vue";
|
||||
import KnowledgeBaseItem from "./KnowledgeBaseItem.vue";
|
||||
import ManualIcon from "@/components/ManualIcon.vue";
|
||||
import CustomDialog from "@/components/CustomDialog.vue";
|
||||
import CustomPagination from "@/components/CustomPagination.vue";
|
||||
|
||||
export default {
|
||||
components: { HeaderBar, VersionFooter, KnowledgeBaseDialog, KnowledgeBaseItem, ManualIcon },
|
||||
components: { HeaderBar, VersionFooter, KnowledgeBaseDialog, KnowledgeBaseItem, ManualIcon, CustomDialog, CustomPagination },
|
||||
data() {
|
||||
return {
|
||||
knowledgeBases: [],
|
||||
@@ -290,22 +304,6 @@ export default {
|
||||
kb.name.toLowerCase().includes(keyword)
|
||||
);
|
||||
},
|
||||
slicePageCount() {
|
||||
return Math.ceil(this.sliceTotal / this.slicePageSize);
|
||||
},
|
||||
sliceVisiblePages() {
|
||||
const pages = [];
|
||||
const maxVisible = 3;
|
||||
let start = Math.max(1, this.sliceCurrentPage - 1);
|
||||
let end = Math.min(this.slicePageCount, start + maxVisible - 1);
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.fetchKnowledgeBases();
|
||||
@@ -478,6 +476,12 @@ export default {
|
||||
|
||||
handleFileChange(file) {
|
||||
if (!file || !file.raw) return;
|
||||
// 文件上传前的验证
|
||||
const isLt10M = file.size / 1024 / 1024 < 10;
|
||||
if (!isLt10M) {
|
||||
this.$message.error(this.$t('knowledgeFileUpload.fileSizeExceeded'));
|
||||
return;
|
||||
}
|
||||
this.selectedFilesList.push({
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
@@ -564,6 +568,7 @@ export default {
|
||||
},
|
||||
|
||||
runRetrievalTest() {
|
||||
if (this.retrievalTestLoading) return;
|
||||
if (!this.retrievalTestForm.question.trim()) {
|
||||
this.$message.error(this.$t('knowledgeFileUpload.testQuestionRequired'));
|
||||
return;
|
||||
@@ -648,6 +653,11 @@ export default {
|
||||
this.fetchSlices();
|
||||
},
|
||||
|
||||
handleSlicePageChange(page) {
|
||||
this.sliceCurrentPage = page;
|
||||
this.fetchSlices();
|
||||
},
|
||||
|
||||
getCardColorClass(index) {
|
||||
const colors = ['blue', 'green', 'purple', 'orange', 'pink', 'cyan'];
|
||||
return colors[index % colors.length];
|
||||
@@ -1009,7 +1019,6 @@ export default {
|
||||
.slice-management {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 65vh;
|
||||
}
|
||||
|
||||
.slice-content-container {
|
||||
@@ -1018,7 +1027,7 @@ export default {
|
||||
}
|
||||
|
||||
.slice-cards-container {
|
||||
max-height: 50vh;
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
padding-right: 4px;
|
||||
|
||||
@@ -1033,9 +1042,6 @@ export default {
|
||||
|
||||
.slice-card {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
padding: 14px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&:last-child {
|
||||
@@ -1057,10 +1063,9 @@ export default {
|
||||
.slice-card-content {
|
||||
background: #fff;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
text-align: left;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
@@ -1069,6 +1074,13 @@ export default {
|
||||
background: #e0e0e0;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.clice-index {
|
||||
color: #467afe;
|
||||
display: inline-block;
|
||||
padding: 4px 6px;
|
||||
background: #e6f0fe;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.content-text {
|
||||
@@ -1088,51 +1100,9 @@ export default {
|
||||
|
||||
.slice-pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-top: 16px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.slice-page-size-select {
|
||||
width: 100px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.slice-page-btn {
|
||||
min-width: 32px;
|
||||
height: 28px;
|
||||
padding: 0 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e5e7eb;
|
||||
background: #fff;
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: #f5f7fa;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: #6b80eb;
|
||||
color: #fff;
|
||||
border-color: #6b80eb;
|
||||
}
|
||||
}
|
||||
|
||||
.slice-total-text {
|
||||
margin-left: 8px;
|
||||
color: #9ca3af;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* ========== Selected Files List ========== */
|
||||
.selected-files-section {
|
||||
@@ -1216,28 +1186,92 @@ export default {
|
||||
}
|
||||
|
||||
.result-chunk {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
padding: 14px;
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
|
||||
p {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 14px;
|
||||
.chunk-left {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.chunk-similarity {
|
||||
// font-size: 12px;
|
||||
color: #409eff;
|
||||
white-space: nowrap;
|
||||
|
||||
.similarity-label {
|
||||
// font-size: 12px;
|
||||
color: #333;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.similarity-value {
|
||||
text-align: left;
|
||||
margin-top: 4px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.similarity-progress {
|
||||
margin-top: 8px;
|
||||
|
||||
::v-deep(.el-progress-bar__outer) {
|
||||
border-radius: 3px;
|
||||
background-color: rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
::v-deep(.el-progress-bar__inner) {
|
||||
border-radius: 3px;
|
||||
background: #4a7cfd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chunk-content {
|
||||
background: #fff;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
max-height: 150px;
|
||||
overflow-y: auto;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
.chunk-right {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.chunk-right-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.chunk-source {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.chunk-index {
|
||||
color: #467afe;
|
||||
display: inline-block;
|
||||
padding: 4px 6px;
|
||||
background: #e6f0fe;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.chunk-content {
|
||||
text-align: left;
|
||||
white-space: normal;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
// max-height: 150px;
|
||||
// overflow-y: auto;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
// white-space: pre-wrap;
|
||||
// word-break: break-word;
|
||||
> p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user