热搜功能实现
1. 新增热搜类型定义 HotSearchItem 接口 2. 新增通用响应类型 ApiResponse 和 AxiosResponse 接口 3. 实现热搜列表展示功能 4. 实现搜索历史记录保存和展示功能 5. 优化搜索逻辑,添加搜索后状态更新
This commit is contained in:
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -32,7 +32,7 @@
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[vue]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.defaultFormatter": "Vue.volar",
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"css.validate": false, //用来校验CSS文件中的语法错误和潜在的问题
|
||||
|
||||
5
components.d.ts
vendored
5
components.d.ts
vendored
@@ -33,7 +33,6 @@ declare module 'vue' {
|
||||
RichText: typeof import('./src/components/RichText.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
SimpleLayout: typeof import('./src/components/Layout/SimpleLayout.vue')['default']
|
||||
VanActionSheet: typeof import('vant/es')['ActionSheet']
|
||||
VanButton: typeof import('vant/es')['Button']
|
||||
VanCard: typeof import('vant/es')['Card']
|
||||
@@ -41,11 +40,8 @@ declare module 'vue' {
|
||||
VanCellGroup: typeof import('vant/es')['CellGroup']
|
||||
VanCheckbox: typeof import('vant/es')['Checkbox']
|
||||
VanCheckboxGroup: typeof import('vant/es')['CheckboxGroup']
|
||||
VanCol: typeof import('vant/es')['Col']
|
||||
VanDivider: typeof import('vant/es')['Divider']
|
||||
VanField: typeof import('vant/es')['Field']
|
||||
VanGrid: typeof import('vant/es')['Grid']
|
||||
VanGridItem: typeof import('vant/es')['GridItem']
|
||||
VanIcon: typeof import('vant/es')['Icon']
|
||||
VanList: typeof import('vant/es')['List']
|
||||
VanNavBar: typeof import('vant/es')['NavBar']
|
||||
@@ -54,7 +50,6 @@ declare module 'vue' {
|
||||
VanPopup: typeof import('vant/es')['Popup']
|
||||
VanRadio: typeof import('vant/es')['Radio']
|
||||
VanRadioGroup: typeof import('vant/es')['RadioGroup']
|
||||
VanRow: typeof import('vant/es')['Row']
|
||||
VanSearch: typeof import('vant/es')['Search']
|
||||
VanSpace: typeof import('vant/es')['Space']
|
||||
VanStepper: typeof import('vant/es')['Stepper']
|
||||
|
||||
@@ -75,3 +75,14 @@ export function saveTemplates(sn, data) {
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取推荐列表
|
||||
* @returns { import('src/api/types/response').HotSearchResponse}
|
||||
*/
|
||||
export function hotSearch() {
|
||||
return request({
|
||||
url: `/console/hot_search/list`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
||||
38
src/api/types/hotSearch.d.ts
vendored
Normal file
38
src/api/types/hotSearch.d.ts
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 热搜项类型定义
|
||||
*/
|
||||
export interface HotSearchItem {
|
||||
/** 热搜ID */
|
||||
id: number;
|
||||
/** 热搜序列号 */
|
||||
sn: string;
|
||||
/** 热搜状态 */
|
||||
status: number;
|
||||
/** 创建时间 */
|
||||
created_at: string;
|
||||
/** 更新时间 */
|
||||
updated_at: string;
|
||||
/** 删除时间,为null表示未删除 */
|
||||
deleted_at: null | string;
|
||||
/** 热搜关键词 */
|
||||
key_word: string;
|
||||
/** 显示顺序 */
|
||||
display_order: number;
|
||||
/** 创建用户ID */
|
||||
created_user_id: number;
|
||||
/** 更新用户ID */
|
||||
updated_user_id: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 热搜列表响应类型
|
||||
*/
|
||||
export interface HotSearchListResponse {
|
||||
list: HotSearchItem[];
|
||||
total?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容旧类型
|
||||
*/
|
||||
type HotSearch = HotSearchItem;
|
||||
95
src/api/types/response.d.ts
vendored
Normal file
95
src/api/types/response.d.ts
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
import { HotSearchItem } from './hotSearch';
|
||||
|
||||
/**
|
||||
* 分页元数据接口
|
||||
*/
|
||||
export interface MetaData {
|
||||
/** 起始记录 */
|
||||
from: number;
|
||||
/** 总记录数 */
|
||||
total: number;
|
||||
/** 当前页码 */
|
||||
current_page: number;
|
||||
/** 最后页码 */
|
||||
last_page: number;
|
||||
/** 每页记录数 */
|
||||
per_page: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用API响应接口
|
||||
*/
|
||||
export interface ApiResponse<T> {
|
||||
/** 响应状态码,0表示成功 */
|
||||
code: number;
|
||||
/** 响应消息,成功时为null */
|
||||
message: string | null;
|
||||
/** 响应数据 */
|
||||
data: T;
|
||||
/** 分页元数据,可选 */
|
||||
meta?: MetaData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Axios响应头部接口
|
||||
*/
|
||||
export interface AxiosResponseHeaders {
|
||||
'content-type': string;
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Axios配置接口
|
||||
*/
|
||||
export interface AxiosConfig {
|
||||
transitional: {
|
||||
silentJSONParsing: boolean;
|
||||
forcedJSONParsing: boolean;
|
||||
clarifyTimeoutError: boolean;
|
||||
};
|
||||
adapter: string[];
|
||||
transformRequest: any[];
|
||||
transformResponse: any[];
|
||||
timeout: number;
|
||||
xsrfCookieName: string;
|
||||
xsrfHeaderName: string;
|
||||
maxContentLength: number;
|
||||
maxBodyLength: number;
|
||||
env: Record<string, any>;
|
||||
headers: {
|
||||
Accept: string;
|
||||
'Content-Type': string;
|
||||
Authorization: string;
|
||||
Source: string;
|
||||
remoteIp: string;
|
||||
[key: string]: string;
|
||||
};
|
||||
baseURL: string;
|
||||
url: string;
|
||||
method: string;
|
||||
allowAbsoluteUrls: boolean;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 完整的Axios响应接口
|
||||
*/
|
||||
export interface AxiosResponse<T> {
|
||||
/** 响应数据 */
|
||||
data: ApiResponse<T>;
|
||||
/** HTTP状态码 */
|
||||
status: number;
|
||||
/** HTTP状态文本 */
|
||||
statusText: string;
|
||||
/** 响应头 */
|
||||
headers: AxiosResponseHeaders;
|
||||
/** 请求配置 */
|
||||
config: AxiosConfig;
|
||||
/** 请求对象 */
|
||||
request: Record<string, any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 热搜列表响应类型
|
||||
*/
|
||||
export type HotSearchResponse = AxiosResponse<HotSearchItem[]>;
|
||||
@@ -48,7 +48,7 @@ function useSetPieChart(
|
||||
|
||||
// 检测边界范围 dom 和 data 是否存在
|
||||
onMounted(() => {
|
||||
console.log(dom);
|
||||
// console.log(dom);
|
||||
if (!dom || data.length === 0) return;
|
||||
// 在 dom 挂载之后,显示饼图
|
||||
pieChart.value = chart.init(dom.value);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { nextTick, ref, watch } from 'vue';
|
||||
import { getSurveysPage } from '@/api/home';
|
||||
import { saveSearchHistory } from "@/views/HomeSearch/components/Recommend/hooks/useRecommend"
|
||||
|
||||
// 问卷
|
||||
const surveys = ref([]);
|
||||
@@ -17,7 +18,7 @@ const dirty = ref(true);
|
||||
// loading 状态
|
||||
const loading = ref(false);
|
||||
|
||||
async function handleSearch() {
|
||||
async function handleSearch () {
|
||||
// loading 状态开启
|
||||
// loading.value = true;
|
||||
const params = {
|
||||
@@ -43,21 +44,25 @@ async function handleSearch() {
|
||||
/**
|
||||
* 更新 搜索关键字信息
|
||||
*/
|
||||
async function updateKeyword() {
|
||||
async function updateKeyword () {
|
||||
// 排除边界条件
|
||||
if (!keyword.value) return;
|
||||
|
||||
// 重新获取数据
|
||||
await handleSearch();
|
||||
// 处理后置条件,点击搜索之后,索引更新,
|
||||
// 处理后置条件,点击搜索之后,索引更新,
|
||||
index.value = 1;
|
||||
// 把关键词添加到 localStorage 中
|
||||
saveSearchHistory(keyword.value)
|
||||
// 打开页面展示状态
|
||||
loading.value = true
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
function updatePageCount(value: number) {
|
||||
function updatePageCount (value: number) {
|
||||
pageCount.value = value;
|
||||
}
|
||||
|
||||
@@ -78,3 +83,4 @@ watch(index, async () => {
|
||||
});
|
||||
|
||||
export { keyword, updateKeyword as handleSearch, lastIndex, loading, surveys, index };
|
||||
|
||||
|
||||
@@ -2,9 +2,16 @@
|
||||
import Search from '@/components/Search/Index.vue';
|
||||
import TemplateMarket from '@/views/HomeSearch/components/TemplateMarket/Index.vue';
|
||||
import MineSurvey from '@/views/HomeSearch/components/MineSurvey/Index.vue';
|
||||
import { handleSearch, keyword } from '@/views/HomeSearch/Hooks/useSurveySearch';
|
||||
import { handleSearch, keyword, loading } from '@/views/HomeSearch/Hooks/useSurveySearch';
|
||||
import Layout from '@/components/Layout/CommonLayout.vue';
|
||||
import { visible } from '@/views/HomeSearch/Hooks/useHomeSearch';
|
||||
import RecommendTag from '@/views/HomeSearch/components/Recommend/Index.vue';
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
onMounted(() => {
|
||||
// 当页面取消挂载时,重置页面展示的状态
|
||||
loading.value = false
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -12,24 +19,31 @@ import { visible } from '@/views/HomeSearch/Hooks/useHomeSearch';
|
||||
<search v-model:value="keyword" :search="handleSearch" />
|
||||
<!-- 广告区域 -->
|
||||
|
||||
<!-- 我的问卷区域 -->
|
||||
<layout v-if="visible.mineSurvey" title="我的任务">
|
||||
<template #content>
|
||||
<mine-survey />
|
||||
</template>
|
||||
</layout>
|
||||
<!-- 更多模板区域 -->
|
||||
<layout v-if="visible.templateMarket" title="问卷模板">
|
||||
<template #content>
|
||||
<template-market />
|
||||
</template>
|
||||
</layout>
|
||||
<section v-if="loading">
|
||||
<!-- 我的问卷区域 -->
|
||||
<layout v-if="visible.mineSurvey" title="我的任务">
|
||||
<template #content>
|
||||
<mine-survey />
|
||||
</template>
|
||||
</layout>
|
||||
<!-- 更多模板区域 -->
|
||||
<layout v-if="visible.templateMarket" title="问卷模板">
|
||||
<template #content>
|
||||
<template-market />
|
||||
</template>
|
||||
</layout>
|
||||
</section>
|
||||
|
||||
<section v-else>
|
||||
<recommend-tag></recommend-tag>
|
||||
</section>
|
||||
<!-- <div class="search-result">-->
|
||||
<!-- <div class="search-result-item" v-for="item in searchResult" :key="item.id">-->
|
||||
<!-- {{ item.name }}-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</section>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
36
src/views/HomeSearch/components/Recommend/Index.vue
Normal file
36
src/views/HomeSearch/components/Recommend/Index.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<script setup lang="ts">
|
||||
import Layout from "@/components/Layout/CommonLayout.vue";
|
||||
import { list, useFetchRecommon, history } from "./hooks/useRecommend";
|
||||
|
||||
useFetchRecommon()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="recommend-container">
|
||||
<layout title="热门搜索">
|
||||
<template #content>
|
||||
<el-space>
|
||||
<el-tag v-for="tag in list">{{ tag.key_word }}</el-tag>
|
||||
</el-space>
|
||||
</template>
|
||||
</layout>
|
||||
|
||||
<layout title="搜索历史">
|
||||
<template #content>
|
||||
<el-space>
|
||||
<el-tag v-for="tag in history">{{ tag }}</el-tag>
|
||||
</el-space>
|
||||
</template>
|
||||
</layout>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/assets/css/theme";
|
||||
|
||||
.recommend-container {
|
||||
margin-top: 20px;
|
||||
padding: 0 theme.$card-radius;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,36 @@
|
||||
import { hotSearch } from "@/api/home";
|
||||
import type { HotSearch } from "@/api/types/hotSearch";
|
||||
import { ref } from "vue";
|
||||
|
||||
// 从服务器接受的列表内容
|
||||
const list = ref<HotSearch[]>([])
|
||||
// 历史列表
|
||||
const history = ref<Set<string>>()
|
||||
initialHistory()
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
// 保存历史
|
||||
function saveSearchHistory (val: string) {
|
||||
if (!history.value) {
|
||||
history.value = new Set()
|
||||
}
|
||||
history.value.add(val)
|
||||
localStorage.setItem('history', JSON.stringify(Array.from(history.value)))
|
||||
}
|
||||
|
||||
|
||||
export { useFetchRecommon, list,saveSearchHistory, history }
|
||||
@@ -10,7 +10,7 @@ import postCssPxToRem from 'postcss-pxtorem';
|
||||
import legacy from '@vitejs/plugin-legacy';
|
||||
// shift + alt 快速定位到对应组件
|
||||
import { codeInspectorPlugin } from 'code-inspector-plugin';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
// import tailwindcss from '@tailwindcss/vite';
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
// 接收 mode 参数
|
||||
@@ -77,7 +77,7 @@ export default defineConfig(({ mode }) => {
|
||||
codeInspectorPlugin({
|
||||
bundler: 'vite'
|
||||
}),
|
||||
tailwindcss()
|
||||
// tailwindcss()
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
Reference in New Issue
Block a user