好的,让我们来实现高级搜索功能,包括按日期范围和特定类别搜索。这将大大提升用户查找特定内容的能力。

第十八部分:实现高级搜索功能

  1. 首先,更新 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 
    });
  });
  1. 更新 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>
<% } %>
  1. 更新 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;
}
  1. 更新主布局文件 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>

这些更改实现了高级搜索功能:

  1. 扩展了搜索路由,支持按关键词、日期范围和类别进行搜索。
  2. 创建了一个新的高级搜索表单,允许用户输入多个搜索条件。
  3. 更新了搜索结果的显示,包括更多的文章信息。
  4. 添加了相应的样式,使高级搜索功能看起来更加美观和易用。

主要改进包括:

  • 用户可以通过关键词、日期范围和特定类别组合搜索文章。
  • 搜索表单提供了更多的过滤选项,提高了搜索的精确度。
  • 搜索结果显示更多相关信息,如作者、发布日期和类别。

这个高级搜索功能大大提高了用户查找特定内容的能力,特别是在博客内容增多时非常有用。

接下来,我们可以考虑添加以下功能:

  1. 用户头像上传
  2. 标签云或热门标签功能
  3. 文章归档功能
  4. 评论系统

你希望继续哪个方向,或者有其他想法吗?