Fuse搜索工具
import Fuse from 'fuse.js'
import type {IFuseOptions} from "fuse.js";
export default function useFuse<T>(list: T[], options: IFuseOptions<T>) {
const fuse = new Fuse<T>(list, options)
function search(keyword: string, limit: number = Infinity): T[] {
if (!keyword) return list
const results = fuse.search(keyword, {limit})
return results.map(r => r.item)
}
/**
* fuseSearch - 单次模糊搜索工具函数
*
* @param list 数据源
* @param keyword 搜索关键词
* @param options Fuse.js 配置
* @param limit 限制返回数量,默认 Infinity
*/
function fuseSearch<T>(
list: T[],
keyword: string,
options: IFuseOptions<T>,
limit: number = Infinity
): T[] {
if (!keyword) return list
const fuse = new Fuse<T>(list, options)
const results = fuse.search(keyword, {limit})
return results.map(r => r.item)
}
return {search, fuseSearch}
}
import { defineEventHandler } from 'h3'
import { db } from '~~/server/utils/db'
function capitalize(str: string): string {
if (!str) return ''
return str.charAt(0).toUpperCase() + str.slice(1)
}
interface BlogItem {
id: number
title: string
summary: string
subCategory: string
author: string
category: string
}
interface SubCategoryGroup {
subCategory: string
list: BlogItem[]
}
interface CategoryGroup {
category: string
subCategories: SubCategoryGroup[]
}
export default defineWrappedResponseHandler(
defineEventHandler(async () => {
type DbRow = {
id: number
title: string
author: string
tags: string
summary: string
sub_category: string
category: string
}
const blogs: DbRow[] = await db('blog_posts as b')
.select(
'b.id',
'b.title',
'b.author',
'b.tags',
'b.summary',
'b.sub_category',
'b.category'
)
.where('b.is_published', 1)
const temp: Record<string, Record<string, BlogItem[]>> = {}
for (const row of blogs) {
const category = row.category || '未分类'
const sub = capitalize(row.sub_category || '未分组')
if (!temp[category]) temp[category] = {}
if (!temp[category][sub]) temp[category][sub] = []
temp[category][sub].push({
id: row.id,
title: row.title,
summary: row.summary,
subCategory: sub,
author: row.author,
category: category
})
}
// 排序 + 转换成数组结构
const result: CategoryGroup[] = Object.entries(temp).map(
([category, subMap]) => {
const subCategories: SubCategoryGroup[] = Object.entries(subMap).map(
([subCategory, list]) => ({
subCategory,
list: list.sort((a, b) =>
a.title.localeCompare(b.title, 'zh-CN', { sensitivity: 'base' })
)
})
)
return {
category,
subCategories
}
}
)
return result
})
)
import {defineEventHandler} from 'h3'
import {db} from '~~/server/utils/db'
function capitalize(str: string): string {
if (!str) return ''
return str.charAt(0).toUpperCase() + str.slice(1)
}
export default defineWrappedResponseHandler(defineEventHandler(async (event) => {
const query = getQuery(event) // 从 URL 获取参数,比如 ?category=tech
const category = query.category as string
const blogs = await db('blog_posts as b')
.select('b.id', 'b.title', 'b.author', 'b.tags', 'b.summary', 'b.sub_category')
.where('b.category', category).andWhere('b.is_published', 1)
const grouped: Record<string, {
id: number;
title: string,
summary: string,
sub_category: string,
author: string
}[]> = {}
for (const row of blogs) {
const tag = capitalize(row.tags)
if (!grouped[tag]) {
grouped[tag] = []
}
grouped[tag].push({
id: row.id,
title: row.title,
summary: row.summary,
sub_category: row.sub_category,
author: row.author
})
}
// 对每个 tag 下的数组按 title 排序
for (const tag in grouped) {
grouped[tag].sort((a, b) => a.title.localeCompare(b.title, 'zh-CN'))
}
return grouped;
}))
// api/blog/star.post.ts
// http POST http://localhost:3000/api/star id:=1 action=inc
export default defineWrappedResponseHandler(
defineEventHandler(async (event) => {
const body = await readBody<{ id: number; action: 'inc' | 'dec' }>(event)
if (!body.id) {
throw new Error('缺少参数 id')
}
if (!['inc', 'dec'].includes(body.action)) {
throw new Error('action 必须是 inc 或 dec')
}
// 更新 SQL
const query = db('blog_posts').where('id', body.id)
if (body.action === 'inc') {
await query.increment('star', 1)
} else {
await query.decrement('star', 1)
}
// 返回最新 star 数
const updated = await db('blog_posts')
.select('id', 'title', 'star')
.where('id', body.id)
.first()
return updated
})
)
想法或问题?在 GitHub Issue 下方参与讨论
去评论