", err.Error())
return
}
// 如果是 AJAX 请求,直接返回 JSON 数据
if r.Header.Get("X-Requested-With") == "XMLHttpRequest" {
respondJSON(w, http.StatusOK, map[string]interface{}{
"code": 0,
"data": data,
})
return
}
// 生成完整 HTML 页面(仅首次加载)
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusOK)
html := generateReviewHTML(data, params["item_id"], bookID, para, page, pageSize, sort)
fmt.Fprint(w, html)
}
// 在 init 函数中初始化表情管理器
func init() {
// 初始化表情管理器
em := fqapi.GetEmojiManager()
em.LoadEmojis()
}
// replaceEmojiWithImages 将表情文本替换为图片标签
func replaceEmojiWithImages(text string) string {
return fqapi.ReplaceEmojisInText(text)
}
// parseCommentData 解析评论数据的通用函数
type CommentInfo struct {
UserName string
UserAvatar string
IsAuthor bool
StickerImageURL string
CreateTime string
CommentText string
CommentID string
DiggCount int
ReplyCount int
ImageURL string
ImageLargeURL string
}
func parseCommentData(comment map[string]interface{}) CommentInfo {
info := CommentInfo{
UserName: "匿名用户",
}
// 提取 comment_id
if cid, ok := comment["comment_id"].(string); ok {
info.CommentID = cid
}
// 用户信息
if userInfo, ok := comment["user_info"].(map[string]interface{}); ok {
if name, ok := userInfo["user_name"].(string); ok {
info.UserName = name
}
if avatar, ok := userInfo["user_avatar"].(string); ok {
info.UserAvatar = avatar
}
if author, ok := userInfo["is_author"].(bool); ok {
info.IsAuthor = author
}
}
// 创建时间
if timestamp, ok := comment["create_timestamp"].(float64); ok {
t := time.Unix(int64(timestamp), 0)
info.CreateTime = t.Format("2006-01-02 15:04")
}
// 评论内容
if text, ok := comment["text"].(string); ok {
info.CommentText = text
}
// 提取图片
if imageData, ok := comment["image_data"].([]interface{}); ok && len(imageData) > 0 {
if imgMap, ok := imageData[0].(map[string]interface{}); ok {
if url, ok := imgMap["web_uri"].(string); ok && url != "" {
info.ImageURL = url
}
if largeURL, ok := imgMap["expand_web_url"].(string); ok && largeURL != "" {
info.ImageLargeURL = largeURL
} else {
info.ImageLargeURL = info.ImageURL
}
}
}
// 统计信息
if count, ok := comment["digg_count"].(float64); ok {
info.DiggCount = int(count)
} else if count, ok := comment["digg_count"].(int); ok {
info.DiggCount = count
}
// 回复数量
if replyCountVal, ok := comment["reply_count"].(float64); ok {
info.ReplyCount = int(replyCountVal)
} else if replyCountVal, ok := comment["reply_count"].(int); ok {
info.ReplyCount = replyCountVal
} else if replyCnt, ok := comment["reply_cnt"].(float64); ok {
info.ReplyCount = int(replyCnt)
} else if replyCnt, ok := comment["reply_cnt"].(int); ok {
info.ReplyCount = replyCnt
}
return info
}
// generateReviewHTML 生成评论 HTML 页面
func generateReviewHTML(data map[string]interface{}, itemID, bookID string, para, page, pageSize, sort int) string {
var html strings.Builder
html.WriteString(`
番茄段评 · 第 `)
html.WriteString(strconv.Itoa(para + 1))
html.WriteString(` 段
段落评论 · `)
// 提取评论总数和是否有更多
total := 0
hasMore := false
nextOffset := 0
// 新接口返回 count 字段表示总数
if countVal, ok := data["count"].(float64); ok {
total = int(countVal)
} else if countVal, ok := data["count"].(int); ok {
total = countVal
}
// 检查是否有更多数据
if hasMoreVal, ok := data["has_more"].(bool); ok {
hasMore = hasMoreVal
} else if hasMoreVal, ok := data["has_more"].(float64); ok {
hasMore = hasMoreVal > 0
} else if hasMoreVal, ok := data["has_more"].(int); ok {
hasMore = hasMoreVal > 0
}
// 获取下一页的 offset
if nextOffsetVal, ok := data["next_offset"].(float64); ok {
nextOffset = int(nextOffsetVal)
} else if nextOffsetVal, ok := data["next_offset"].(int); ok {
nextOffset = nextOffsetVal
}
html.WriteString(strconv.Itoa(total))
html.WriteString(` 条
最热
最新
`)
// 解析评论数据
comments := []map[string]interface{}{}
if commentsList, ok := data["comments"].([]interface{}); ok {
for _, item := range commentsList {
if comment, ok := item.(map[string]interface{}); ok {
comments = append(comments, comment)
}
}
}
// 计算分页
totalComments := len(comments)
startIdx := (page - 1) * pageSize
endIdx := startIdx + pageSize
if endIdx > totalComments {
endIdx = totalComments
}
// 获取当前页的评论
var pageComments []map[string]interface{}
if startIdx < totalComments {
pageComments = comments[startIdx:endIdx]
}
html.WriteString(`
`)
if len(pageComments) == 0 {
html.WriteString(`
暂无评论
`)
} else {
for idx, comment := range pageComments {
info := parseCommentData(comment)
// 生成 HTML
html.WriteString(`
`)
html.WriteString(htmlEscape(info.UserName))
if info.IsAuthor {
html.WriteString(`作者`)
}
if info.StickerImageURL != "" {
html.WriteString(``)
}
html.WriteString(`