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>
|
<template>
|
||||||
<section class="search-container">
|
<section class="search-container">
|
||||||
<van-search
|
<van-search
|
||||||
|
v-focus="focus"
|
||||||
v-model="value"
|
v-model="value"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
style="--van-search-padding: 0"
|
style="--van-search-padding: 0"
|
||||||
@@ -12,8 +13,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { vFocus } from '@/utils/directives/useVFocus';
|
||||||
|
|
||||||
// 搜索的关键词
|
// 搜索的关键词
|
||||||
const value = defineModel<string>('value', { required: true });
|
const value = defineModel<string>('value', { required: true });
|
||||||
|
// focus 是否默认调出键盘
|
||||||
|
const focus = defineModel('focus', { default: false });
|
||||||
/**
|
/**
|
||||||
* @description 搜索方法
|
* @description 搜索方法
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import type { Directive } from 'vue';
|
import type { Directive, DirectiveBinding } from 'vue';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义指令,用于在元素挂载后自动获取焦点
|
* 自定义指令,用于在元素挂载后自动获取焦点
|
||||||
*/
|
*/
|
||||||
export const vFocus: Directive = {
|
export const vFocus: Directive = {
|
||||||
mounted(el: HTMLInputElement) {
|
mounted(el: HTMLInputElement, binding: DirectiveBinding<any, string>) {
|
||||||
el.focus();
|
const value = binding.value;
|
||||||
|
value && el.focus();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { nextTick, ref, watch } from 'vue';
|
import { nextTick, ref, watch } from 'vue';
|
||||||
import { getSurveysPage } from '@/api/home';
|
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';
|
import { getSearchInfo } from '@/api/home/search';
|
||||||
|
|
||||||
// 问卷
|
// 问卷
|
||||||
@@ -23,7 +23,7 @@ const templates = ref();
|
|||||||
// banners
|
// banners
|
||||||
const banners = ref();
|
const banners = ref();
|
||||||
|
|
||||||
async function handleSearch () {
|
async function handleSearch() {
|
||||||
// loading 状态开启
|
// loading 状态开启
|
||||||
// loading.value = true;
|
// loading.value = true;
|
||||||
const params = {
|
const params = {
|
||||||
@@ -54,13 +54,16 @@ async function handleSearch () {
|
|||||||
/**
|
/**
|
||||||
* 更新 搜索关键字信息
|
* 更新 搜索关键字信息
|
||||||
*/
|
*/
|
||||||
async function updateKeyword (key?: string) {
|
async function updateKeyword(key?: string) {
|
||||||
// 如果 key 存在,则更新关键字
|
// 如果 key 存在,则更新关键字
|
||||||
if (key) keyword.value = key;
|
if (key) keyword.value = key;
|
||||||
|
|
||||||
// 排除边界条件
|
// 排除边界条件
|
||||||
if (!keyword.value) return;
|
if (!keyword.value) {
|
||||||
|
initialHistory()
|
||||||
|
loading.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 重新获取数据
|
// 重新获取数据
|
||||||
await handleSearch();
|
await handleSearch();
|
||||||
@@ -76,7 +79,7 @@ async function updateKeyword (key?: string) {
|
|||||||
*
|
*
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
function updatePageCount (value: number) {
|
function updatePageCount(value: number) {
|
||||||
pageCount.value = value;
|
pageCount.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ onMounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<section class="search-container">
|
<section class="search-container">
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<search v-model:value="keyword as string" :search="handleSearch" />
|
<search :focus="true" v-model:value="keyword as string" :search="handleSearch" />
|
||||||
</div>
|
</div>
|
||||||
<!-- 广告区域 -->
|
<!-- 广告区域 -->
|
||||||
<image-slider :banners="banners" v-if="banners?.length" />
|
<image-slider :banners="banners" v-if="banners?.length" />
|
||||||
@@ -27,10 +27,16 @@ onMounted(() => {
|
|||||||
<section class="result" v-if="loading">
|
<section class="result" v-if="loading">
|
||||||
<!-- 我的任务区域 -->
|
<!-- 我的任务区域 -->
|
||||||
<layout v-if="visible.mineSurvey" title="我的任务">
|
<layout v-if="visible.mineSurvey" title="我的任务">
|
||||||
|
<template #title>
|
||||||
|
<span class="title">我的任务</span>
|
||||||
|
</template>
|
||||||
<mine-survey />
|
<mine-survey />
|
||||||
</layout>
|
</layout>
|
||||||
<!-- 更多模板区域 -->
|
<!-- 更多模板区域 -->
|
||||||
<layout v-if="visible.templateMarket" title="问卷模板">
|
<layout v-if="visible.templateMarket" title="问卷模板">
|
||||||
|
<template #title>
|
||||||
|
<span class="title">问卷模板</span>
|
||||||
|
</template>
|
||||||
<template-market />
|
<template-market />
|
||||||
</layout>
|
</layout>
|
||||||
</section>
|
</section>
|
||||||
@@ -44,6 +50,18 @@ onMounted(() => {
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@use '@/assets/css/theme';
|
@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-container {
|
||||||
.search {
|
.search {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Layout from '@/components/Layout/CommonLayout.vue';
|
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 { Delete } from '@element-plus/icons-vue';
|
||||||
import { handleSearch } from '../../Hooks/useSurveySearch';
|
import { handleSearch } from '../../Hooks/useSurveySearch';
|
||||||
|
|
||||||
@@ -10,6 +10,9 @@ useFetchRecommon();
|
|||||||
<template>
|
<template>
|
||||||
<section class="recommend-container">
|
<section class="recommend-container">
|
||||||
<layout title="热门搜索">
|
<layout title="热门搜索">
|
||||||
|
<template #title>
|
||||||
|
<el-text class="title">热门搜索</el-text>
|
||||||
|
</template>
|
||||||
<el-space>
|
<el-space>
|
||||||
<el-tag style="color: black" color="white" :hit="false" round v-for="tag in list">{{
|
<el-tag style="color: black" color="white" :hit="false" round v-for="tag in list">{{
|
||||||
tag.key_word
|
tag.key_word
|
||||||
@@ -20,9 +23,9 @@ useFetchRecommon();
|
|||||||
<layout>
|
<layout>
|
||||||
<template #title>
|
<template #title>
|
||||||
<section class="history-title">
|
<section class="history-title">
|
||||||
<el-text>历史记录</el-text>
|
<el-text class="title">历史记录</el-text>
|
||||||
<div>
|
<div>
|
||||||
<el-icon><Delete /></el-icon>
|
<el-icon @click="delHistory"><Delete /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
@@ -44,6 +47,15 @@ useFetchRecommon();
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@use '@/assets/css/theme';
|
@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 {
|
.recommend-container {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
padding: 0 (theme.$gap * 2);
|
padding: 0 (theme.$gap * 2);
|
||||||
|
|||||||
@@ -1,36 +1,49 @@
|
|||||||
import { hotSearch } from "@/api/home";
|
import { addHistory, clearHistory, fetchHistory } from '@/api/history';
|
||||||
import type { HotSearch } from "@/api/types/hotSearch";
|
import { hotSearch } from '@/api/home';
|
||||||
import { ref } from "vue";
|
import type { HotSearch } from '@/api/types/hotSearch';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
// 从服务器接受的列表内容
|
// 从服务器接受的列表内容
|
||||||
const list = ref<HotSearch[]>([])
|
const list = ref<HotSearch[]>([]);
|
||||||
// 历史列表
|
// 历史列表
|
||||||
const history = ref<Set<string>>()
|
const history = ref<Set<string>>(new Set());
|
||||||
initialHistory()
|
initialHistory();
|
||||||
|
|
||||||
async function useFetchRecommon () {
|
async function useFetchRecommon() {
|
||||||
const { data } = await hotSearch()
|
const { data } = await hotSearch();
|
||||||
list.value = data.data
|
list.value = data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化历史
|
// 初始化历史
|
||||||
function initialHistory () {
|
async function initialHistory() {
|
||||||
const historyStr = localStorage.getItem('history')
|
// 屏蔽从storage获取记录的方式
|
||||||
if (historyStr) {
|
// const historyStr = localStorage.getItem('history')
|
||||||
history.value = new Set(JSON.parse(historyStr))
|
// if (historyStr) {
|
||||||
} else {
|
// history.value = new Set(JSON.parse(historyStr))
|
||||||
history.value = new Set()
|
// } 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) {
|
async function saveSearchHistory(val: string) {
|
||||||
if (!history.value) {
|
// 屏蔽从storage获取记录的方式
|
||||||
history.value = new Set()
|
// if (!history.value) {
|
||||||
}
|
// history.value = new Set();
|
||||||
history.value.add(val)
|
// }
|
||||||
localStorage.setItem('history', JSON.stringify(Array.from(history.value)))
|
// history.value.add(val);
|
||||||
|
// localStorage.setItem('history', JSON.stringify(Array.from(history.value)));
|
||||||
|
addHistory(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function delHistory() {
|
||||||
export { useFetchRecommon, list,saveSearchHistory, history }
|
await clearHistory();
|
||||||
|
}
|
||||||
|
export { useFetchRecommon, list, saveSearchHistory, history, delHistory,initialHistory };
|
||||||
|
|||||||
Reference in New Issue
Block a user