Skip to content

Commit eaa01d9

Browse files
author
Taois
committed
feat:聚合搜索基础版本
1 parent d273e61 commit eaa01d9

File tree

4 files changed

+1788
-40
lines changed

4 files changed

+1788
-40
lines changed

dashboard/src/components/Header.vue

Lines changed: 205 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,57 @@
22
<a-layout-header class="header">
33
<!-- 左侧控制按钮 -->
44
<div class="header-left">
5-
<a-button shape="circle" @click="goBack">
6-
<template #icon>
7-
<icon-left/>
8-
</template>
9-
</a-button>
10-
<a-button shape="circle" @click="goForward">
11-
<template #icon>
12-
<icon-right/>
13-
</template>
14-
</a-button>
15-
<a-button shape="circle" @click="refreshPage">
16-
<template #icon>
17-
<icon-refresh/>
18-
</template>
19-
</a-button>
5+
<!-- 聚合搜索页面模式 -->
6+
<template v-if="isSearchAggregationPage">
7+
<a-button shape="circle" @click="goBackFromSearch">
8+
<template #icon>
9+
<icon-left/>
10+
</template>
11+
</a-button>
12+
<span class="search-page-title">聚合搜索</span>
13+
</template>
14+
<!-- 普通页面模式 -->
15+
<template v-else>
16+
<a-button shape="circle" @click="goBack">
17+
<template #icon>
18+
<icon-left/>
19+
</template>
20+
</a-button>
21+
<a-button shape="circle" @click="goForward">
22+
<template #icon>
23+
<icon-right/>
24+
</template>
25+
</a-button>
26+
<a-button shape="circle" @click="refreshPage">
27+
<template #icon>
28+
<icon-refresh/>
29+
</template>
30+
</a-button>
31+
</template>
2032
</div>
2133

2234
<!-- 中间搜索框 -->
23-
<div class="header-center" v-if="searchAggregationEnabled">
24-
<a-input-search
25-
placeholder="搜索内容..."
26-
enter-button="搜索"
27-
@search="onSearch"
28-
/>
35+
<div class="header-center" :class="{ 'search-page-mode': isSearchAggregationPage }" v-if="searchAggregationEnabled">
36+
<div class="search-container">
37+
<a-input-search
38+
v-model="searchValue"
39+
placeholder="搜索内容..."
40+
enter-button="搜索"
41+
@search="onSearch"
42+
@click="handleSearchClick"
43+
@input="handleSearchInput"
44+
/>
45+
<a-button
46+
class="search-settings-btn"
47+
shape="circle"
48+
@click="openSearchSettings"
49+
:title="'搜索设置'"
50+
>
51+
<template #icon>
52+
<icon-settings/>
53+
</template>
54+
</a-button>
55+
</div>
2956
</div>
3057

3158
<!-- 右侧控制按钮 -->
@@ -68,17 +95,35 @@
6895
</div>
6996
</div>
7097
</div>
98+
99+
<!-- 搜索设置弹窗 -->
100+
<SearchSettingsModal
101+
v-model:visible="showSearchSettings"
102+
@confirm="onSearchSettingsConfirm"
103+
/>
71104
</a-layout-header>
72105
</template>
73106

