| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221 |
- <template>
- <div class="app-container">
- <!-- 顶部导航 -->
- <div class="app-header">
- <div class="header-content">
- <div class="header-main">
- <h1 class="app-title">智能知识库助手</h1>
- <p style="color: rgba(255, 255, 255, 0.8);
- font-size: 1rem;
- margin: 8px 0 0 0;
- font-weight: 500;">基于RAG技术的智能问答系统</p>
- </div>
- <div class="header-stats">
- <div class="stat-item">
- <span class="stat-number">{{ knowledgeBaseList.length }}</span>
- <span class="stat-label">知识库</span>
- </div>
- <div class="stat-item">
- <span class="stat-number">{{ selectedDatasetIds.length }}</span>
- <span class="stat-label">已选择</span>
- </div>
- </div>
- <!-- 在 header-content 内的 header-stats 后面添加 -->
- <div class="header-actions">
- <el-button
- class="history-btn"
- @click="$router.push('/qanda/history')"
- >
- <span class="btn-icon">📚</span>
- 查看历史问题
- </el-button>
- </div>
- </div>
- </div>
- <div class="main-layout">
- <!-- 左侧知识库侧边栏 -->
- <div class="sidebar">
- <div class="sidebar-header">
- <div class="sidebar-title">
- <h3>📚 知识库选择</h3>
- <p class="sidebar-subtitle">选择要查询的知识库</p>
- </div>
- <!-- <el-button-->
- <!-- class="refresh-btn"-->
- <!-- size="small"-->
- <!-- @click="getKnowledgeBaseList"-->
- <!-- :loading="refreshing"-->
- <!-- >-->
- <!-- <span v-if="!refreshing">🔄</span>-->
- <!-- <span v-else>...</span>-->
- <!-- </el-button>-->
- </div>
- <div class="knowledge-list">
- <div
- v-for="item in knowledgeBaseList"
- :key="item.dataset_id"
- :class="['knowledge-card', { 'active': selectedDatasetIds.includes(item.dataset_id) }]"
- @click="toggleDatasetSelection(item.dataset_id)"
- >
- <div class="card-content">
- <div class="knowledge-icon">
- <span v-if="selectedDatasetIds.includes(item.dataset_id)">✅</span>
- <span v-else>📖</span>
- </div>
- <div class="knowledge-info">
- <span class="knowledge-name">{{ item.name }}</span>
- <span class="knowledge-desc" v-if="item.description">{{ item.description }}</span>
- <span class="knowledge-status" :class="{ 'active': selectedDatasetIds.includes(item.dataset_id) }">
- {{ selectedDatasetIds.includes(item.dataset_id) ? '已选择' : '点击选择' }}
- </span>
- </div>
- </div>
- </div>
- </div>
- <div class="sidebar-footer">
- <div class="selected-count">
- <span class="count-number">{{ selectedDatasetIds.length }}</span>
- <span class="count-label">个知识库已选择</span>
- </div>
- <el-button
- v-if="selectedDatasetIds.length > 0"
- class="clear-btn"
- size="small"
- @click="clearSelection"
- >
- 清空选择
- </el-button>
- </div>
- </div>
- <!-- 右侧主内容区 -->
- <div class="content-area">
- <!-- 搜索区域 -->
- <div class="search-section">
- <div class="search-card">
- <div class="search-header">
- <div class="search-title">
- <h2>💬 开始提问</h2>
- <p>输入您的问题,AI将基于选定的知识库为您解答</p>
- </div>
- <div class="search-tips">
- <span class="tip-item">🔍 智能检索</span>
- <span class="tip-item">🤖 AI分析</span>
- <span class="tip-item">📚 多源参考</span>
- </div>
- </div>
- <div class="search-input-group">
- <div class="input-container">
- <el-input
- v-model="query"
- placeholder="例如:请介绍一下机器学习的基本概念..."
- size="large"
- class="search-input"
- @keyup.enter="chat"
- :disabled="loading"
- >
- <template #prefix>
- <span class="input-icon">💭</span>
- </template>
- </el-input>
- <div class="input-tips" v-if="selectedDatasetIds.length > 0">
- 将在 {{ selectedDatasetIds.length }} 个知识库中搜索答案
- </div>
- </div>
- <el-button
- @click="chat"
- type="primary"
- :disabled="loading || !query.trim() || selectedDatasetIds.length === 0"
- size="large"
- class="search-button"
- >
- <span v-if="loading" class="button-loading">
- <span class="loading-spinner"></span>
- 思考中...
- </span>
- <span v-else class="button-content">
- <span class="button-icon">🚀</span>
- 开始提问
- </span>
- </el-button>
- </div>
- <!-- 快速提问示例 -->
- <!-- <div class="quick-questions" v-if="!loading">-->
- <!-- <p class="quick-title">💡 试试这些问题:</p>-->
- <!-- <div class="question-chips">-->
- <!-- <el-tag-->
- <!-- v-for="question in quickQuestions"-->
- <!-- :key="question"-->
- <!-- class="question-chip"-->
- <!-- @click="query = question; chat()"-->
- <!-- :disabled="loading"-->
- <!-- >-->
- <!-- {{ question }}-->
- <!-- </el-tag>-->
- <!-- </div>-->
- <!-- </div>-->
- </div>
- </div>
- <!-- 加载状态 -->
- <div v-if="loading" class="loading-section">
- <div class="loading-content">
- <div class="loading-animation">
- <div class="thinking-robot">🤖</div>
- <div class="thinking-dots">
- <span></span>
- <span></span>
- <span></span>
- </div>
- </div>
- <p class="loading-text">AI正在分析您的问题,请稍候...</p>
- <p class="loading-subtext">正在从 {{ selectedDatasetIds.length }} 个知识库中检索相关信息</p>
- </div>
- </div>
- <!-- 最终回答 - 始终展开 -->
- <div v-if="chatSummary && !loading" class="thinking-card answer-card">
- <div class="card-header">
- <div class="header-icon">💡</div>
- <div class="header-content">
- <h3>最终回答</h3>
- <p> 基于知识库内容生成的完整答案</p>
- </div>
- <!-- <div class="header-actions">-->
- <!-- <el-tooltip content="复制回答" placement="top">-->
- <!-- <el-button text class="action-btn" @click="copyToClipboard(chatSummary)">-->
- <!-- 📋-->
- <!-- </el-button>-->
- <!-- </el-tooltip>-->
- <!-- </div>-->
- </div>
- <div class="card-body">
- <div v-html="parsedChatSummary" class="thinking-content"></div>
- </div>
- </div>
- <!-- 思考过程展示 - 可折叠 -->
- <div v-if="showThinkingProcess && !loading" class="thinking-section">
- <!-- RAG 思考过程 - 可折叠 -->
- <div v-if="ragSummary" class="collapsible-section">
- <div class="collapsible-header" @click="toggleSection('rag')">
- <div class="header-main">
- <div class="header-icon">🔍</div>
- <div class="header-content">
- <h3>检索增强分析</h3>
- <p> 从知识库中检索相关信息并进行分析</p>
- </div>
- </div>
- <div class="header-actions">
- <div class="collapse-icon" :class="{ rotated: expandedSections.rag }">
- <span>▼</span>
- </div>
- </div>
- </div>
- <div v-show="expandedSections.rag" class="collapsible-content">
- <div class="card-body">
- <div v-html="parsedRagSummary" class="thinking-content"></div>
- </div>
- </div>
- </div>
- <!-- LLM 思考过程 - 可折叠 -->
- <div v-if="llmSummary" class="collapsible-section">
- <div class="collapsible-header" @click="toggleSection('llm')">
- <div class="header-main">
- <div class="header-icon">🤔</div>
- <div class="header-content">
- <h3>AI搜索分析</h3>
- <p> 基于AI搜索内容进行深度分析</p>
- </div>
- </div>
- <div class="header-actions">
- <div class="collapse-icon" :class="{ rotated: expandedSections.llm }">
- <span>▼</span>
- </div>
- </div>
- </div>
- <div v-show="expandedSections.llm" class="collapsible-content">
- <div class="card-body">
- <div v-html="parsedLlmSummary" class="thinking-content"></div>
- </div>
- </div>
- </div>
- </div>
- <!-- 搜索结果 - 可折叠 -->
- <div v-if="searchResults.length > 0 && !loading" class="collapsible-section results-section">
- <div class="collapsible-header" @click="toggleSection('results')">
- <div class="header-main">
- <div class="header-icon">📋</div>
- <div class="header-content">
- <h3>参考内容</h3>
- <p> AI回答时参考的知识库内容 ({{ searchResults.length }} 条)</p>
- </div>
- </div>
- <div class="header-actions">
- <div class="collapse-icon" :class="{ rotated: expandedSections.results }">
- <span>▼</span>
- </div>
- </div>
- </div>
- <div v-show="expandedSections.results" class="collapsible-content">
- <div class="results-container">
- <div class="results-stats">
- <span class="stat">共找到 {{ searchResults.length }} 条相关内容</span>
- <span class="stat">平均相关度: {{ averageScore }}%</span>
- </div>
- <div class="results-grid">
- <div
- v-for="(result, index) in searchResults"
- :key="result.contentSummary + index"
- class="result-card"
- @click="handleDetails(result)"
- >
- <div class="result-badge">#{{ index + 1 }}</div>
- <div class="result-header">
- <h4 class="result-title">{{ result.contentSummary }}</h4>
- <div class="result-meta">
- <span class="score-badge" :class="getScoreClass(result.score)">
- {{ (result.score * 100).toFixed(1) }}%
- </span>
- <span class="source-tag">{{ result.datasetName }}</span>
- <span v-if="result.textType === 3" class="file-type pdf-type">PDF</span>
- <span v-else class="file-type text-type">文本</span>
- </div>
- </div>
- <p class="result-preview">{{ result.content.substring(0, 150) }}...</p>
- <div class="result-footer">
- <span class="view-details">
- <span class="view-icon">🔍</span>
- 查看详情
- </span>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- 空状态 -->
- <div v-if="!loading && !showThinkingProcess && searchResults.length === 0 && hasSearched" class="empty-state">
- <div class="empty-content">
- <div class="empty-icon">🔍</div>
- <h3>未找到相关内容</h3>
- <p>请尝试调整问题关键词或选择其他知识库</p>
- <el-button @click="query = ''" class="retry-btn">
- 重新提问
- </el-button>
- </div>
- </div>
- <!-- 初始状态 -->
- <div v-if="!loading && !hasSearched" class="welcome-state">
- <div class="welcome-content">
- <div class="welcome-icon">🤖</div>
- <h3>欢迎使用智能知识库助手</h3>
- <p>选择左侧的知识库,输入您的问题,AI将为您提供精准的答案</p>
- <div class="feature-list">
- <div class="feature-item">
- <span class="feature-icon">🔍</span>
- <span>智能检索多个知识库</span>
- </div>
- <div class="feature-item">
- <span class="feature-icon">🤔</span>
- <span>展示AI思考过程</span>
- </div>
- <div class="feature-item">
- <span class="feature-icon">📚</span>
- <span>提供参考来源</span>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- 美化后的弹窗 -->
- <el-dialog
- v-model="dialogVisible"
- width="85%"
- class="content-dialog"
- :close-on-click-modal="false"
- >
- <template #header>
- <div class="dialog-header">
- <div class="dialog-title">
- <div class="title-icon" :class="selectedResult.textType === 3 ? 'pdf-icon' : 'text-icon'">
- {{ selectedResult.textType === 3 ? '📄' : '📝' }}
- </div>
- <div class="title-content">
- <h3>{{ selectedResult.contentSummary }}</h3>
- <div class="title-meta">
- <span class="meta-badge knowledge-badge">
- <span class="badge-icon">📚</span>
- {{ selectedResult.datasetName }}
- </span>
- <span class="meta-badge score-badge" :class="getScoreClass(selectedResult.score)">
- <span class="badge-icon">🎯</span>
- 相关度: {{ (selectedResult.score * 100).toFixed(1) }}%
- </span>
- <span v-if="selectedResult.textType === 3" class="meta-badge file-type-badge pdf-badge">
- <span class="badge-icon">📄</span>
- PDF文档
- </span>
- <span v-else class="meta-badge file-type-badge text-badge">
- <span class="badge-icon">📝</span>
- 文本文档
- </span>
- </div>
- </div>
- </div>
- </div>
- </template>
- <div class="dialog-content">
- <div class="content-tabs">
- <div
- class="tab-item"
- :class="{ active: activeTab === 'summary' }"
- @click="activeTab = 'summary'"
- >
- <span class="tab-icon">📝</span>
- 摘要内容
- </div>
- <div
- v-if="selectedResult.textType !== 3"
- class="tab-item"
- :class="{ active: activeTab === 'original' }"
- @click="activeTab = 'original'"
- >
- <span class="tab-icon">📖</span>
- 完整原文
- </div>
- <div
- v-if="selectedResult.textType === 3"
- class="tab-item"
- :class="{ active: activeTab === 'pdf' }"
- @click="activeTab = 'pdf'"
- >
- <span class="tab-icon">📄</span>
- PDF文档
- </div>
- </div>
- <div class="tab-content">
- <div v-show="activeTab === 'summary'" class="content-section summary-section">
- <div class="section-header">
- <h4>内容摘要</h4>
- </div>
- <div class="summary-content">
- {{ selectedResult.content }}
- </div>
- </div>
- <div v-show="activeTab === 'original'" class="content-section original-section">
- <div class="section-header">
- <h4>完整原文</h4>
- </div>
- <div class="original-content">
- <pre>{{ originalContent }}</pre>
- </div>
- </div>
- <!-- PDF 内容展示 -->
- <div v-show="activeTab === 'pdf'" class="content-section pdf-section">
- <div class="section-header">
- <h4>PDF文档</h4>
- <el-button
- v-if="selectedResult.url"
- type="primary"
- class="view-pdf-btn"
- @click="openPdfInNewTab"
- >
- <span class="button-icon">👀</span>
- 在新窗口查看
- </el-button>
- </div>
- <div class="pdf-content" v-if="selectedResult.url">
- <div class="pdf-viewer-container">
- <iframe
- :src="selectedResult.url"
- class="pdf-viewer"
- frameborder="0"
- @load="onPdfLoad"
- @error="onPdfError"
- ></iframe>
- <div v-if="pdfLoading" class="pdf-loading">
- <div class="loading-spinner"></div>
- <p>正在加载PDF文档...</p>
- </div>
- </div>
- </div>
- <div v-else class="pdf-empty">
- <div class="empty-icon">📄</div>
- <h3>PDF文档不可用</h3>
- <p>无法加载PDF文档,请检查文件地址是否正确</p>
- </div>
- </div>
- </div>
- </div>
- <template #footer>
- <div class="dialog-footer">
- <div class="footer-actions">
- <el-button
- class="action-btn secondary"
- @click="dialogVisible = false"
- >
- 取消
- </el-button>
- <el-button
- type="primary"
- class="action-btn primary"
- @click="dialogVisible = false"
- >
- 关闭
- </el-button>
- </div>
- </div>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup>
- import {ref, onMounted, computed} from 'vue';
- import {ElMessage, ElMessageBox} from 'element-plus';
- import {marked} from 'marked';
- import {API_BASE_URL} from "@/config";
- // 响应式数据
- const knowledgeBaseList = ref([]);
- const selectedDatasetIds = ref([11, 12]);
- const query = ref('');
- const searchResults = ref([]);
- const chatSummary = ref('');
- const ragSummary = ref('');
- const llmSummary = ref('');
- const dialogVisible = ref(false);
- const selectedResult = ref({});
- const originalContent = ref('');
- const loading = ref(false);
- const refreshing = ref(false);
- const hasSearched = ref(false);
- const activeTab = ref('summary');
- const pdfLoading = ref(false);
- // 可折叠区域的展开状态
- const expandedSections = ref({
- rag: false,
- llm: false,
- results: false
- });
- // 快速提问示例
- const quickQuestions = ref([
- "请总结一下主要概念",
- "有哪些重要的注意事项?",
- "请提供相关的示例说明",
- "这个主题的核心要点是什么?"
- ]);
- // 计算属性
- const showThinkingProcess = computed(() => {
- return chatSummary.value || ragSummary.value || llmSummary.value;
- });
- const averageScore = computed(() => {
- if (searchResults.value.length === 0) return 0;
- const total = searchResults.value.reduce((sum, result) => sum + result.score, 0);
- return (total / searchResults.value.length * 100).toFixed(1);
- });
- // 解析 Markdown 内容
- const parseMarkdown = (content) => {
- if (!content) return '';
- const markdownSymbols = /[#*+\-`>!]/;
- const isMarkdown = markdownSymbols.test(content);
- return isMarkdown ? marked(content) : content;
- };
- const parsedChatSummary = computed(() => parseMarkdown(chatSummary.value));
- const parsedRagSummary = computed(() => parseMarkdown(ragSummary.value));
- const parsedLlmSummary = computed(() => parseMarkdown(llmSummary.value));
- // 根据分数获取样式类
- const getScoreClass = (score) => {
- if (score >= 0.8) return 'high';
- if (score >= 0.6) return 'medium';
- return 'low';
- };
- // 复制到剪贴板
- const copyToClipboard = async (text) => {
- try {
- await navigator.clipboard.writeText(text);
- ElMessage.success('已复制到剪贴板');
- } catch (err) {
- ElMessage.error('复制失败');
- }
- };
- // PDF相关方法
- const onPdfLoad = () => {
- pdfLoading.value = false;
- };
- const onPdfError = () => {
- pdfLoading.value = false;
- ElMessage.error('PDF文档加载失败,请检查网络连接或文件地址');
- };
- const openPdfInNewTab = () => {
- if (selectedResult.value.url) {
- window.open(selectedResult.value.url, '_blank');
- }
- };
- // 切换可折叠区域
- const toggleSection = (section) => {
- expandedSections.value[section] = !expandedSections.value[section];
- };
- // 清空选择
- const clearSelection = async () => {
- try {
- await ElMessageBox.confirm('确定要清空所有选中的知识库吗?', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- });
- selectedDatasetIds.value = [];
- ElMessage.success('已清空选择');
- } catch {
- // 用户取消操作
- }
- };
- // 方法
- const getKnowledgeBaseList = async () => {
- refreshing.value = true;
- try {
- const response = await fetch(`${API_BASE_URL}/dataset/list`);
- const data = await response.json();
- knowledgeBaseList.value = data.data;
- // ElMessage.success('知识库列表已更新');
- } catch (error) {
- ElMessage.error('获取知识库列表失败');
- } finally {
- refreshing.value = false;
- }
- };
- const toggleDatasetSelection = (datasetId) => {
- const index = selectedDatasetIds.value.indexOf(datasetId);
- if (index === -1) {
- selectedDatasetIds.value.push(datasetId);
- } else {
- selectedDatasetIds.value.splice(index, 1);
- }
- };
- const chat = async () => {
- if (loading.value || !query.value.trim()) return;
- if (selectedDatasetIds.value.length === 0) {
- ElMessage.warning('请先选择知识库');
- return;
- }
- // 重置状态
- chatSummary.value = '';
- ragSummary.value = '';
- llmSummary.value = '';
- searchResults.value = [];
- hasSearched.value = true;
- // 重置展开状态
- expandedSections.value = {
- rag: false,
- llm: false,
- results: false
- };
- loading.value = true;
- try {
- const datasetIds = selectedDatasetIds.value.join(',');
- const response = await fetch(`${API_BASE_URL}/chat?query=${encodeURIComponent(query.value)}&datasetIds=${datasetIds}`);
- const data = await response.json();
- if (data.data) {
- searchResults.value = data.data.results || [];
- chatSummary.value = data.data.chat_res || '';
- ragSummary.value = data.data.rag_summary || '';
- llmSummary.value = data.data.llm_summary || '';
- } else {
- ElMessage.error('未获取到有效数据');
- }
- } catch (error) {
- ElMessage.error('请求失败,请稍后重试');
- } finally {
- loading.value = false;
- }
- };
- const handleDetails = async (result) => {
- selectedResult.value = result;
- dialogVisible.value = true;
- // 根据文档类型设置默认标签页
- if (result.textType === 3) {
- activeTab.value = 'summary';
- if (result.url) {
- pdfLoading.value = true;
- }
- } else {
- activeTab.value = 'summary';
- }
- try {
- const response = await fetch(`${API_BASE_URL}/content/get?docId=${result.docId}`);
- const data = await response.json();
- if (data.status_code === 200) {
- originalContent.value = data.data.text;
- // 更新选中结果的数据,确保包含完整的文档信息
- selectedResult.value = {
- ...selectedResult.value,
- textType: data.data.textType,
- url: data.data.url
- };
- } else {
- ElMessage.error('获取原文内容失败');
- }
- } catch (error) {
- ElMessage.error('请求原文内容失败');
- }
- };
- // 生命周期
- onMounted(() => {
- getKnowledgeBaseList();
- });
- </script>
- <style scoped>
- /* 基础样式 */
- .app-container {
- min-height: 100vh;
- background: linear-gradient(135deg, rgba(102, 126, 234, 0.6) 0%, rgba(118, 75, 162, 0.4) 100%);
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- }
- /* 顶部导航样式 */
- .app-header {
- background: rgba(255, 255, 255, 0.1);
- backdrop-filter: blur(20px);
- padding: 16px 0;
- border-bottom: 1px solid rgba(255, 255, 255, 0.1);
- }
- .header-content {
- max-width: 1400px;
- margin: 0 auto;
- padding: 0 24px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .header-main {
- flex: 1;
- }
- .app-title {
- color: white;
- font-size: 2.25rem;
- font-weight: 800;
- margin: 0;
- text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
- background: linear-gradient(135deg, #fff 0%, #e2e8f0 100%);
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
- }
- .app-subtitle {
- color: rgba(255, 255, 255, 0.8);
- font-size: 1rem;
- margin: 8px 0 0 0;
- font-weight: 500;
- }
- .header-stats {
- display: flex;
- gap: 24px;
- }
- .stat-item {
- display: flex;
- flex-direction: column;
- align-items: center;
- }
- .stat-number {
- color: white;
- font-size: 1.5rem;
- font-weight: 700;
- }
- .stat-label {
- color: rgba(255, 255, 255, 0.7);
- font-size: 0.8rem;
- margin-top: 4px;
- }
- /* 主布局 */
- .main-layout {
- display: flex;
- max-width: 1400px;
- margin: 0 auto;
- padding: 24px;
- gap: 24px;
- min-height: calc(100vh - 120px);
- align-items: flex-start;
- }
- /* 侧边栏样式 - 固定位置 */
- .sidebar {
- width: 320px;
- flex-shrink: 0;
- display: flex;
- flex-direction: column;
- position: sticky;
- top: 24px;
- max-height: calc(100vh - 120px);
- overflow-y: auto;
- }
- .sidebar-header {
- background: white;
- padding: 20px;
- border-radius: 20px;
- margin-bottom: 16px;
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- flex-shrink: 0;
- }
- .sidebar-title h3 {
- margin: 0 0 6px 0;
- color: #2d3748;
- font-size: 1.25rem;
- font-weight: 700;
- }
- .sidebar-subtitle {
- margin: 0;
- color: #718096;
- font-size: 0.85rem;
- }
- .refresh-btn {
- padding: 8px;
- border-radius: 10px;
- border: 1px solid #e2e8f0;
- background: white;
- transition: all 0.3s ease;
- }
- .refresh-btn:hover {
- background: #f7fafc;
- transform: rotate(90deg);
- }
- .knowledge-list {
- flex: 1;
- display: flex;
- flex-direction: column;
- gap: 12px;
- overflow-y: auto;
- min-height: 0;
- }
- .knowledge-card {
- background: white;
- padding: 16px;
- border-radius: 16px;
- cursor: pointer;
- transition: all 0.3s ease;
- border: 2px solid transparent;
- display: flex;
- align-items: center;
- gap: 12px;
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
- overflow: hidden;
- }
- .knowledge-card:hover {
- transform: translateY(-4px);
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
- }
- .knowledge-card.active {
- border-color: #4299e1;
- background: linear-gradient(135deg, #ebf8ff 0%, #ffffff 100%);
- }
- .card-content {
- padding: 16px;
- display: flex;
- align-items: flex-start;
- gap: 12px;
- }
- .knowledge-icon {
- font-size: 1.25rem;
- width: 40px;
- height: 40px;
- display: flex;
- align-items: center;
- justify-content: center;
- background: #f7fafc;
- border-radius: 10px;
- flex-shrink: 0;
- }
- .knowledge-info {
- flex: 1;
- min-width: 0;
- }
- .knowledge-name {
- display: block;
- font-weight: 600;
- color: #2d3748;
- margin-bottom: 4px;
- font-size: 0.95rem;
- line-height: 1.4;
- }
- .knowledge-desc {
- display: block;
- color: #718096;
- font-size: 0.8rem;
- line-height: 1.4;
- margin-bottom: 6px;
- }
- .knowledge-status {
- font-size: 0.75rem;
- color: #a0aec0;
- font-weight: 500;
- }
- .knowledge-status.active {
- color: #4299e1;
- font-weight: 600;
- }
- .sidebar-footer {
- background: white;
- padding: 16px 20px;
- border-radius: 16px;
- margin-top: 16px;
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
- display: flex;
- justify-content: space-between;
- align-items: center;
- flex-shrink: 0;
- position: sticky;
- bottom: 0;
- z-index: 10;
- }
- .selected-count {
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .count-number {
- background: #4299e1;
- color: white;
- padding: 4px 10px;
- border-radius: 12px;
- font-size: 0.85rem;
- font-weight: 700;
- }
- .count-label {
- color: #718096;
- font-size: 0.85rem;
- }
- .clear-btn {
- font-size: 0.8rem;
- padding: 6px 12px;
- border-radius: 8px;
- }
- /* 主内容区样式 */
- .content-area {
- flex: 1;
- display: flex;
- flex-direction: column;
- gap: 24px;
- min-height: 0;
- }
- .search-section {
- width: 100%;
- }
- .search-card {
- background: white;
- padding: 32px;
- border-radius: 24px;
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.12);
- }
- .search-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- margin-bottom: 28px;
- }
- .search-title h2 {
- margin: 0 0 8px 0;
- color: #2d3748;
- font-size: 1.75rem;
- font-weight: 700;
- }
- .search-title p {
- margin: 0;
- color: #718096;
- font-size: 1rem;
- }
- .search-tips {
- display: flex;
- gap: 12px;
- }
- .tip-item {
- background: #f7fafc;
- padding: 6px 12px;
- border-radius: 12px;
- font-size: 0.8rem;
- color: #718096;
- border: 1px solid #e2e8f0;
- }
- /* 搜索框和按钮高度统一 */
- .search-input-group {
- display: flex;
- gap: 16px;
- margin-bottom: 24px;
- align-items: stretch;
- }
- .input-container {
- flex: 1;
- display: flex;
- flex-direction: column;
- }
- .search-input {
- border-radius: 16px;
- height: 100%;
- }
- .search-input :deep(.el-input__wrapper) {
- border-radius: 16px;
- padding: 16px 20px;
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
- border: 1px solid #e2e8f0;
- transition: all 0.3s ease;
- height: 56px;
- display: flex;
- align-items: center;
- }
- .search-input :deep(.el-input__wrapper:hover) {
- border-color: #4299e1;
- box-shadow: 0 4px 20px rgba(66, 153, 225, 0.15);
- }
- .search-input :deep(.el-input__wrapper.is-focus) {
- border-color: #4299e1;
- box-shadow: 0 4px 20px rgba(66, 153, 225, 0.2);
- }
- .input-icon {
- font-size: 1.25rem;
- margin-right: 8px;
- }
- .input-tips {
- font-size: 0.8rem;
- color: #718096;
- margin-top: 8px;
- text-align: center;
- }
- .search-button {
- border-radius: 16px;
- padding: 16px 32px;
- font-weight: 600;
- transition: all 0.3s ease;
- min-width: 140px;
- height: 56px;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .search-button:not(:disabled):hover {
- transform: translateY(-2px);
- box-shadow: 0 8px 25px rgba(66, 153, 225, 0.4);
- }
- .button-loading {
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .loading-spinner {
- width: 16px;
- height: 16px;
- border: 2px solid transparent;
- border-top: 2px solid white;
- border-radius: 50%;
- animation: spin 1s linear infinite;
- }
- @keyframes spin {
- 0% {
- transform: rotate(0deg);
- }
- 100% {
- transform: rotate(360deg);
- }
- }
- .button-content {
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .button-icon {
- font-size: 1.1rem;
- }
- .quick-questions {
- border-top: 1px solid #e2e8f0;
- padding-top: 20px;
- }
- .quick-title {
- margin: 0 0 12px 0;
- color: #718096;
- font-size: 0.9rem;
- font-weight: 600;
- }
- .question-chips {
- display: flex;
- flex-wrap: wrap;
- gap: 8px;
- }
- .question-chip {
- cursor: pointer;
- border-radius: 20px;
- padding: 8px 16px;
- transition: all 0.3s ease;
- border: 1px solid #e2e8f0;
- background: white;
- font-size: 0.85rem;
- }
- .question-chip:hover {
- background: #4299e1;
- color: white;
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(66, 153, 225, 0.3);
- }
- /* 加载状态 */
- .loading-section {
- background: white;
- border-radius: 24px;
- padding: 60px 32px;
- text-align: center;
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.12);
- }
- .loading-content {
- max-width: 400px;
- margin: 0 auto;
- }
- .loading-animation {
- margin-bottom: 24px;
- }
- .thinking-robot {
- font-size: 4rem;
- margin-bottom: 16px;
- animation: bounce 2s infinite;
- }
- @keyframes bounce {
- 0%, 20%, 50%, 80%, 100% {
- transform: translateY(0);
- }
- 40% {
- transform: translateY(-10px);
- }
- 60% {
- transform: translateY(-5px);
- }
- }
- .thinking-dots {
- display: flex;
- justify-content: center;
- gap: 8px;
- margin-bottom: 20px;
- }
- .thinking-dots span {
- width: 12px;
- height: 12px;
- border-radius: 50%;
- background: #4299e1;
- animation: bounce 1.4s infinite ease-in-out;
- }
- .thinking-dots span:nth-child(1) {
- animation-delay: -0.32s;
- }
- .thinking-dots span:nth-child(2) {
- animation-delay: -0.16s;
- }
- .loading-text {
- color: #2d3748;
- font-size: 1.2rem;
- font-weight: 600;
- margin: 0 0 8px 0;
- }
- .loading-subtext {
- color: #718096;
- font-size: 0.95rem;
- margin: 0;
- }
- /* 最终回答卡片 */
- .thinking-card.answer-card {
- background: white;
- border-radius: 20px;
- overflow: hidden;
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.12);
- border-left: 6px solid #48bb78;
- }
- .answer-card .card-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 24px 28px;
- background: linear-gradient(135deg, #f0fff4 0%, #ffffff 100%);
- border-bottom: 1px solid #e2e8f0;
- }
- .answer-card .card-body {
- padding: 0 28px 28px;
- }
- /* 可折叠区域样式 */
- .collapsible-section {
- background: white;
- border-radius: 20px;
- overflow: hidden;
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
- margin-bottom: 16px;
- transition: all 0.3s ease;
- }
- .collapsible-section:hover {
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
- }
- .collapsible-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 20px 28px;
- cursor: pointer;
- transition: background-color 0.3s ease;
- border-bottom: 1px solid transparent;
- }
- .collapsible-header:hover {
- background: rgba(0, 0, 0, 0.02);
- }
- .collapsible-section:has(.collapsible-content:not([style*="display: none"])) .collapsible-header {
- border-bottom-color: #e2e8f0;
- }
- .header-main {
- display: flex;
- align-items: center;
- gap: 16px;
- flex: 1;
- }
- .header-actions {
- display: flex;
- align-items: center;
- gap: 12px;
- }
- .action-btn {
- padding: 8px;
- border-radius: 10px;
- transition: all 0.3s ease;
- }
- .action-btn:hover {
- background: #f7fafc;
- }
- .collapse-icon {
- transition: transform 0.3s ease;
- color: #718096;
- font-size: 14px;
- }
- .collapse-icon.rotated {
- transform: rotate(180deg);
- }
- .collapsible-content {
- padding: 0;
- }
- /* 为不同部分设置不同的左侧边框颜色 */
- .collapsible-section:nth-child(1) .collapsible-header {
- border-left: 6px solid #4299e1;
- }
- .collapsible-section:nth-child(2) .collapsible-header {
- border-left: 6px solid #9f7aea;
- }
- .collapsible-section:nth-child(3) .collapsible-header {
- border-left: 6px solid #ed8936;
- }
- .header-icon {
- font-size: 1.75rem;
- width: 52px;
- height: 52px;
- display: flex;
- align-items: center;
- justify-content: center;
- background: white;
- border-radius: 12px;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
- }
- .header-content h3 {
- margin: 0 0 6px 0;
- color: #2d3748;
- font-size: 1.3rem;
- font-weight: 700;
- }
- .header-content p {
- margin: 0;
- color: #718096;
- font-size: 0.9rem;
- }
- .card-body {
- padding: 0 28px 28px;
- }
- .thinking-content {
- line-height: 1.7;
- color: #4a5568;
- font-size: 1rem;
- }
- .thinking-content :deep(h1),
- .thinking-content :deep(h2),
- .thinking-content :deep(h3) {
- color: #2d3748;
- margin-top: 1.5em;
- margin-bottom: 0.5em;
- }
- .thinking-content :deep(p) {
- margin-bottom: 1em;
- }
- .thinking-content :deep(ul),
- .thinking-content :deep(ol) {
- margin: 1em 0;
- padding-left: 1.5em;
- }
- .thinking-content :deep(li) {
- margin-bottom: 0.5em;
- }
- .thinking-content :deep(code) {
- background: #f7fafc;
- padding: 2px 6px;
- border-radius: 4px;
- font-family: 'Monaco', 'Consolas', monospace;
- color: #e53e3e;
- font-size: 0.9em;
- }
- .thinking-content :deep(pre) {
- background: #2d3748;
- color: #e2e8f0;
- padding: 20px;
- border-radius: 12px;
- overflow-x: auto;
- margin: 1.5em 0;
- font-size: 0.9em;
- }
- .thinking-content :deep(blockquote) {
- border-left: 4px solid #4299e1;
- margin: 1.5em 0;
- padding-left: 20px;
- color: #718096;
- font-style: italic;
- }
- /* 搜索结果样式 */
- .results-container {
- padding: 0;
- }
- .results-stats {
- padding: 20px 28px;
- background: #f7fafc;
- border-bottom: 1px solid #e2e8f0;
- display: flex;
- gap: 24px;
- }
- .results-stats .stat {
- color: #718096;
- font-size: 0.9rem;
- font-weight: 500;
- }
- .results-grid {
- padding: 24px 28px;
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
- gap: 20px;
- }
- .result-card {
- background: white;
- border-radius: 16px;
- padding: 20px;
- cursor: pointer;
- transition: all 0.3s ease;
- border: 1px solid #e2e8f0;
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
- position: relative;
- overflow: hidden;
- }
- .result-card:hover {
- transform: translateY(-4px);
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
- border-color: #4299e1;
- }
- .result-badge {
- position: absolute;
- top: 12px;
- right: 12px;
- background: #4299e1;
- color: white;
- padding: 4px 10px;
- border-radius: 12px;
- font-size: 0.8rem;
- font-weight: 700;
- }
- .result-header {
- margin-bottom: 12px;
- }
- .result-title {
- margin: 0 0 12px 0;
- color: #2d3748;
- font-size: 1.1rem;
- font-weight: 600;
- line-height: 1.4;
- }
- .result-meta {
- display: flex;
- gap: 8px;
- align-items: center;
- flex-wrap: wrap;
- }
- .score-badge {
- padding: 4px 10px;
- border-radius: 12px;
- font-size: 0.8rem;
- font-weight: 700;
- color: white;
- }
- .score-badge.high {
- background: #48bb78;
- }
- .score-badge.medium {
- background: #ed8936;
- }
- .score-badge.low {
- background: #e53e3e;
- }
- .source-tag {
- background: #f7fafc;
- padding: 4px 10px;
- border-radius: 12px;
- font-size: 0.8rem;
- color: #718096;
- border: 1px solid #e2e8f0;
- }
- .file-type {
- padding: 4px 10px;
- border-radius: 12px;
- font-size: 0.8rem;
- font-weight: 600;
- color: white;
- }
- .file-type.pdf-type {
- background: #e53e3e;
- }
- .file-type.text-type {
- background: #48bb78;
- }
- .result-preview {
- margin: 0 0 16px 0;
- color: #718096;
- line-height: 1.5;
- font-size: 0.9rem;
- display: -webkit-box;
- -webkit-line-clamp: 3;
- -webkit-box-orient: vertical;
- overflow: hidden;
- }
- .result-footer {
- display: flex;
- justify-content: flex-end;
- }
- .view-details {
- color: #4299e1;
- font-weight: 600;
- font-size: 0.9rem;
- transition: color 0.3s ease;
- display: flex;
- align-items: center;
- gap: 6px;
- }
- .view-icon {
- font-size: 0.8rem;
- }
- .result-card:hover .view-details {
- color: #2b6cb0;
- }
- /* 空状态 */
- .empty-state {
- background: white;
- border-radius: 24px;
- padding: 80px 32px;
- text-align: center;
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.12);
- }
- .empty-content {
- max-width: 400px;
- margin: 0 auto;
- }
- .empty-icon {
- font-size: 4rem;
- margin-bottom: 20px;
- }
- .empty-state h3 {
- margin: 0 0 12px 0;
- color: #2d3748;
- font-size: 1.5rem;
- font-weight: 700;
- }
- .empty-state p {
- margin: 0 0 24px 0;
- color: #718096;
- font-size: 1rem;
- line-height: 1.5;
- }
- .retry-btn {
- border-radius: 12px;
- padding: 10px 24px;
- }
- /* 欢迎状态 */
- .welcome-state {
- background: white;
- border-radius: 24px;
- padding: 80px 32px;
- text-align: center;
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.12);
- }
- .welcome-content {
- max-width: 500px;
- margin: 0 auto;
- }
- .welcome-icon {
- font-size: 5rem;
- margin-bottom: 24px;
- animation: float 3s ease-in-out infinite;
- }
- @keyframes float {
- 0%, 100% {
- transform: translateY(0px);
- }
- 50% {
- transform: translateY(-10px);
- }
- }
- .welcome-state h3 {
- margin: 0 0 16px 0;
- color: #2d3748;
- font-size: 1.75rem;
- font-weight: 700;
- }
- .welcome-state p {
- margin: 0 0 32px 0;
- color: #718096;
- font-size: 1.1rem;
- line-height: 1.6;
- }
- .feature-list {
- display: flex;
- flex-direction: column;
- gap: 12px;
- max-width: 300px;
- margin: 0 auto;
- }
- .feature-item {
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 12px 16px;
- background: #f7fafc;
- border-radius: 12px;
- color: #4a5568;
- font-size: 0.95rem;
- }
- .feature-icon {
- font-size: 1.2rem;
- }
- /* 弹窗样式 */
- .content-dialog :deep(.el-dialog) {
- border-radius: 24px;
- overflow: hidden;
- box-shadow: 0 25px 50px rgba(0, 0, 0, 0.2);
- }
- .content-dialog :deep(.el-dialog__header) {
- padding: 0;
- margin: 0;
- }
- .content-dialog :deep(.el-dialog__headerbtn) {
- top: 24px;
- right: 24px;
- width: 32px;
- height: 32px;
- border-radius: 8px;
- background: #f7fafc;
- }
- .content-dialog :deep(.el-dialog__headerbtn:hover) {
- background: #e2e8f0;
- }
- .dialog-header {
- padding: 0;
- }
- .dialog-title {
- display: flex;
- align-items: flex-start;
- gap: 16px;
- padding: 32px 32px 0;
- }
- .title-icon {
- font-size: 2.5rem;
- width: 60px;
- height: 60px;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 16px;
- color: white;
- flex-shrink: 0;
- }
- .title-icon.pdf-icon {
- background: linear-gradient(135deg, #e53e3e 0%, #c53030 100%);
- }
- .title-icon.text-icon {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- }
- .title-content {
- flex: 1;
- min-width: 0;
- }
- .title-content h3 {
- margin: 0 0 12px 0;
- color: #2d3748;
- font-size: 1.5rem;
- font-weight: 700;
- line-height: 1.4;
- }
- .title-meta {
- display: flex;
- gap: 12px;
- flex-wrap: wrap;
- }
- .meta-badge {
- display: flex;
- align-items: center;
- gap: 6px;
- padding: 6px 12px;
- border-radius: 12px;
- font-size: 0.85rem;
- font-weight: 500;
- }
- .knowledge-badge {
- background: #ebf8ff;
- color: #2b6cb0;
- border: 1px solid #bee3f8;
- }
- .score-badge.high {
- background: #f0fff4;
- color: #2f855a;
- border: 1px solid #c6f6d5;
- }
- .score-badge.medium {
- background: #fffaf0;
- color: #c05621;
- border: 1px solid #feebc8;
- }
- .score-badge.low {
- background: #fff5f5;
- color: #c53030;
- border: 1px solid #fed7d7;
- }
- .file-type-badge.pdf-badge {
- background: #fff5f5;
- color: #c53030;
- border: 1px solid #fed7d7;
- }
- .file-type-badge.text-badge {
- background: #f0fff4;
- color: #2f855a;
- border: 1px solid #c6f6d5;
- }
- .badge-icon {
- font-size: 0.8rem;
- }
- .dialog-content {
- padding: 0;
- }
- .content-tabs {
- display: flex;
- padding: 0 32px;
- border-bottom: 1px solid #e2e8f0;
- margin-top: 24px;
- }
- .tab-item {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 12px 20px;
- cursor: pointer;
- border-bottom: 2px solid transparent;
- color: #718096;
- font-weight: 500;
- transition: all 0.3s ease;
- }
- .tab-item:hover {
- color: #4299e1;
- }
- .tab-item.active {
- color: #4299e1;
- border-bottom-color: #4299e1;
- }
- .tab-icon {
- font-size: 1.1rem;
- }
- .tab-content {
- padding: 0 32px 32px;
- }
- .content-section {
- margin-top: 24px;
- }
- .section-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 16px;
- }
- .section-header h4 {
- margin: 0;
- color: #2d3748;
- font-size: 1.2rem;
- font-weight: 600;
- }
- .copy-btn, .view-pdf-btn {
- font-size: 0.9rem;
- padding: 6px 12px;
- border-radius: 8px;
- }
- .summary-content {
- background: #f7fafc;
- padding: 20px;
- border-radius: 12px;
- color: #4a5568;
- line-height: 1.6;
- font-size: 0.95rem;
- border: 1px solid #e2e8f0;
- }
- .original-content {
- background: #f7fafc;
- border-radius: 12px;
- border: 1px solid #e2e8f0;
- max-height: 500px;
- overflow-y: auto;
- }
- .original-content pre {
- margin: 0;
- padding: 20px;
- color: #4a5568;
- line-height: 1.6;
- font-size: 0.9rem;
- white-space: pre-wrap;
- word-wrap: break-word;
- }
- /* PDF内容展示样式 */
- .pdf-content {
- flex: 1;
- display: flex;
- flex-direction: column;
- }
- .pdf-viewer-container {
- flex: 1;
- position: relative;
- border: 1px solid #e2e8f0;
- border-radius: 12px;
- overflow: hidden;
- background: #f7fafc;
- min-height: 500px;
- }
- .pdf-viewer {
- width: 100%;
- height: 100%;
- min-height: 500px;
- background: white;
- }
- .pdf-loading {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- background: rgba(255, 255, 255, 0.9);
- }
- .pdf-loading .loading-spinner {
- width: 40px;
- height: 40px;
- border: 4px solid #e2e8f0;
- border-top: 4px solid #4299e1;
- border-radius: 50%;
- animation: spin 1s linear infinite;
- margin-bottom: 16px;
- }
- .pdf-loading p {
- margin: 0;
- color: #718096;
- font-size: 1rem;
- }
- .pdf-empty {
- text-align: center;
- padding: 60px 20px;
- background: #f7fafc;
- border-radius: 12px;
- border: 1px solid #e2e8f0;
- }
- .pdf-empty .empty-icon {
- font-size: 3rem;
- margin-bottom: 16px;
- opacity: 0.6;
- }
- .pdf-empty h3 {
- margin: 0 0 8px 0;
- color: #2d3748;
- font-size: 1.25rem;
- font-weight: 600;
- }
- .pdf-empty p {
- margin: 0;
- color: #718096;
- font-size: 0.95rem;
- }
- .dialog-footer {
- padding: 0 32px 24px;
- }
- .footer-actions {
- display: flex;
- justify-content: flex-end;
- gap: 12px;
- }
- .action-btn {
- border-radius: 12px;
- padding: 10px 24px;
- font-weight: 500;
- transition: all 0.3s ease;
- }
- .action-btn.secondary {
- border: 1px solid #e2e8f0;
- background: white;
- color: #718096;
- }
- .action-btn.secondary:hover {
- background: #f7fafc;
- border-color: #cbd5e0;
- }
- .action-btn.primary {
- background: #4299e1;
- border: 1px solid #4299e1;
- color: white;
- }
- .action-btn.primary:hover {
- background: #3182ce;
- border-color: #3182ce;
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(66, 153, 225, 0.3);
- }
- /* 在样式部分添加 */
- .header-actions {
- display: flex;
- align-items: center;
- }
- .history-btn {
- background: rgba(255, 255, 255, 0.2);
- border: 1px solid rgba(255, 255, 255, 0.3);
- color: white;
- border-radius: 12px;
- padding: 10px 20px;
- font-weight: 600;
- transition: all 0.3s ease;
- backdrop-filter: blur(10px);
- margin-left: 50px;
- }
- .history-btn:hover {
- background: rgba(255, 255, 255, 0.3);
- transform: translateY(-2px);
- box-shadow: 0 8px 25px rgba(255, 255, 255, 0.2);
- }
- .btn-icon {
- margin-right: 6px;
- }
- /* 响应式设计 */
- @media (max-width: 1200px) {
- .main-layout {
- flex-direction: column;
- }
- .sidebar {
- width: 100%;
- position: static;
- max-height: none;
- margin-bottom: 20px;
- }
- .sidebar-footer {
- position: static;
- }
- .results-grid {
- grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
- }
- }
- @media (max-width: 768px) {
- .app-title {
- font-size: 1.75rem;
- }
- .header-content {
- flex-direction: column;
- gap: 16px;
- text-align: center;
- }
- .header-stats {
- gap: 32px;
- }
- .main-layout {
- padding: 16px;
- }
- .search-card {
- padding: 24px;
- }
- .search-header {
- flex-direction: column;
- gap: 16px;
- text-align: center;
- }
- .search-tips {
- justify-content: center;
- }
- .search-input-group {
- flex-direction: column;
- }
- .search-button {
- width: 100%;
- }
- .collapsible-header {
- padding: 16px 20px;
- }
- .header-main {
- gap: 12px;
- }
- .header-icon {
- width: 44px;
- height: 44px;
- font-size: 1.5rem;
- }
- .results-grid {
- grid-template-columns: 1fr;
- }
- .dialog-title {
- flex-direction: column;
- text-align: center;
- gap: 12px;
- }
- .title-content h3 {
- font-size: 1.3rem;
- }
- .content-tabs {
- padding: 0 20px;
- flex-wrap: wrap;
- }
- .tab-content {
- padding: 0 20px 20px;
- }
- .pdf-viewer {
- min-height: 400px;
- }
- }
- @media (max-width: 480px) {
- .app-title {
- font-size: 1.5rem;
- }
- .search-card {
- padding: 20px;
- }
- .thinking-card .card-header,
- .collapsible-header {
- padding: 16px;
- }
- .card-body {
- padding: 0 16px 16px;
- }
- .results-grid {
- grid-template-columns: 1fr;
- }
- .content-dialog :deep(.el-dialog) {
- width: 95% !important;
- margin: 20px auto;
- }
- .title-meta {
- flex-direction: column;
- align-items: flex-start;
- gap: 8px;
- }
- .result-meta {
- flex-direction: column;
- align-items: flex-start;
- gap: 8px;
- }
- }
- /* 侧边栏滚动条样式 */
- .sidebar::-webkit-scrollbar {
- width: 6px;
- }
- .sidebar::-webkit-scrollbar-track {
- background: #f1f1f1;
- border-radius: 3px;
- }
- .sidebar::-webkit-scrollbar-thumb {
- background: #c1c1c1;
- border-radius: 3px;
- }
- .sidebar::-webkit-scrollbar-thumb:hover {
- background: #a8a8a8;
- }
- .knowledge-list::-webkit-scrollbar {
- width: 4px;
- }
- .knowledge-list::-webkit-scrollbar-track {
- background: transparent;
- }
- .knowledge-list::-webkit-scrollbar-thumb {
- background: #d1d1d1;
- border-radius: 2px;
- }
- </style>
|