feat: 新增CWD评论系统前后端代码及文档
refactor: 移除旧版评论系统代码并重构为Vue3前端 docs: 更新后端配置文档说明 fix: 修复评论提交频率限制和邮件通知逻辑 style: 格式化代码并优化样式 test: 添加Vitest测试配置 build: 更新依赖项和构建配置 chore: 清理无用文件和缓存
This commit is contained in:
108
cwd-comments-api/src/api/public/getComments.ts
Normal file
108
cwd-comments-api/src/api/public/getComments.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { Context } from 'hono'
|
||||
import { Bindings } from '../../bindings'
|
||||
import { getCravatar } from '../../utils/getAvatar'
|
||||
|
||||
export const getComments = async (c: Context<{ Bindings: Bindings }>) => {
|
||||
const post_slug = c.req.query('post_slug')
|
||||
const page = parseInt(c.req.query('page') || '1')
|
||||
const limit = Math.min(parseInt(c.req.query('limit') || '20'), 50)
|
||||
const nested = c.req.query('nested') !== 'false'
|
||||
const avatar_prefix = c.req.query('avatar_prefix')
|
||||
const offset = (page - 1) * limit
|
||||
|
||||
if (!post_slug) return c.json({ message: "post_slug is required" }, 400)
|
||||
|
||||
try {
|
||||
// 1. 查询审核通过的评论
|
||||
const query = `
|
||||
SELECT id, author, email, url, content_text as contentText,
|
||||
content_html as contentHtml, pub_date as pubDate, parent_id as parentId,
|
||||
post_slug as postSlug
|
||||
FROM Comment
|
||||
WHERE post_slug = ? AND status = "approved"
|
||||
ORDER BY pub_date DESC
|
||||
`
|
||||
const { results } = await c.env.CWD_DB.prepare(query).bind(post_slug).all()
|
||||
|
||||
// 2. 批量处理头像并格式化
|
||||
const allComments = await Promise.all(results.map(async (row: any) => ({
|
||||
...row,
|
||||
avatar: await getCravatar(row.email, avatar_prefix || undefined),
|
||||
replies: []
|
||||
})))
|
||||
|
||||
// 3. 处理嵌套逻辑(扁平化:2级往后的回复都放在根评论的 replies 中)
|
||||
if (nested) {
|
||||
const commentMap = new Map()
|
||||
const rootComments: any[] = []
|
||||
|
||||
// 建立评论映射
|
||||
allComments.forEach(comment => commentMap.set(comment.id, comment))
|
||||
|
||||
// 找出所有根评论
|
||||
allComments.forEach(comment => {
|
||||
if (!comment.parentId) {
|
||||
rootComments.push(comment)
|
||||
}
|
||||
})
|
||||
|
||||
// 为每个非根评论找到其根评论,并添加 replyToAuthor 字段
|
||||
allComments.forEach(comment => {
|
||||
if (comment.parentId) {
|
||||
// 获取直接父评论的作者名
|
||||
const parentComment = commentMap.get(comment.parentId)
|
||||
if (parentComment) {
|
||||
comment.replyToAuthor = parentComment.author
|
||||
}
|
||||
|
||||
// 向上查找根评论
|
||||
let rootId = comment.parentId
|
||||
let current = commentMap.get(rootId)
|
||||
while (current && current.parentId) {
|
||||
rootId = current.parentId
|
||||
current = commentMap.get(rootId)
|
||||
}
|
||||
|
||||
// 将回复添加到根评论的 replies 中
|
||||
const rootComment = commentMap.get(rootId)
|
||||
if (rootComment && !rootComment.parentId) {
|
||||
rootComment.replies.push(comment)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 对每个根评论的 replies 按时间正序排列
|
||||
rootComments.forEach(root => {
|
||||
root.replies.sort((a: any, b: any) =>
|
||||
new Date(a.pubDate).getTime() - new Date(b.pubDate).getTime()
|
||||
)
|
||||
})
|
||||
|
||||
// 对根评论进行分页
|
||||
const paginatedData = rootComments.slice(offset, offset + limit)
|
||||
return c.json({
|
||||
data: paginatedData,
|
||||
pagination: {
|
||||
page,
|
||||
limit,
|
||||
total: Math.ceil(rootComments.length / limit),
|
||||
totalCount: allComments.length,
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 非嵌套逻辑直接分页
|
||||
const paginatedData = allComments.slice(offset, offset + limit)
|
||||
return c.json({
|
||||
data: paginatedData,
|
||||
pagination: {
|
||||
page,
|
||||
limit,
|
||||
total: Math.ceil(allComments.length / limit),
|
||||
totalCount: allComments.length,
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (e: any) {
|
||||
return c.json({ message: e.message }, 500)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user