|
@@ -2,7 +2,7 @@
|
|
<div class="knowledge-results">
|
|
<div class="knowledge-results">
|
|
<!-- 搜索框 -->
|
|
<!-- 搜索框 -->
|
|
<div class="search-box">
|
|
<div class="search-box">
|
|
- <div class="input-wrapper">
|
|
|
|
|
|
+ <!-- <div class="input-wrapper">
|
|
<input
|
|
<input
|
|
v-model="searchQuery"
|
|
v-model="searchQuery"
|
|
type="text"
|
|
type="text"
|
|
@@ -15,7 +15,7 @@
|
|
class="clear-icon"
|
|
class="clear-icon"
|
|
@click="clearSearch"
|
|
@click="clearSearch"
|
|
>×</span>
|
|
>×</span>
|
|
- </div>
|
|
|
|
|
|
+ </div> -->
|
|
<!-- <button @click="handleSearch" :disabled="isSearching" class="search-button">
|
|
<!-- <button @click="handleSearch" :disabled="isSearching" class="search-button">
|
|
{{ isSearching ? '搜索中...' : '搜索' }}
|
|
{{ isSearching ? '搜索中...' : '搜索' }}
|
|
</button> -->
|
|
</button> -->
|
|
@@ -29,8 +29,14 @@
|
|
@scroll="handleScroll"
|
|
@scroll="handleScroll"
|
|
>
|
|
>
|
|
<div v-for="result in displayResults" :key="result.id" class="result-item">
|
|
<div v-for="result in displayResults" :key="result.id" class="result-item">
|
|
- <div class="result-title">{{ result.title }}</div>
|
|
|
|
|
|
+ <h3 class="result-title">
|
|
|
|
+ <a :href="result.link" target="_blank" rel="noopener noreferrer">{{ result.title }}</a>
|
|
|
|
+ </h3>
|
|
<div class="result-content" v-html="formatContent(result.content)"></div>
|
|
<div class="result-content" v-html="formatContent(result.content)"></div>
|
|
|
|
+ <div v-if="result.translation" class="result-translation">
|
|
|
|
+ <span class="translation-label">中文释义:</span>
|
|
|
|
+ <span class="translation-content">{{ result.translation }}</span>
|
|
|
|
+ </div>
|
|
<div class="result-meta">
|
|
<div class="result-meta">
|
|
<span class="result-source">来源: {{ result.source || '知识库' }}</span>
|
|
<span class="result-source">来源: {{ result.source || '知识库' }}</span>
|
|
<span class="result-date">{{ formatDate(result.date) }}</span>
|
|
<span class="result-date">{{ formatDate(result.date) }}</span>
|
|
@@ -87,10 +93,15 @@ export default defineComponent({
|
|
type: String,
|
|
type: String,
|
|
default: 'remote', // 'remote' 或 'local'
|
|
default: 'remote', // 'remote' 或 'local'
|
|
validator: (value) => ['remote', 'local'].includes(value)
|
|
validator: (value) => ['remote', 'local'].includes(value)
|
|
|
|
+ },
|
|
|
|
+ // 添加是否显示中文释义的配置
|
|
|
|
+ showTranslation: {
|
|
|
|
+ type: Boolean,
|
|
|
|
+ default: true
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
|
|
- emits: ['update:enableSearch', 'search'],
|
|
|
|
|
|
+ emits: ['update:enableSearch', 'search', 'translate'],
|
|
|
|
|
|
setup(props, { emit }) {
|
|
setup(props, { emit }) {
|
|
const searchQuery = ref('');
|
|
const searchQuery = ref('');
|
|
@@ -107,8 +118,11 @@ export default defineComponent({
|
|
|
|
|
|
// 监听搜索结果变化
|
|
// 监听搜索结果变化
|
|
watch(() => props.searchResults, (newResults) => {
|
|
watch(() => props.searchResults, (newResults) => {
|
|
- console.log(newResults);
|
|
|
|
- displayResults.value = newResults;
|
|
|
|
|
|
+ console.log('New search results:', newResults);
|
|
|
|
+ displayResults.value = newResults.map(result => ({
|
|
|
|
+ ...result,
|
|
|
|
+ translation: result.translation || '' // 确保translation字段存在
|
|
|
|
+ }));
|
|
});
|
|
});
|
|
|
|
|
|
// 监听 message prop 的变化
|
|
// 监听 message prop 的变化
|
|
@@ -130,7 +144,8 @@ export default defineComponent({
|
|
query: searchQuery.value,
|
|
query: searchQuery.value,
|
|
page: page.value,
|
|
page: page.value,
|
|
pageSize: pageSize.value,
|
|
pageSize: pageSize.value,
|
|
- type: props.searchType
|
|
|
|
|
|
+ type: props.searchType,
|
|
|
|
+ needTranslation: props.showTranslation // 添加是否需要翻译的标志
|
|
});
|
|
});
|
|
} finally {
|
|
} finally {
|
|
isSearching.value = false;
|
|
isSearching.value = false;
|
|
@@ -176,12 +191,13 @@ export default defineComponent({
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
- // 添加格式化内容的方法
|
|
|
|
|
|
+ // 格式化内容的方法
|
|
const formatContent = (content) => {
|
|
const formatContent = (content) => {
|
|
if (!content) return '';
|
|
if (!content) return '';
|
|
- // 将内容中的关键词高亮显示
|
|
|
|
- return content.replace(new RegExp(searchQuery.value, 'gi'),
|
|
|
|
- match => `<span style="color: #1677ff; font-weight: 500;">${match}</span>`
|
|
|
|
|
|
+ // 将内容中的关键词高亮显示,同时处理HTML标签
|
|
|
|
+ const escapedQuery = searchQuery.value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
|
|
+ return content.replace(new RegExp(escapedQuery, 'gi'),
|
|
|
|
+ match => `<span class="highlight">${match}</span>`
|
|
);
|
|
);
|
|
};
|
|
};
|
|
|
|
|
|
@@ -386,41 +402,68 @@ export default defineComponent({
|
|
}
|
|
}
|
|
|
|
|
|
.result-item {
|
|
.result-item {
|
|
- padding: var(--base-spacing);
|
|
|
|
- margin-bottom: var(--base-spacing);
|
|
|
|
- border-radius: var(--border-radius);
|
|
|
|
- background: #fff;
|
|
|
|
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
+ padding: 20px 0;
|
|
|
|
+ border-bottom: 1px solid #f0f0f0;
|
|
transition: all 0.3s ease;
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
- @media (max-width: 480px) {
|
|
|
|
- padding: calc(var(--base-spacing) / 2);
|
|
|
|
- margin-bottom: calc(var(--base-spacing) / 2);
|
|
|
|
|
|
+ &:last-child {
|
|
|
|
+ border-bottom: none;
|
|
}
|
|
}
|
|
|
|
|
|
&:hover {
|
|
&:hover {
|
|
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
|
|
- transform: translateY(-2px);
|
|
|
|
|
|
+ background: rgba(0, 0, 0, 0.02);
|
|
}
|
|
}
|
|
|
|
|
|
.result-title {
|
|
.result-title {
|
|
- font-size: calc(var(--base-font-size) + 2px);
|
|
|
|
- margin-bottom: 8px;
|
|
|
|
- color: #1677ff;
|
|
|
|
|
|
+ margin: 0 0 8px;
|
|
|
|
+ font-size: 16px;
|
|
|
|
+
|
|
|
|
+ a {
|
|
|
|
+ color: #1677ff;
|
|
|
|
+ text-decoration: none;
|
|
|
|
|
|
- @media (max-width: 480px) {
|
|
|
|
- font-size: var(--base-font-size);
|
|
|
|
|
|
+ &:hover {
|
|
|
|
+ text-decoration: underline;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
.result-content {
|
|
.result-content {
|
|
- font-size: var(--small-font-size);
|
|
|
|
color: rgba(0, 0, 0, 0.65);
|
|
color: rgba(0, 0, 0, 0.65);
|
|
- margin-bottom: 12px;
|
|
|
|
- line-height: 1.6;
|
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
+ line-height: 1.5;
|
|
|
|
+ }
|
|
|
|
|
|
- @media (max-width: 480px) {
|
|
|
|
- font-size: var(--smaller-font-size);
|
|
|
|
|
|
+ .result-translation {
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ color: rgba(0, 0, 0, 0.65);
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
+ padding: 8px;
|
|
|
|
+ background: #f5f5f5;
|
|
|
|
+ border-radius: 4px;
|
|
|
|
+
|
|
|
|
+ .translation-label {
|
|
|
|
+ color: rgba(0, 0, 0, 0.85);
|
|
|
|
+ font-weight: 500;
|
|
|
|
+ margin-right: 8px;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .translation-content {
|
|
|
|
+ color: rgba(0, 0, 0, 0.65);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .result-meta {
|
|
|
|
+ font-size: 12px;
|
|
|
|
+ color: rgba(0, 0, 0, 0.45);
|
|
|
|
+ display: flex;
|
|
|
|
+ gap: 16px;
|
|
|
|
+
|
|
|
|
+ .result-date,
|
|
|
|
+ .result-source {
|
|
|
|
+ display: inline-flex;
|
|
|
|
+ align-items: center;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -488,6 +531,22 @@ export default defineComponent({
|
|
.result-content {
|
|
.result-content {
|
|
color: rgba(255, 255, 255, 0.65);
|
|
color: rgba(255, 255, 255, 0.65);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ .result-translation {
|
|
|
|
+ background: #1f1f1f;
|
|
|
|
+
|
|
|
|
+ .translation-label {
|
|
|
|
+ color: rgba(255, 255, 255, 0.85);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .translation-content {
|
|
|
|
+ color: rgba(255, 255, 255, 0.65);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .result-meta {
|
|
|
|
+ color: rgba(255, 255, 255, 0.45);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -559,4 +618,12 @@ export default defineComponent({
|
|
transition: none;
|
|
transition: none;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+.highlight {
|
|
|
|
+ color: #1677ff;
|
|
|
|
+ font-weight: 500;
|
|
|
|
+ padding: 0 2px;
|
|
|
|
+ border-radius: 2px;
|
|
|
|
+ background: rgba(24, 144, 255, 0.1);
|
|
|
|
+}
|
|
</style>
|
|
</style>
|