74107
<script>
75-
import {defineComponent, ref, computed} from 'vue';
108+
import {defineComponent, ref, computed, watch} from 'vue';
109+
import {useRoute, useRouter} from 'vue-router';
76110
import {Message} from '@arco-design/web-vue';
111+
import SearchSettingsModal from './SearchSettingsModal.vue';
77112
78113
export default defineComponent({
79-
components: {},
114+
components: {
115+
SearchSettingsModal
116+
},
80117
setup() {
118+
const route = useRoute();
119+
const router = useRouter();
81120
const showConfirmModal = ref(false);
121+
const searchValue = ref('');
122+
123+
// 检测是否在聚合搜索页面
124+
const isSearchAggregationPage = computed(() => {
125+
return route.name === 'SearchAggregation';
126+
});
82127
83128
// 从localStorage获取聚搜功能状态
84129
const getSearchAggregationStatus = () => {
@@ -108,16 +153,38 @@ export default defineComponent({
108153
// 定期检查状态变化(用于同一页面内的状态更新)
109154
const checkInterval = setInterval(updateSearchAggregationStatus, 1000);
110155
156+
// 监听路由变化,同步搜索关键词
157+
watch(() => route.query.keyword, (keyword) => {
158+
if (keyword && isSearchAggregationPage.value) {
159+
searchValue.value = keyword;
160+
}
161+
}, { immediate: true });
162+
163+
// 监听路由变化,清空搜索框(当离开搜索页面时)
164+
watch(() => route.name, (routeName) => {
165+
if (routeName !== 'SearchAggregation') {
166+
searchValue.value = '';
167+
}
168+
});
169+
111170
return {
112171
showConfirmModal,
113-
searchAggregationEnabled
172+
searchAggregationEnabled,
173+
searchValue,
174+
showSearchSettings: ref(false),
175+
isSearchAggregationPage,
176+
router
114177
};
115178
},
116179
methods: {
117180
goBack() {
118181
Message.info("前进按钮");
119182
// 执行前进逻辑
120183
},
184+
goBackFromSearch() {
185+
// 从聚合搜索页面返回到上一页
186+
this.$router.go(-1);
187+
},
121188
goForward() {
122189
Message.info("后退按钮");
123190
// 执行后退逻辑
@@ -128,8 +195,45 @@ export default defineComponent({
128195
window.location.reload();
129196
},
130197
onSearch(value) {
131-
Message.info(`搜索内容: ${value}`);
132-
// 执行搜索逻辑
198+
if (!value || !value.trim()) {
199+
Message.warning('请输入搜索内容');
200+
return;
201+
}
202+
203+
if (this.isSearchAggregationPage) {
204+
// 如果已经在搜索页面,直接更新查询参数
205+
this.$router.push({
206+
name: 'SearchAggregation',
207+
query: { keyword: value.trim() }
208+
});
209+
} else {
210+
// 如果不在搜索页面,跳转到聚合搜索页面并执行搜索
211+
this.$router.push({
212+
name: 'SearchAggregation',
213+
query: { keyword: value.trim() }
214+
});
215+
}
216+
},
217+
handleSearchClick() {
218+
// 点击搜索框时的处理
219+
if (!this.isSearchAggregationPage) {
220+
// 如果不在搜索页面,跳转到搜索页面
221+
this.$router.push({ name: 'SearchAggregation' });
222+
}
223+
},
224+
handleSearchInput(value) {
225+
// 搜索输入时的处理(可以用于实时搜索建议等)
226+
// 暂时不做特殊处理
227+
},
228+
openSearchSettings() {
229+
// 打开搜索设置弹窗
230+
this.showSearchSettings = true;
231+
},
232+
onSearchSettingsConfirm(settings) {
233+
// 处理搜索设置确认
234+
const selectedCount = settings.selectedSources ? settings.selectedSources.length : 0;
235+
Message.success(`已选择 ${selectedCount} 个搜索源`);
236+
this.showSearchSettings = false;
133237
},
134238
minimize() {
135239
Message.info("最小化窗口");
@@ -226,6 +330,17 @@ export default defineComponent({
226330
gap: 8px;
227331
}
228332
333+
.search-page-title {
334+
font-size: 16px;
335+
font-weight: 600;
336+
color: var(--color-text-1);
337+
margin-left: 12px;
338+
white-space: nowrap;
339+
user-select: none;
340+
display: flex;
341+
align-items: center;
342+
}
343+
229344
.header-center {
230345
flex: 1;
231346
display: flex;
@@ -285,53 +400,103 @@ export default defineComponent({
285400
box-shadow: 0 2px 8px rgba(255, 71, 87, 0.3);
286401
}
287402
288-
/* 搜索框样式 */
289-
.header-center :deep(.arco-input-search) {
403+
/* 搜索容器样式 */
404+
.search-container {
405+
display: flex;
406+
align-items: center;
407+
gap: 8px;
290408
width: 100%;
291-
max-width: 400px;
409+
max-width: 450px;
410+
}
411+
412+
/* 搜索框样式 */
413+
.search-container :deep(.arco-input-search) {
414+
flex: 1;
292415
border-radius: 8px;
293416
background: var(--color-bg-1);
294417
border: 1px solid var(--color-border-2);
295418
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
296419
transition: all 0.2s ease;
420+
cursor: pointer;
297421
}
298422
299-
.header-center :deep(.arco-input-search:hover) {
423+
.search-container :deep(.arco-input-search:hover) {
300424
border-color: var(--color-border-3);
301425
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
302426
}
303427
304-
.header-center :deep(.arco-input-search:focus-within) {
428+
/* 聚合搜索页面时的搜索框样式 */
429+
.header-center.search-page-mode .search-container :deep(.arco-input-search) {
430+
border-radius: 10px;
431+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
432+
}
433+
434+
.header-center.search-page-mode .search-container :deep(.arco-input-search .arco-input-wrapper) {
435+
border: 2px solid var(--color-border-2);
436+
transition: all 0.2s ease;
437+
}
438+
439+
.header-center.search-page-mode .search-container :deep(.arco-input-search .arco-input-wrapper:focus-within) {
440+
border-color: var(--color-primary-6);
441+
box-shadow: 0 0 0 3px rgba(var(--primary-6), 0.1);
442+
}
443+
444+
/* 搜索设置按钮样式 */
445+
.search-settings-btn {
446+
width: 36px !important;
447+
height: 36px !important;
448+
border-radius: 8px !important;
449+
border: 1px solid var(--color-border-2) !important;
450+
background: var(--color-bg-2) !important;
451+
color: var(--color-text-2) !important;
452+
transition: all 0.2s ease !important;
453+
flex-shrink: 0;
454+
}
455+
456+
.search-settings-btn:hover {
457+
background: var(--color-fill-3) !important;
458+
border-color: var(--color-border-3) !important;
459+
color: var(--color-text-1) !important;
460+
transform: translateY(-1px);
461+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
462+
}
463+
464+
.search-settings-btn:active {
465+
transform: translateY(0) !important;
466+
background: var(--color-fill-4) !important;
467+
}
468+
469+
.search-container :deep(.arco-input-search:focus-within) {
305470
border-color: var(--color-primary-6);
306471
box-shadow: 0 0 0 2px var(--color-primary-1);
307472
}
308473
309-
.header-center :deep(.arco-input-wrapper) {
474+
.search-container :deep(.arco-input-wrapper) {
310475
border-radius: 8px;
311476
background: transparent;
312477
border: none;
313478
}
314479
315-
.header-center :deep(.arco-input) {
480+
.search-container :deep(.arco-input) {
316481
background: transparent;
317482
border: none;
318483
color: var(--color-text-1);
319484
font-size: 14px;
320485
}
321486
322-
.header-center :deep(.arco-input::placeholder) {
487+
.search-container :deep(.arco-input::placeholder) {
323488
color: var(--color-text-3);
324489
}
325490
326-
.header-center :deep(.arco-input-search-btn) {
491+
.search-container :deep(.arco-input-search-btn) {
327492
border-radius: 0 8px 8px 0;
328493
background: var(--color-primary-6);
329494
border: none;
330495
color: white;
331496
transition: background-color 0.2s ease;
332497
}
333498
334-
.header-center :deep(.arco-input-search-btn:hover) {
499+
.search-container :deep(.arco-input-search-btn:hover) {
335500
background: var(--color-primary-7);
336501
}
337502
@@ -454,8 +619,8 @@ export default defineComponent({
454619
margin: 0 10px;
455620
}
456621
457-
.header-center :deep(.arco-input-search) {
458-
max-width: 250px;
622+
.search-container {
623+
max-width: 280px;
459624
}
460625
461626
.confirm-modal {
@@ -484,8 +649,8 @@ export default defineComponent({
484649
margin: 0 5px;
485650
}
486651
487-
.header-center :deep(.arco-input-search) {
488-
max-width: 200px;
652+
.search-container {
653+
max-width: 220px;
489654
}
490655
491656
.header-left :deep(.arco-btn),

0 commit comments

Comments
 (0)