好的,让我们来实现高级搜索功能,包括按日期范围和特定类别搜索。这将大大提升用户查找特定内容的能力。
第十八部分:实现高级搜索功能
- 首先,更新
src/routes/search.ts文件,添加高级搜索逻辑:
import { Elysia } from "elysia";
import { db } from "../db";
import { posts, users, categories, postCategories } from "../db/schema";
import { eq, like, or, and, between, inArray } from "drizzle-orm";
export const searchRoutes = new Elysia()
.get("/search", async ({ query, render }) => {
const { q, startDate, endDate, categoryIds } = query;
let conditions = [];
if (q) {
conditions.push(
or(
like(posts.title, `%${q}%`),
like(posts.content, `%${q}%`),
like(users.username, `%${q}%`)
)
);
}
if (startDate && endDate) {
conditions.push(between(posts.createdAt, new Date(startDate), new Date(endDate)));
}
if (categoryIds) {
const categoryIdArray = Array.isArray(categoryIds) ? categoryIds : [categoryIds];
conditions.push(inArray(postCategories.categoryId, categoryIdArray));
}
const searchResults = await db
.select({
id: posts.id,
title: posts.title,
content: posts.content,
createdAt: posts.createdAt,
author: users.username,
categories: categories.name,
})
.from(posts)
.leftJoin(users, eq(posts.authorId, users.id))
.leftJoin(postCategories, eq(posts.id, postCategories.postId))
.leftJoin(categories, eq(postCategories.categoryId, categories.id))
.where(and(...conditions))
.all();
// 对结果进行处理,合并相同文章的类别
const processedResults = searchResults.reduce((acc, curr) => {
const existingPost = acc.find(post => post.id === curr.id);
if (existingPost) {
if (curr.categories && !existingPost.categories.includes(curr.categories)) {
existingPost.categories.push(curr.categories);
}
} else {
acc.push({
...curr,
categories: curr.categories ? [curr.categories] : []
});
}
return acc;
}, []);
// 获取所有类别,用于搜索表单
const allCategories = await db.select().from(categories).all();
return render("search", {
posts: processedResults,
query: q,
startDate,
endDate,
selectedCategoryIds: categoryIds ? (Array.isArray(categoryIds) ? categoryIds : [categoryIds]) : [],
allCategories
});
});- 更新
src/views/search.eta文件,添加高级搜索表单:
<% layout('./layouts/main.eta', { title: 'Advanced Search' }) %>
<h1>Advanced Search</h1>
<form action="/search" method="GET">
<div>
<label for="q">Keywords:</label>
<input type="text" id="q" name="q" value="<%= it.query %>">
</div>
<div>
<label for="startDate">Start Date:</label>
<input type="date" id="startDate" name="startDate" value="<%= it.startDate %>">
</div>
<div>
<label for="endDate">End Date:</label>
<input type="date" id="endDate" name="endDate" value="<%= it.endDate %>">
</div>
<div>
<label>Categories:</label>
<% it.allCategories.forEach(category => { %>
<label>
<input type="checkbox" name="categoryIds" value="<%= category.id %>"
<%= it.selectedCategoryIds.includes(category.id.toString()) ? 'checked' : '' %>>
<%= category.name %>
</label>
<% }) %>
</div>
<button type="submit">Search</button>
</form>
<% if (it.posts.length > 0) { %>
<h2>Search Results</h2>
<ul class="search-results">
<% it.posts.forEach(post => { %>
<li>
<h3><a href="/posts/<%= post.id %>"><%= post.title %></a></h3>
<p>By <%= post.author %> on <%= new Date(post.createdAt).toLocaleDateString() %></p>
<% if (post.categories && post.categories.length > 0) { %>
<p>Categories: <%= post.categories.join(', ') %></p>
<% } %>
<p><%= post.content.substring(0, 200) %>...</p>
</li>
<% }) %>
</ul>
<% } else if (it.query || it.startDate || it.endDate || it.selectedCategoryIds.length > 0) { %>
<p>No results found for your search criteria.</p>
<% } %>- 更新
public/styles/main.css文件,添加一些高级搜索相关的样式:
/* ... 前面的样式保持不变 */
.advanced-search-form {
margin-bottom: 20px;
}
.advanced-search-form div {
margin-bottom: 10px;
}
.advanced-search-form label {
display: inline-block;
width: 100px;
}
.advanced-search-form input[type="text"],
.advanced-search-form input[type="date"] {
width: 200px;
padding: 5px;
}
.advanced-search-form .categories-group {
display: flex;
flex-wrap: wrap;
}
.advanced-search-form .categories-group label {
width: auto;
margin-right: 15px;
}
.search-results li {
margin-bottom: 20px;
border-bottom: 1px solid #ddd;
padding-bottom: 10px;
}
.search-results h3 {
margin-bottom: 5px;
}
.search-results p {
margin: 5px 0;
}- 更新主布局文件
src/views/layouts/main.eta,将搜索链接改为高级搜索:
<header>
<nav>
<a href="/">Home</a>
<a href="/posts/new">New Post</a>
<% if (it.user) { %>
<a href="/logout">Logout</a>
<% } else { %>
<a href="/login">Login</a>
<a href="/register">Register</a>
<% } %>
<a href="/search">Advanced Search</a>
</nav>
</header>这些更改实现了高级搜索功能:
- 扩展了搜索路由,支持按关键词、日期范围和类别进行搜索。
- 创建了一个新的高级搜索表单,允许用户输入多个搜索条件。
- 更新了搜索结果的显示,包括更多的文章信息。
- 添加了相应的样式,使高级搜索功能看起来更加美观和易用。
主要改进包括:
- 用户可以通过关键词、日期范围和特定类别组合搜索文章。
- 搜索表单提供了更多的过滤选项,提高了搜索的精确度。
- 搜索结果显示更多相关信息,如作者、发布日期和类别。
这个高级搜索功能大大提高了用户查找特定内容的能力,特别是在博客内容增多时非常有用。
接下来,我们可以考虑添加以下功能:
- 用户头像上传
- 标签云或热门标签功能
- 文章归档功能
- 评论系统
你希望继续哪个方向,或者有其他想法吗?