feat: 优化搜索功能并添加历史记录功能
1. 新增历史记录API模块,支持获取和添加搜索历史 2. 优化搜索组件交互体验 3. 更新搜索推荐功能,支持历史记录展示 4. 修复搜索框焦点控制问题 5. 优化搜索状态管理逻辑
This commit is contained in:
38
src/api/history/index.ts
Normal file
38
src/api/history/index.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 获取历史记录
|
||||
* @returns
|
||||
*/
|
||||
export function fetchHistory() {
|
||||
return request({
|
||||
url: `/console/hot_search_history/list`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加历史记录
|
||||
* @param keyword {string}
|
||||
* @returns
|
||||
*/
|
||||
export function addHistory(keyword: string) {
|
||||
return request({
|
||||
url: `/console/hot_search_history/add`,
|
||||
method: 'post',
|
||||
data: {
|
||||
keyword: keyword
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除所有的历史记录
|
||||
* @returns
|
||||
*/
|
||||
export function clearHistory() {
|
||||
return request({
|
||||
url: `/console/hot_search_history/clear`,
|
||||
method: 'post'
|
||||
});
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<section class="search-container">
|
||||
<van-search
|
||||
v-focus="focus"
|
||||
v-model="value"
|
||||
:placeholder="placeholder"
|
||||
style="--van-search-padding: 0"
|
||||
@@ -12,8 +13,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { vFocus } from '@/utils/directives/useVFocus';
|
||||
|
||||
// 搜索的关键词
|
||||
const value = defineModel<string>('value', { required: true });
|
||||
// focus 是否默认调出键盘
|
||||
const focus = defineModel('focus', { default: false });
|
||||
/**
|
||||
* @description 搜索方法
|
||||
*/
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { Directive } from 'vue';
|
||||
import type { Directive, DirectiveBinding } from 'vue';
|
||||
|
||||
/**
|
||||
* 自定义指令,用于在元素挂载后自动获取焦点
|
||||
*/
|
||||
export const vFocus: Directive = {
|
||||
mounted(el: HTMLInputElement) {
|
||||
el.focus();
|
||||
mounted(el: HTMLInputElement, binding: DirectiveBinding<any, string>) {
|
||||
const value = binding.value;
|
||||
value && el.focus();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { nextTick, ref, watch } from 'vue';
|
||||
import { getSurveysPage } from '@/api/home';
|
||||
import { saveSearchHistory } from '@/views/HomeSearch/components/Recommend/hooks/useRecommend';
|
||||
import { initialHistory, saveSearchHistory } from '@/views/HomeSearch/components/Recommend/hooks/useRecommend';
|
||||
import { getSearchInfo } from '@/api/home/search';
|
||||
|
||||
// 问卷
|
||||
@@ -23,7 +23,7 @@ const templates = ref();
|
||||
// banners
|
||||
const banners = ref();
|
||||
|
||||
async function handleSearch () {
|
||||
async function handleSearch() {
|
||||
// loading 状态开启
|
||||
// loading.value = true;
|
||||
const params = {
|
||||
@@ -54,13 +54,16 @@ async function handleSearch () {
|
||||
/**
|
||||
* 更新 搜索关键字信息
|
||||
*/
|
||||
async function updateKeyword (key?: string) {
|
||||
async function updateKeyword(key?: string) {
|
||||
// 如果 key 存在,则更新关键字
|
||||
if (key) keyword.value = key;
|
||||
|
||||
// 排除边界条件
|
||||
if (!keyword.value) return;
|
||||
|
||||
if (!keyword.value) {
|
||||
initialHistory()
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 重新获取数据
|
||||
await handleSearch();
|
||||
@@ -76,7 +79,7 @@ async function updateKeyword (key?: string) {
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
function updatePageCount (value: number) {
|
||||
function updatePageCount(value: number) {
|
||||
pageCount.value = value;
|
||||
}
|
||||
|
||||
@@ -105,4 +108,4 @@ export {
|
||||
index,
|
||||
templates,
|
||||
banners
|
||||
};
|
||||
};
|
||||
@@ -19,7 +19,7 @@ onMounted(() => {
|
||||
<template>
|
||||
<section class="search-container">
|
||||
<div class="search">
|
||||
<search v-model:value="keyword as string" :search="handleSearch" />
|
||||
<search :focus="true" v-model:value="keyword as string" :search="handleSearch" />
|
||||
</div>
|
||||
<!-- 广告区域 -->
|
||||
<image-slider :banners="banners" v-if="banners?.length" />
|
||||
@@ -27,10 +27,16 @@ onMounted(() => {
|
||||
<section class="result" v-if="loading">
|
||||
<!-- 我的任务区域 -->
|
||||
<layout v-if="visible.mineSurvey" title="我的任务">
|
||||
<template #title>
|
||||
<span class="title">我的任务</span>
|
||||
</template>
|
||||
<mine-survey />
|
||||
</layout>
|
||||
<!-- 更多模板区域 -->
|
||||
<layout v-if="visible.templateMarket" title="问卷模板">
|
||||
<template #title>
|
||||
<span class="title">问卷模板</span>
|
||||
</template>
|
||||
<template-market />
|
||||
</layout>
|
||||
</section>
|
||||
@@ -44,6 +50,18 @@ onMounted(() => {
|
||||
<style scoped lang="scss">
|
||||
@use '@/assets/css/theme';
|
||||
|
||||
.title {
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(0, 0, 0, 1);
|
||||
font-size: 14px;
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 20px;
|
||||
margin: 28px 297px 0 2px;
|
||||
}
|
||||
|
||||
.search-container {
|
||||
.search {
|
||||
padding-top: 10px;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import Layout from '@/components/Layout/CommonLayout.vue';
|
||||
import { list, useFetchRecommon, history } from './hooks/useRecommend';
|
||||
import { list, useFetchRecommon, history, delHistory } from './hooks/useRecommend';
|
||||
import { Delete } from '@element-plus/icons-vue';
|
||||
import { handleSearch } from '../../Hooks/useSurveySearch';
|
||||
|
||||
@@ -10,6 +10,9 @@ useFetchRecommon();
|
||||
<template>
|
||||
<section class="recommend-container">
|
||||
<layout title="热门搜索">
|
||||
<template #title>
|
||||
<el-text class="title">热门搜索</el-text>
|
||||
</template>
|
||||
<el-space>
|
||||
<el-tag style="color: black" color="white" :hit="false" round v-for="tag in list">{{
|
||||
tag.key_word
|
||||
@@ -20,9 +23,9 @@ useFetchRecommon();
|
||||
<layout>
|
||||
<template #title>
|
||||
<section class="history-title">
|
||||
<el-text>历史记录</el-text>
|
||||
<el-text class="title">历史记录</el-text>
|
||||
<div>
|
||||
<el-icon><Delete /></el-icon>
|
||||
<el-icon @click="delHistory"><Delete /></el-icon>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -44,6 +47,15 @@ useFetchRecommon();
|
||||
<style scoped lang="scss">
|
||||
@use '@/assets/css/theme';
|
||||
|
||||
.title {
|
||||
font-size: 25px;
|
||||
font-weight: 800;
|
||||
margin-bottom: 10px;
|
||||
color: rgba(102, 102, 102, 1);
|
||||
font-size: 13px;
|
||||
font-family: PingFangSC;
|
||||
}
|
||||
|
||||
.recommend-container {
|
||||
margin-top: 20px;
|
||||
padding: 0 (theme.$gap * 2);
|
||||
|
||||
@@ -1,36 +1,49 @@
|
||||
import { hotSearch } from "@/api/home";
|
||||
import type { HotSearch } from "@/api/types/hotSearch";
|
||||
import { ref } from "vue";
|
||||
import { addHistory, clearHistory, fetchHistory } from '@/api/history';
|
||||
import { hotSearch } from '@/api/home';
|
||||
import type { HotSearch } from '@/api/types/hotSearch';
|
||||
import { ref } from 'vue';
|
||||
|
||||
// 从服务器接受的列表内容
|
||||
const list = ref<HotSearch[]>([])
|
||||
const list = ref<HotSearch[]>([]);
|
||||
// 历史列表
|
||||
const history = ref<Set<string>>()
|
||||
initialHistory()
|
||||
const history = ref<Set<string>>(new Set());
|
||||
initialHistory();
|
||||
|
||||
async function useFetchRecommon () {
|
||||
const { data } = await hotSearch()
|
||||
list.value = data.data
|
||||
async function useFetchRecommon() {
|
||||
const { data } = await hotSearch();
|
||||
list.value = data.data;
|
||||
}
|
||||
|
||||
// 初始化历史
|
||||
function initialHistory () {
|
||||
const historyStr = localStorage.getItem('history')
|
||||
if (historyStr) {
|
||||
history.value = new Set(JSON.parse(historyStr))
|
||||
} else {
|
||||
history.value = new Set()
|
||||
}
|
||||
async function initialHistory() {
|
||||
// 屏蔽从storage获取记录的方式
|
||||
// const historyStr = localStorage.getItem('history')
|
||||
// if (historyStr) {
|
||||
// history.value = new Set(JSON.parse(historyStr))
|
||||
// } else {
|
||||
// history.value = new Set()
|
||||
// }
|
||||
|
||||
const { data } = await fetchHistory();
|
||||
console.log(data);
|
||||
|
||||
data.data.forEach((item: { id: number; keyword: string }) => {
|
||||
history.value.add(item.keyword);
|
||||
});
|
||||
}
|
||||
|
||||
// 保存历史
|
||||
function saveSearchHistory (val: string) {
|
||||
if (!history.value) {
|
||||
history.value = new Set()
|
||||
}
|
||||
history.value.add(val)
|
||||
localStorage.setItem('history', JSON.stringify(Array.from(history.value)))
|
||||
async function saveSearchHistory(val: string) {
|
||||
// 屏蔽从storage获取记录的方式
|
||||
// if (!history.value) {
|
||||
// history.value = new Set();
|
||||
// }
|
||||
// history.value.add(val);
|
||||
// localStorage.setItem('history', JSON.stringify(Array.from(history.value)));
|
||||
addHistory(val);
|
||||
}
|
||||
|
||||
|
||||
export { useFetchRecommon, list,saveSearchHistory, history }
|
||||
async function delHistory() {
|
||||
await clearHistory();
|
||||
}
|
||||
export { useFetchRecommon, list, saveSearchHistory, history, delHistory,initialHistory };
|
||||
|
||||
Reference in New Issue
Block a user