Skip to content

Commit 31aeb63

Browse files
authored
Merge pull request #2305 from xinnan-tech/his_download
add:首页智能体添加搜索记录
2 parents 1417ee0 + 0175a7a commit 31aeb63

File tree

4 files changed

+191
-6
lines changed

4 files changed

+191
-6
lines changed

main/manager-web/src/components/HeaderBar.vue

Lines changed: 185 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,29 @@
6666
<!-- 右侧元素 -->
6767
<div class="header-right">
6868
<div class="search-container" v-if="$route.path === '/home' && !(isSuperAdmin && isSmallScreen)">
69-
<el-input v-model="search" :placeholder="$t('header.searchPlaceholder')" class="custom-search-input"
70-
@keyup.enter.native="handleSearch">
71-
<i slot="suffix" class="el-icon-search search-icon" @click="handleSearch"></i>
72-
</el-input>
69+
<div class="search-wrapper">
70+
<el-input v-model="search" :placeholder="$t('header.searchPlaceholder')" class="custom-search-input"
71+
@keyup.enter.native="handleSearch" @focus="showSearchHistory" @blur="hideSearchHistory" clearable
72+
ref="searchInput">
73+
<i slot="suffix" class="el-icon-search search-icon" @click="handleSearch"></i>
74+
</el-input>
75+
<!-- 搜索历史下拉框 -->
76+
<div v-if="showHistory && searchHistory.length > 0" class="search-history-dropdown">
77+
<div class="search-history-header">
78+
<span>{{ $t('header.searchHistory') }}</span>
79+
<el-button type="text" size="small" class="clear-history-btn" @click="clearSearchHistory">
80+
{{ $t('header.clearHistory') }}
81+
</el-button>
82+
</div>
83+
<div class="search-history-list">
84+
<div v-for="(item, index) in searchHistory" :key="index" class="search-history-item"
85+
@click.stop="selectSearchHistory(item)">
86+
<span class="history-text">{{ item }}</span>
87+
<i class="el-icon-close clear-item-icon" @click.stop="removeSearchHistory(index)"></i>
88+
</div>
89+
</div>
90+
</div>
91+
</div>
7392
</div>
7493

