fix: 优化知识库文档列表及问答消息气泡markdown表格样式
This commit is contained in:
parent
e29ac67a91
commit
9f950db862
|
|
@ -944,9 +944,10 @@ const hasAnySources = (sources: TraceData | null | undefined) => {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
background: white;
|
background: white;
|
||||||
font-size: 0.83rem; /* 比正文(0.95rem)小2px,约为0.83rem */
|
font-size: 0.75rem; /* 12px */
|
||||||
line-height: 1.4;
|
line-height: 1.3;
|
||||||
border: 1px solid #e5e7eb;
|
border: 1px solid #e5e7eb;
|
||||||
|
table-layout: auto; /* 允许列宽根据内容自适应 */
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep .table-wrapper summary {
|
::v-deep .table-wrapper summary {
|
||||||
|
|
@ -971,15 +972,15 @@ const hasAnySources = (sources: TraceData | null | undefined) => {
|
||||||
|
|
||||||
.answer-content :deep(th),
|
.answer-content :deep(th),
|
||||||
.answer-content :deep(td) {
|
.answer-content :deep(td) {
|
||||||
padding: 0.75rem 1rem;
|
padding: 0.5rem 0.75rem; /* 减少内边距,使表格更紧凑 */
|
||||||
border: 1px solid #e5e7eb;
|
border: 1px solid #e5e7eb;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
max-width: 200px;
|
max-width: none; /* 移除最大宽度限制,允许列宽自适应 */
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
font-size: 0.83rem; /* 确保表格单元格字体也比正文小2px */
|
font-size: 0.75rem; /* 12px */
|
||||||
}
|
}
|
||||||
|
|
||||||
.answer-content :deep(th) {
|
.answer-content :deep(th) {
|
||||||
|
|
@ -987,7 +988,7 @@ const hasAnySources = (sources: TraceData | null | undefined) => {
|
||||||
background: #f8fafc;
|
background: #f8fafc;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #374151;
|
color: #374151;
|
||||||
font-size: 0.83rem; /* 与表格整体字体大小保持一致,比正文小2px */
|
font-size: 0.8125rem; /* 13px */
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.025em;
|
letter-spacing: 0.025em;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
|
|
@ -1043,21 +1044,22 @@ const hasAnySources = (sources: TraceData | null | undefined) => {
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.answer-content :deep(table) {
|
.answer-content :deep(table) {
|
||||||
min-width: 600px;
|
min-width: 600px;
|
||||||
font-size: 0.75rem; /* 移动端保持比正文小的比例 */
|
font-size: 0.6875rem; /* 11px 移动端 */
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
border: 1px solid #e5e7eb;
|
border: 1px solid #e5e7eb;
|
||||||
|
line-height: 1.2; /* 移动端更紧凑的行高 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.answer-content :deep(th),
|
.answer-content :deep(th),
|
||||||
.answer-content :deep(td) {
|
.answer-content :deep(td) {
|
||||||
padding: 0.5rem 0.75rem;
|
padding: 0.375rem 0.5rem; /* 移动端更紧凑的内边距 */
|
||||||
max-width: 150px;
|
max-width: none; /* 移动端也允许列宽自适应 */
|
||||||
border: 1px solid #e5e7eb;
|
border: 1px solid #e5e7eb;
|
||||||
font-size: 0.75rem; /* 移动端表格单元格字体 */
|
font-size: 0.6875rem; /* 11px 移动端表格内容 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.answer-content :deep(th) {
|
.answer-content :deep(th) {
|
||||||
font-size: 0.75rem; /* 移动端表头字体 */
|
font-size: 0.75rem; /* 12px 移动端表头 */
|
||||||
border-bottom: 2px solid #e5e7eb;
|
border-bottom: 2px solid #e5e7eb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ export function useMessageHandlers() {
|
||||||
/<table>/g,
|
/<table>/g,
|
||||||
`<details class="table-wrapper" open>
|
`<details class="table-wrapper" open>
|
||||||
<summary>
|
<summary>
|
||||||
Expand / Collapse table
|
展开 / 折叠表格
|
||||||
</summary>
|
</summary>
|
||||||
<div class="table-container"><table class="excel-table" border="1" width="auto" cellspacing="0" cellpadding="0">`
|
<div class="table-container"><table class="excel-table" border="1" width="auto" cellspacing="0" cellpadding="0">`
|
||||||
).replace(
|
).replace(
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,27 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="main-container">
|
<div class="main-container">
|
||||||
<!-- 搜索头部 -->
|
<!-- 搜索头部 -->
|
||||||
<div class="search-header">
|
<div class="search-header" :class="{ 'collapsed': headerCollapsed }">
|
||||||
<div class="search-logo">
|
<div class="search-logo">
|
||||||
<h1>智能检索</h1>
|
<h1>智能检索</h1>
|
||||||
|
<!-- 折叠/展开按钮 -->
|
||||||
|
<button
|
||||||
|
v-if="hasSearched"
|
||||||
|
class="collapse-toggle-btn"
|
||||||
|
@click="toggleHeaderCollapse"
|
||||||
|
:class="{ 'collapsed': headerCollapsed }"
|
||||||
|
>
|
||||||
|
<svg v-if="!headerCollapsed" viewBox="0 0 24 24" width="20" height="20">
|
||||||
|
<path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"/>
|
||||||
|
</svg>
|
||||||
|
<svg v-else viewBox="0 0 24 24" width="20" height="20">
|
||||||
|
<path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- 搜索框 -->
|
<!-- 搜索框 -->
|
||||||
<div class="search-box-container">
|
<div class="search-box-container" v-show="!headerCollapsed">
|
||||||
<div class="search-box-wrapper">
|
<div class="search-box-wrapper">
|
||||||
<div class="search-box">
|
<div class="search-box">
|
||||||
<input
|
<input
|
||||||
|
|
@ -79,12 +92,15 @@
|
||||||
找到约 {{ totalResults }} 条结果 (用时 {{ searchTime }}秒)
|
找到约 {{ totalResults }} 条结果 (用时 {{ searchTime }}秒)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 结果列表 -->
|
<!-- 结果容器 -->
|
||||||
<div class="results-list">
|
<div class="results-container" :class="{ 'preview-mode': previewDrawerVisible }">
|
||||||
<div
|
<!-- 左侧结果列表 -->
|
||||||
v-for="(result, index) in paginatedResults"
|
<div class="results-list-left">
|
||||||
:key="index"
|
<div
|
||||||
|
v-for="(result, index) in leftColumnResults"
|
||||||
|
:key="`left-${index}`"
|
||||||
class="result-item"
|
class="result-item"
|
||||||
|
:class="{ 'preview-selected': selectedPreviewIndex === getGlobalIndex(index) }"
|
||||||
>
|
>
|
||||||
<!-- 文件名和置信度 -->
|
<!-- 文件名和置信度 -->
|
||||||
<div class="result-header">
|
<div class="result-header">
|
||||||
|
|
@ -151,51 +167,93 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 分页组件 -->
|
<!-- 右侧结果列表 -->
|
||||||
<div class="pagination-container" v-if="totalResults > pageSize">
|
<div class="results-list-right" v-if="!previewDrawerVisible">
|
||||||
<el-pagination
|
<div
|
||||||
v-model:current-page="currentPage"
|
v-for="(result, index) in rightColumnResults"
|
||||||
v-model:page-size="pageSize"
|
:key="`right-${index}`"
|
||||||
:page-sizes="[5, 10, 20, 50]"
|
class="result-item"
|
||||||
:total="totalResults"
|
>
|
||||||
layout="total, sizes, prev, pager, next, jumper"
|
<!-- 文件名和置信度 -->
|
||||||
@size-change="handleSizeChange"
|
<div class="result-header">
|
||||||
@current-change="handleCurrentChange"
|
<div class="file-info">
|
||||||
/>
|
<img
|
||||||
|
:src="getFileTypeIcon(getFileExtension(result.retrievalDto?.name || ''))"
|
||||||
|
:alt="getFileExtension(result.retrievalDto?.name || '')"
|
||||||
|
class="file-type-icon"
|
||||||
|
/>
|
||||||
|
<h3 class="result-title" @click="handleTitleClick(result)">
|
||||||
|
{{ result.retrievalDto?.name || "未知文档" }}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="confidence-score">
|
||||||
|
<span class="confidence-label">置信度:</span>
|
||||||
|
<span class="confidence-value" :class="getConfidenceClass(result.score)">
|
||||||
|
{{ (parseFloat(result.score) * 100).toFixed(1) }}%
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 空状态 -->
|
<!-- 文档内容摘要 -->
|
||||||
<div class="empty-state" v-if="!hasSearched">
|
<div class="result-content">
|
||||||
<div class="empty-icon">
|
<p class="content-snippet" v-html="getHighlightedContent(result.retrievalDto?.content || '暂无内容', getGlobalIndex(index + leftColumnResults.length))">
|
||||||
<svg viewBox="0 0 24 24">
|
</p>
|
||||||
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
|
<div v-if="(result.retrievalDto?.content || '').length > 200" class="expand-btn" @click="toggleExpand(getGlobalIndex(index + leftColumnResults.length))">
|
||||||
|
{{ expandedItems.includes(getGlobalIndex(index + leftColumnResults.length)) ? '收起' : '展开更多' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 文档信息 -->
|
||||||
|
<div class="result-meta">
|
||||||
|
<span class="meta-item">
|
||||||
|
<svg class="meta-icon" viewBox="0 0 24 24">
|
||||||
|
<path d="M12,2A2,2 0 0,1 14,4C14,4.74 13.6,5.39 13,5.73V7H14A7,7 0 0,1 21,14H22A1,1 0 0,1 23,15V18A1,1 0 0,1 22,19H21V20A2,2 0 0,1 19,22H5A2,2 0 0,1 3,20V19H2A1,1 0 0,1 1,18V15A1,1 0 0,1 2,14H3A7,7 0 0,1 10,7H11V5.73C10.4,5.39 10,4.74 10,4A2,2 0 0,1 12,2M7.5,13A2.5,2.5 0 0,0 5,15.5A2.5,2.5 0 0,0 7.5,18A2.5,2.5 0 0,0 10,15.5A2.5,2.5 0 0,0 16.5,18A2.5,2.5 0 0,0 19,15.5A2.5,2.5 0 0,0 16.5,13Z" />
|
||||||
</svg>
|
</svg>
|
||||||
|
知识库: {{ result.retrievalDto?.datasetName || '未知知识库' }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<h3>开始您的智能检索</h3>
|
|
||||||
<p>输入关键词,从海量文档中快速找到您需要的信息</p>
|
<!-- 操作按钮 -->
|
||||||
|
<div class="result-actions">
|
||||||
|
<el-button
|
||||||
|
type="info"
|
||||||
|
:icon="View"
|
||||||
|
text
|
||||||
|
class="action-btn preview-btn"
|
||||||
|
@click="handlePreview(result)"
|
||||||
|
v-if="result.retrievalDto?.sourceUrl && canPreview(result.retrievalDto?.name)"
|
||||||
|
>
|
||||||
|
预览
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
:icon="Download"
|
||||||
|
text
|
||||||
|
class="action-btn"
|
||||||
|
@click="handleDownload(result)"
|
||||||
|
v-if="result.retrievalDto?.sourceUrl"
|
||||||
|
>
|
||||||
|
下载
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 无结果状态 -->
|
<!-- 右侧预览窗口 -->
|
||||||
<div class="no-results" v-if="hasSearched && allResults.length === 0 && !loading">
|
<div class="preview-panel" v-if="previewDrawerVisible">
|
||||||
<div class="no-results-icon">
|
<div class="preview-header">
|
||||||
<svg viewBox="0 0 24 24">
|
<h3>文件预览</h3>
|
||||||
<path d="M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z" />
|
<el-button
|
||||||
</svg>
|
type="text"
|
||||||
</div>
|
@click="closePreview"
|
||||||
<h3>未找到相关结果</h3>
|
class="close-preview-btn"
|
||||||
<p>请尝试使用不同的关键词或搜索方法</p>
|
>
|
||||||
</div>
|
<svg viewBox="0 0 24 24" width="16" height="16">
|
||||||
|
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
|
||||||
<!-- 预览抽屉 -->
|
</svg>
|
||||||
<el-drawer
|
</el-button>
|
||||||
v-model="previewDrawerVisible"
|
</div>
|
||||||
title="文件预览"
|
<div class="preview-content" v-loading="previewLoading">
|
||||||
:direction="'rtl'"
|
|
||||||
size="50%"
|
|
||||||
class="preview-drawer"
|
|
||||||
>
|
|
||||||
<div v-loading="previewLoading">
|
|
||||||
<!-- TXT 文件预览 -->
|
<!-- TXT 文件预览 -->
|
||||||
<div v-if="previewFileType === 'txt'" class="text-preview-container">
|
<div v-if="previewFileType === 'txt'" class="text-preview-container">
|
||||||
<pre class="text-preview">{{ previewTextContent }}</pre>
|
<pre class="text-preview">{{ previewTextContent }}</pre>
|
||||||
|
|
@ -297,7 +355,45 @@
|
||||||
<p>您可以下载文件后使用相应的应用程序打开</p>
|
<p>您可以下载文件后使用相应的应用程序打开</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-drawer>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分页组件 -->
|
||||||
|
<div class="pagination-container" v-if="totalResults > pageSize">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="currentPage"
|
||||||
|
v-model:page-size="pageSize"
|
||||||
|
:page-sizes="[5, 10, 20, 50]"
|
||||||
|
:total="totalResults"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 空状态 -->
|
||||||
|
<div class="empty-state" v-if="!hasSearched">
|
||||||
|
<div class="empty-icon">
|
||||||
|
<svg viewBox="0 0 24 24">
|
||||||
|
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3>开始您的智能检索</h3>
|
||||||
|
<p>输入关键词,从海量文档中快速找到您需要的信息</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 无结果状态 -->
|
||||||
|
<div class="no-results" v-if="hasSearched && allResults.length === 0 && !loading">
|
||||||
|
<div class="no-results-icon">
|
||||||
|
<svg viewBox="0 0 24 24">
|
||||||
|
<path d="M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3>未找到相关结果</h3>
|
||||||
|
<p>请尝试使用不同的关键词或搜索方法</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -378,6 +474,8 @@ const previewFileUrl = ref('')
|
||||||
const previewTextContent = ref('')
|
const previewTextContent = ref('')
|
||||||
const previewMarkdownContent = ref('')
|
const previewMarkdownContent = ref('')
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
|
const selectedPreviewIndex = ref(-1) // 当前预览的索引
|
||||||
|
const headerCollapsed = ref(false) // 头部折叠状态
|
||||||
|
|
||||||
const knowledgeList = ref([])
|
const knowledgeList = ref([])
|
||||||
|
|
||||||
|
|
@ -423,6 +521,11 @@ const removeKnowledge = (kbId: string) => {
|
||||||
const handleSelectKnowledge = () => {
|
const handleSelectKnowledge = () => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 切换头部折叠状态
|
||||||
|
const toggleHeaderCollapse = () => {
|
||||||
|
headerCollapsed.value = !headerCollapsed.value
|
||||||
|
}
|
||||||
// 搜索处理函数
|
// 搜索处理函数
|
||||||
const handleSearch = async () => {
|
const handleSearch = async () => {
|
||||||
if (!searchQuery.value.trim()) {
|
if (!searchQuery.value.trim()) {
|
||||||
|
|
@ -457,6 +560,13 @@ const handleSearch = async () => {
|
||||||
totalResults.value = allResults.value.length
|
totalResults.value = allResults.value.length
|
||||||
currentPage.value = 1 // 重置到第一页
|
currentPage.value = 1 // 重置到第一页
|
||||||
searchTime.value = ((Date.now() - startTime) / 1000).toFixed(2)
|
searchTime.value = ((Date.now() - startTime) / 1000).toFixed(2)
|
||||||
|
|
||||||
|
// 搜索成功后自动折叠头部
|
||||||
|
if (allResults.value.length > 0) {
|
||||||
|
setTimeout(() => {
|
||||||
|
headerCollapsed.value = true
|
||||||
|
}, 500) // 延迟500ms后折叠,让用户看到搜索结果
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('搜索失败:', error)
|
console.error('搜索失败:', error)
|
||||||
ElMessage.error('搜索失败,请稍后重试')
|
ElMessage.error('搜索失败,请稍后重试')
|
||||||
|
|
@ -572,6 +682,24 @@ const paginatedResults = computed(() => {
|
||||||
return allResults.value.slice(start, end)
|
return allResults.value.slice(start, end)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 计算左列结果(当预览模式时,所有结果都在左列)
|
||||||
|
const leftColumnResults = computed(() => {
|
||||||
|
if (previewDrawerVisible.value) {
|
||||||
|
return paginatedResults.value
|
||||||
|
}
|
||||||
|
// 正常模式:左列显示奇数索引的结果(1,3,5...)
|
||||||
|
return paginatedResults.value.filter((_, index) => index % 2 === 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 计算右列结果(仅在非预览模式时显示)
|
||||||
|
const rightColumnResults = computed(() => {
|
||||||
|
if (previewDrawerVisible.value) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
// 正常模式:右列显示偶数索引的结果(2,4,6...)
|
||||||
|
return paginatedResults.value.filter((_, index) => index % 2 === 1)
|
||||||
|
})
|
||||||
|
|
||||||
// 分页大小改变处理
|
// 分页大小改变处理
|
||||||
const handleSizeChange = (newSize: number) => {
|
const handleSizeChange = (newSize: number) => {
|
||||||
pageSize.value = newSize
|
pageSize.value = newSize
|
||||||
|
|
@ -657,8 +785,13 @@ const handlePreview = async (result: any) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置预览模式
|
||||||
previewDrawerVisible.value = true
|
previewDrawerVisible.value = true
|
||||||
previewLoading.value = true
|
previewLoading.value = true
|
||||||
|
|
||||||
|
// 记录当前预览的索引
|
||||||
|
const resultIndex = paginatedResults.value.findIndex(r => r === result)
|
||||||
|
selectedPreviewIndex.value = getGlobalIndex(resultIndex)
|
||||||
|
|
||||||
// 重置 Excel 预览状态
|
// 重置 Excel 预览状态
|
||||||
excelRowLimited.value = false
|
excelRowLimited.value = false
|
||||||
|
|
@ -725,6 +858,17 @@ const handlePreview = async (result: any) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 关闭预览
|
||||||
|
const closePreview = () => {
|
||||||
|
previewDrawerVisible.value = false
|
||||||
|
selectedPreviewIndex.value = -1
|
||||||
|
previewLoading.value = false
|
||||||
|
previewFileType.value = ''
|
||||||
|
previewFileUrl.value = ''
|
||||||
|
previewTextContent.value = ''
|
||||||
|
previewMarkdownContent.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
// 从预览中下载文件
|
// 从预览中下载文件
|
||||||
const handleDownloadFromPreview = async () => {
|
const handleDownloadFromPreview = async () => {
|
||||||
// 在智能检索中,我们可以通过当前预览的文件URL直接下载
|
// 在智能检索中,我们可以通过当前预览的文件URL直接下载
|
||||||
|
|
@ -829,6 +973,16 @@ onMounted(() => {
|
||||||
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-header.collapsed {
|
||||||
|
padding: 15px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-header.collapsed .search-logo h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-logo h1 {
|
.search-logo h1 {
|
||||||
|
|
@ -856,6 +1010,41 @@ onMounted(() => {
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 折叠按钮样式 */
|
||||||
|
.collapse-toggle-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
border: 1px solid rgba(102, 126, 234, 0.3);
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.1);
|
||||||
|
color: #667eea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-toggle-btn:hover {
|
||||||
|
background: rgba(102, 126, 234, 0.1);
|
||||||
|
border-color: rgba(102, 126, 234, 0.5);
|
||||||
|
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.2);
|
||||||
|
transform: translateY(-50%) scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-toggle-btn svg {
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-toggle-btn.collapsed svg {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
/* 搜索框容器 */
|
/* 搜索框容器 */
|
||||||
.search-box-container {
|
.search-box-container {
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
|
|
@ -1005,7 +1194,7 @@ onMounted(() => {
|
||||||
.search-results {
|
.search-results {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 20px;
|
padding: 20px 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
background: rgba(255, 255, 255, 0.05);
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
|
@ -1016,12 +1205,99 @@ onMounted(() => {
|
||||||
color: #70757a;
|
color: #70757a;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
padding-left: 8px;
|
padding: 0 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.results-list {
|
/* 结果容器 */
|
||||||
max-width: 800px;
|
.results-container {
|
||||||
margin-bottom: 20px;
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-container.preview-mode {
|
||||||
|
gap: 10px;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 左侧结果列表 */
|
||||||
|
.results-list-left {
|
||||||
|
flex: 1;
|
||||||
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-container.preview-mode .results-list-left {
|
||||||
|
flex: 0 0 50%;
|
||||||
|
max-width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 右侧结果列表 */
|
||||||
|
.results-list-right {
|
||||||
|
flex: 1;
|
||||||
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-container.preview-mode .results-list-right {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(100%);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 预览面板 */
|
||||||
|
.preview-panel {
|
||||||
|
flex: 0 0 50%;
|
||||||
|
background: rgba(255, 255, 255, 0.95);
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
border-radius: 16px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(100%);
|
||||||
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-container.preview-mode .preview-panel {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 20px 24px;
|
||||||
|
border-bottom: 1px solid rgba(102, 126, 234, 0.1);
|
||||||
|
background: linear-gradient(135deg, rgba(102, 126, 234, 0.05) 0%, rgba(118, 75, 162, 0.05) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
color: #667eea;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-preview-btn {
|
||||||
|
color: #909399;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-preview-btn:hover {
|
||||||
|
color: #667eea;
|
||||||
|
background-color: rgba(102, 126, 234, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 结果项 */
|
/* 结果项 */
|
||||||
|
|
@ -1058,6 +1334,19 @@ onMounted(() => {
|
||||||
border-color: rgba(102, 126, 234, 0.3);
|
border-color: rgba(102, 126, 234, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 预览选中状态 */
|
||||||
|
.result-item.preview-selected {
|
||||||
|
background: linear-gradient(135deg, rgba(102, 126, 234, 0.1) 0%, rgba(118, 75, 162, 0.1) 100%);
|
||||||
|
border-color: rgba(102, 126, 234, 0.5);
|
||||||
|
box-shadow: 0 8px 32px rgba(102, 126, 234, 0.2);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-item.preview-selected::before {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
height: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes slideInUp {
|
@keyframes slideInUp {
|
||||||
from {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
@ -1257,7 +1546,7 @@ onMounted(() => {
|
||||||
.pagination-container {
|
.pagination-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 20px 0;
|
padding: 20px;
|
||||||
border-top: 1px solid #e8eaed;
|
border-top: 1px solid #e8eaed;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
@ -1302,6 +1591,21 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 响应式设计 */
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.results-container {
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-container.preview-mode {
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-container.preview-mode .results-list-left,
|
||||||
|
.results-container.preview-mode .preview-panel {
|
||||||
|
flex: 0 0 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.search-header {
|
.search-header {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
|
|
@ -1311,6 +1615,16 @@ onMounted(() => {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.collapse-toggle-btn {
|
||||||
|
right: 10px;
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-header.collapsed .search-logo h1 {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.search-box-container {
|
.search-box-container {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
@ -1319,6 +1633,28 @@ onMounted(() => {
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.results-container {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-container.preview-mode {
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-container.preview-mode .results-list-left {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-container.preview-mode .preview-panel {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 100%;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.result-header {
|
.result-header {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
|
@ -1354,6 +1690,14 @@ onMounted(() => {
|
||||||
.pagination-container :deep(.el-pagination .el-pagination__jump) {
|
.pagination-container :deep(.el-pagination .el-pagination__jump) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.preview-header {
|
||||||
|
padding: 16px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-header h3 {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 操作按钮样式 */
|
/* 操作按钮样式 */
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@
|
||||||
type="index"
|
type="index"
|
||||||
:index="indexMethod"
|
:index="indexMethod"
|
||||||
/>
|
/>
|
||||||
<el-table-column prop="fileName" :label="t('vabI18n.knowledge.document.table.fileName')" min-width="250" sortable="custom" :sort-orders="['ascending', 'descending']">
|
<el-table-column prop="fileName" :label="t('vabI18n.knowledge.document.table.fileName')" min-width="200" sortable="custom" :sort-orders="['ascending', 'descending']">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="file-name-cell">
|
<div class="file-name-cell">
|
||||||
<img
|
<img
|
||||||
|
|
@ -134,13 +134,13 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="createDate" :label="t('vabI18n.knowledge.document.table.createDate')" width="180" sortable="custom" :sort-orders="['ascending', 'descending']" />
|
<el-table-column prop="createDate" :label="t('vabI18n.knowledge.document.table.createDate')" width="180" sortable="custom" :sort-orders="['ascending', 'descending']" />
|
||||||
<el-table-column prop="charCount" :label="t('vabI18n.knowledge.document.table.charCount')" width="120" align="right" sortable="custom" :sort-orders="['ascending', 'descending']">
|
<el-table-column prop="charCount" :label="t('vabI18n.knowledge.document.table.fileSize', '文件大小')" width="120" align="right" sortable="custom" :sort-orders="['ascending', 'descending']">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<span class="char-count" v-if="row.type === 'file'">{{ formatFileSize(row.charCount) }}</span>
|
<span class="char-count" v-if="row.type === 'file'">{{ formatFileSize(row.charCount) }}</span>
|
||||||
<span v-else class="folder-indicator">--</span>
|
<span v-else class="folder-indicator">--</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="t('vabI18n.knowledge.document.table.actions')" width="380" fixed="right">
|
<el-table-column :label="t('vabI18n.knowledge.document.table.actions')" width="320" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<!-- 文件操作 -->
|
<!-- 文件操作 -->
|
||||||
|
|
@ -1594,6 +1594,7 @@ const handleClosePreviewDialog = () => {
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1603,6 +1604,8 @@ const handleClosePreviewDialog = () => {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
width: 100%;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-bar {
|
.action-bar {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue