Files
soul-yongping/soul-api/internal/handler/search.go
Alex-larget d82ef6d8e4 Enhance mini program environment configuration and chapter loading logic
- Introduced a debugging environment configuration in app.js, allowing for dynamic API endpoint selection based on the environment.
- Implemented lazy loading for chapter parts in chapters.js, improving performance by only fetching necessary data.
- Updated UI elements in chapters.wxml to reflect changes in chapter loading and added loading indicators.
- Enhanced error handling and data management for chapter retrieval, ensuring a smoother user experience.
- Added functionality for switching API environments in settings.js, visible only in development mode.
2026-03-14 18:04:05 +08:00

83 lines
2.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handler
import (
"net/http"
"strings"
"unicode/utf8"
"soul-api/internal/database"
"soul-api/internal/model"
"github.com/gin-gonic/gin"
)
// escapeLike 转义 LIKE 中的 % _ \,防止注入与通配符滥用
func escapeLike(s string) string {
s = strings.ReplaceAll(s, "\\", "\\\\")
s = strings.ReplaceAll(s, "%", "\\%")
s = strings.ReplaceAll(s, "_", "\\_")
return s
}
// SearchGet GET /api/search?q= 从 chapters 表搜索GORM参数化
func SearchGet(c *gin.Context) {
q := strings.TrimSpace(c.Query("q"))
if q == "" {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "请输入搜索关键词"})
return
}
pattern := "%" + escapeLike(q) + "%"
var list []model.Chapter
err := database.DB().Model(&model.Chapter{}).
Where("section_title LIKE ? OR content LIKE ?", pattern, pattern).
Order("sort_order ASC, id ASC").
Limit(50).
Find(&list).Error
if err != nil {
c.JSON(http.StatusOK, gin.H{"success": true, "data": gin.H{"keyword": q, "total": 0, "results": []interface{}{}}})
return
}
sortChaptersByNaturalID(list)
lowerQ := strings.ToLower(q)
results := make([]gin.H, 0, len(list))
for _, ch := range list {
matchType := "content"
score := 5
if strings.Contains(strings.ToLower(ch.SectionTitle), lowerQ) {
matchType = "title"
score = 10
}
snippet := ""
pos := strings.Index(strings.ToLower(ch.Content), lowerQ)
if pos >= 0 && len(ch.Content) > 0 {
start := pos - 50
if start < 0 {
start = 0
}
end := pos + utf8.RuneCountInString(q) + 50
if end > len(ch.Content) {
end = len(ch.Content)
}
snippet = ch.Content[start:end]
if start > 0 {
snippet = "..." + snippet
}
if end < len(ch.Content) {
snippet = snippet + "..."
}
}
price := 1.0
if ch.Price != nil {
price = *ch.Price
}
results = append(results, gin.H{
"id": ch.ID, "title": ch.SectionTitle, "partTitle": ch.PartTitle, "chapterTitle": ch.ChapterTitle,
"price": price, "isFree": ch.IsFree, "matchType": matchType, "score": score, "snippet": snippet,
})
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": gin.H{"keyword": q, "total": len(results), "results": results},
})
}