feat:增加博客搜索模块

This commit is contained in:
2025-09-25 17:31:57 +08:00
parent 98918eb9b6
commit 4972f1dd53
6 changed files with 146 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
import { cloudService } from './index'
import { IBlog, IBlogCategory, IBlogComment, IBlogStats, IQueryBlog } from '@/types/blog'
import { IBlog, IBlogCategory, IBlogComment, IBlogSearch, IBlogStats, IQueryBlog } from '@/types/blog'
import qs from 'qs'
import { IPageRecord } from '@/types'
@@ -11,6 +11,13 @@ export const queryBlogApi = (currentPage: number, pageSize: number): Promise<IPa
params: { currentPage, pageSize }
})
export const searchBlogApi = (keyword: string): Promise<IBlogSearch[]> =>
cloudService({
url: '/blog-api/blog/search',
method: 'get',
params: { keyword }
})
export const queryBlogByConditionApi = (query: IQueryBlog): Promise<IBlog[]> =>
cloudService({
url: '/blog-api/blog/condition',

View File

@@ -17,7 +17,7 @@
<span class="value">{{ blogStore.blogStats.blogCount }}</span>
</el-menu-item>
<el-menu-item>
<el-menu-item index="/search">
<i class="fa fa-search fa-fw" />
<span class="menu-title">搜索</span>
</el-menu-item>

View File

@@ -12,7 +12,7 @@ const blogRoutes: RouteRecordRaw[] = [
component: () => import('@/views/overview.vue')
},
{
path: '/overview/detail:id',
path: '/overview/detail/:id',
name: 'DetailId',
component: () => import('@/views/detail[id].vue')
}
@@ -28,7 +28,7 @@ const blogRoutes: RouteRecordRaw[] = [
component: () => import('@/views/category.vue')
},
{
path: '/category:name',
path: '/category/:name',
name: 'CategoryName',
component: () => import('@/views/category[name].vue')
}
@@ -44,6 +44,17 @@ const blogRoutes: RouteRecordRaw[] = [
component: () => import('@/views/archive.vue')
}
]
},
{
path: '/search',
redirect: '/search/index',
component: BlogLayout,
children: [
{
path: '/search/index',
component: () => import('@/views/search.vue')
}
]
}
]

View File

@@ -1,12 +1,12 @@
import { defineStore } from 'pinia'
import {
IBlog, IBlogCategory, IBlogComment,
IBlogLatest, IBlogNestedComment, IBlogStats, INewBlog, IQueryBlog
IBlogLatest, IBlogNestedComment, IBlogSearch, IBlogStats, INewBlog, IQueryBlog
} from '@/types/blog'
import {
addBlogCommentApi,
queryBlogApi, queryBlogByConditionApi, queryBlogByIdApi,
queryBlogCategoryApi, queryBlogCommentApi, queryBlogStatsApi, queryLatestBlogApi
queryBlogCategoryApi, queryBlogCommentApi, queryBlogStatsApi, queryLatestBlogApi, searchBlogApi
} from '@/apis/blog.ts'
import { IHandleApi } from 'vue3-common/types'
import { ImagePathEnum } from '@/types'
@@ -17,6 +17,7 @@ export const useBlogStore = defineStore('blog', {
blogList: [] as IBlog[],
blogCommentList: [] as IBlogComment[],
blogNestedCommentList: [] as IBlogNestedComment[],
searchBlogList: [] as IBlogSearch[],
currentBlogComment: {
id: 0,
blogId: 0,
@@ -50,6 +51,8 @@ export const useBlogStore = defineStore('blog', {
blogStats: {} as IBlogStats,
latestBlogList: [] as IBlogLatest[],
queryBlog: {} as IQueryBlog,
searchBlogKeyword: '',
isSearching: false,
blogImagePath: ImagePathEnum.BLOG,
blogApiType: 'ADD' as IHandleApi,
pageInfo: {
@@ -83,6 +86,11 @@ export const useBlogStore = defineStore('blog', {
async queryBlogComment(blogId: number) {
this.blogCommentList = await queryBlogCommentApi(blogId)
},
async searchBlog(keyword: string) {
this.isSearching = true
this.searchBlogList = await searchBlogApi(keyword)
this.isSearching = false
},
async addBlogComment(blogComment: IBlogComment) {
await addBlogCommentApi(blogComment)
await this.queryBlogById(blogComment.blogId)

View File

@@ -82,3 +82,10 @@ export interface IBlogNestedComment {
comment: IBlogComment;
replies: IBlogComment[];
}
export interface IBlogSearch {
id: number;
title: string;
content: string;
highlight: string;
}

107
src/views/search.vue Normal file
View File

@@ -0,0 +1,107 @@
<template>
<div class="blog-search blog-section card-item">
<el-input
v-model="blogStore.searchBlogKeyword"
@input="searchBlogClick"
clearable
placeholder="搜索博客文章..."
/>
<div v-if="blogStore.searchBlogList.length > 0"
v-loading="blogStore.isSearching"
element-loading-text="正在搜索中..."
class="blog-results">
<h3 class="results-title">找到 {{ blogStore.searchBlogList.length }} 篇相关博客</h3>
<div v-for="(blog, index) in blogStore.searchBlogList"
:key="index" class="blog-card card-item">
<h4 class="blog-title">{{ blog.title }}</h4>
<div class="blog-excerpt" v-html="blog.highlight" />
<router-link :to="`/overview/detail/${blog.id}`" class="read-more">阅读全文</router-link>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useBlogStore } from '@/store/blog'
import { onMounted } from 'vue'
const blogStore = useBlogStore()
onMounted(() => {
blogStore.searchBlogKeyword = ''
blogStore.searchBlogList = []
})
const searchBlogClick = async (value: string) => {
if (!value) {
blogStore.searchBlogList = []
return
}
await blogStore.searchBlog(value)
}
</script>
<style lang="scss">
.blog-search {
padding: 20px;
.search-box {
display: flex;
gap: 10px;
}
.blog-results {
display: flex;
flex-direction: column;
gap: 10px;
.results-title {
color: #333;
margin-bottom: 25px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.blog-card {
padding: 20px;
display: flex;
flex-direction: column;
gap: 10px;
.blog-title {
color: #2c3e50;
margin: 0 0 10px 0;
font-size: 1.4rem;
}
.blog-excerpt {
color: #34495e;
line-height: 1.6;
}
.read-more {
display: inline-block;
color: #009FA8;
text-decoration: none;
font-weight: 500;
transition: color 0.3s;
}
.read-more:hover {
color: #009FA8;
text-decoration: underline;
}
}
.blog-card:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
cursor: pointer;
}
}
}
</style>