7594
<!-- 语言切换下拉菜单 -->
@@ -99,7 +118,7 @@
99118
</span>
100119
<el-dropdown-menu slot="dropdown">
101120
<el-dropdown-item @click.native="showChangePasswordDialog">{{ $t('header.changePassword')
102-
}}</el-dropdown-item>
121+
}}</el-dropdown-item>
103122
<el-dropdown-item @click.native="handleLogout">{{ $t('header.logout') }}</el-dropdown-item>
104123
</el-dropdown-menu>
105124
</el-dropdown>
@@ -134,7 +153,12 @@ export default {
134153
userDropdownVisible: false,
135154
paramDropdownVisible: false,
136155
languageDropdownVisible: false,
137-
isSmallScreen: false
156+
isSmallScreen: false,
157+
// 搜索历史相关
158+
searchHistory: [],
159+
showHistory: false,
160+
SEARCH_HISTORY_KEY: 'xiaozhi_search_history',
161+
MAX_HISTORY_COUNT: 3
138162
}
139163
},
140164
computed: {
@@ -165,6 +189,8 @@ export default {
165189
this.fetchUserInfo();
166190
this.checkScreenSize();
167191
window.addEventListener('resize', this.checkScreenSize);
192+
// 从localStorage加载搜索历史
193+
this.loadSearchHistory();
168194
},
169195
//移除事件监听器
170196
beforeDestroy() {
@@ -222,6 +248,9 @@ export default {
222248
return;
223249
}
224250
251+
// 保存搜索历史
252+
this.saveSearchHistory(searchValue);
253+
225254
try {
226255
// 创建不区分大小写的正则表达式
227256
const regex = new RegExp(searchValue, 'i');
@@ -234,6 +263,85 @@ export default {
234263
showClose: true
235264
});
236265
}
266+
267+
// 搜索完成后让输入框失去焦点,从而触发blur事件隐藏搜索历史
268+
if (this.$refs.searchInput) {
269+
this.$refs.searchInput.blur();
270+
}
271+
},
272+
273+
// 显示搜索历史
274+
showSearchHistory() {
275+
this.showHistory = true;
276+
},
277+
278+
// 隐藏搜索历史
279+
hideSearchHistory() {
280+
// 延迟隐藏,以便点击事件能够执行
281+
setTimeout(() => {
282+
this.showHistory = false;
283+
}, 200);
284+
},
285+
286+
// 加载搜索历史
287+
loadSearchHistory() {
288+
try {
289+
const history = localStorage.getItem(this.SEARCH_HISTORY_KEY);
290+
if (history) {
291+
this.searchHistory = JSON.parse(history);
292+
}
293+
} catch (error) {
294+
console.error('加载搜索历史失败:', error);
295+
this.searchHistory = [];
296+
}
297+
},
298+
299+
// 保存搜索历史
300+
saveSearchHistory(keyword) {
301+
if (!keyword || this.searchHistory.includes(keyword)) {
302+
return;
303+
}
304+
305+
// 添加到历史记录开头
306+
this.searchHistory.unshift(keyword);
307+
308+
// 限制历史记录数量
309+
if (this.searchHistory.length > this.MAX_HISTORY_COUNT) {
310+
this.searchHistory = this.searchHistory.slice(0, this.MAX_HISTORY_COUNT);
311+
}
312+
313+
// 保存到localStorage
314+
try {
315+
localStorage.setItem(this.SEARCH_HISTORY_KEY, JSON.stringify(this.searchHistory));
316+
} catch (error) {
317+
console.error('保存搜索历史失败:', error);
318+
}
319+
},
320+
321+
// 选择搜索历史项
322+
selectSearchHistory(keyword) {
323+
this.search = keyword;
324+
this.handleSearch();
325+
},
326+
327+
// 移除单个搜索历史项
328+
removeSearchHistory(index) {
329+
this.searchHistory.splice(index, 1);
330+
try {
331+
localStorage.setItem(this.SEARCH_HISTORY_KEY, JSON.stringify(this.searchHistory));
332+
} catch (error) {
333+
console.error('更新搜索历史失败:', error);
334+
}
335+
},
336+
337+
// 清空所有搜索历史
338+
clearSearchHistory() {
339+
this.searchHistory = [];
340+
try {
341+
localStorage.removeItem(this.SEARCH_HISTORY_KEY);
342+
} catch (error) {
343+
console.error('清空搜索历史失败:', error);
344+
}
237345
},
238346
// 显示修改密码弹窗
239347
showChangePasswordDialog() {
@@ -371,6 +479,77 @@ export default {
371479
max-width: none;
372480
}
373481
482+
.search-wrapper {
483+
position: relative;
484+
}
485+
486+
.search-history-dropdown {
487+
position: absolute;
488+
top: 100%;
489+
left: 0;
490+
right: 0;
491+
background: white;
492+
border: 1px solid #e4e6ef;
493+
border-radius: 4px;
494+
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
495+
z-index: 1000;
496+
margin-top: 2px;
497+
}
498+
499+
.search-history-header {
500+
display: flex;
501+
justify-content: space-between;
502+
align-items: center;
503+
padding: 8px 12px;
504+
border-bottom: 1px solid #f0f0f0;
505+
font-size: 12px;
506+
color: #909399;
507+
}
508+
509+
.clear-history-btn {
510+
color: #909399;
511+
font-size: 11px;
512+
padding: 0;
513+
height: auto;
514+
}
515+
516+
.clear-history-btn:hover {
517+
color: #606266;
518+
}
519+
520+
.search-history-list {
521+
max-height: 200px;
522+
overflow-y: auto;
523+
}
524+
525+
.search-history-item {
526+
display: flex;
527+
justify-content: space-between;
528+
align-items: center;
529+
padding: 8px 12px;
530+
cursor: pointer;
531+
font-size: 12px;
532+
color: #606266;
533+
}
534+
535+
.search-history-item:hover {
536+
background-color: #f5f7fa;
537+
}
538+
539+
.clear-item-icon {
540+
font-size: 10px;
541+
color: #909399;
542+
visibility: hidden;
543+
}
544+
545+
.search-history-item:hover .clear-item-icon {
546+
visibility: visible;
547+
}
548+
549+
.clear-item-icon:hover {
550+
color: #ff4949;
551+
}
552+
374553
.custom-search-input>>>.el-input__inner {
375554
height: 18px;
376555
border-radius: 9px;

main/manager-web/src/i18n/en.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export default {
1515
'header.paramManagement': 'Params Management',
1616
'header.dictManagement': 'Dict Management',
1717
'header.agentTemplate': 'Default Role Templates', // 添加这一行
18+
'header.searchHistory': 'Search History',
19+
'header.clearHistory': 'Clear History',
1820

1921
// McpToolCallDialog component text
2022
'mcpToolCall.title': 'Tool Call',

main/manager-web/src/i18n/zh_CN.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export default {
1515
'header.paramManagement': '参数管理',
1616
'header.dictManagement': '字典管理',
1717
'header.agentTemplate': '默认角色模板',
18+
'header.searchHistory': '搜索历史',
19+
'header.clearHistory': '清空历史',
1820

1921
// McpToolCallDialog组件文本
2022
'mcpToolCall.title': '工具调用',

main/manager-web/src/i18n/zh_TW.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export default {
1515
'header.paramManagement': '參數管理',
1616
'header.dictManagement': '字典管理',
1717
'header.agentTemplate': '預設角色模板', // 添加这一行
18+
'header.searchHistory': '搜索歷史',
19+
'header.clearHistory': '清空歷史',
1820

1921
// McpToolCallDialog组件文本
2022
'mcpToolCall.title': '工具調用',

0 commit comments

Comments
 (0)