Files
nl-blogs/server/handlers/dashboard.go
2026-01-20 15:23:37 +08:00

117 lines
3.1 KiB
Go
Raw Permalink 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 handlers
import (
"net/url"
"strings"
"github.com/gin-gonic/gin"
"github.com/niangaodev/art-code/repositories"
"github.com/niangaodev/art-code/utils"
)
// GetDashboardStats 获取仪表盘统计数据
func GetDashboardStats(c *gin.Context) {
startDate := c.Query("startDate")
endDate := c.Query("endDate")
// URL解码日期参数处理+号被编码的情况
if startDate != "" {
if decoded, err := url.QueryUnescape(startDate); err == nil {
// 将+号替换为空格URL编码中+可能代表空格)
startDate = strings.ReplaceAll(decoded, "+", " ")
}
}
if endDate != "" {
if decoded, err := url.QueryUnescape(endDate); err == nil {
// 将+号替换为空格URL编码中+可能代表空格)
endDate = strings.ReplaceAll(decoded, "+", " ")
}
}
// 1. 获取博文增长趋势
postsTrend, err := repositories.GetNewPostsTrend(startDate, endDate)
if err != nil {
postsTrend = []repositories.TrendData{} // Fallback empty
}
// 2. 获取访客UV (根据IP)
uvTrend, err := repositories.GetDailyUV(startDate, endDate)
if err != nil {
uvTrend = []repositories.UVTrendData{}
}
// 3. 用户画像-地域分布(使用 user_access_logs 表)
userRegions, err := repositories.GetUserRegionsFromUserAccessLogs(startDate, endDate)
if err != nil {
// 即使出错也返回所有34个省份的默认数据Count为0
userRegions = repositories.GetDefaultUserRegions()
}
// 4. 热门文章 Top 5
// 优先使用访问日志统计不足5条则用posts表的read_count补齐
topPosts, err := repositories.GetTopArticlesByAccess(5)
if err != nil {
topPosts = []struct {
ArticleID int `json:"article_id"`
Title string `json:"title"`
Count int `json:"count"`
}{}
}
if len(topPosts) < 5 {
// Fetch more than needed to ensure we find unique ones, or just fetch top 5
dbPosts, err := repositories.GetTopPosts(10)
if err == nil {
// Create a map of existing IDs to avoid duplicates
existingIDs := make(map[int]bool)
for _, p := range topPosts {
existingIDs[p.ArticleID] = true
}
for _, p := range dbPosts {
if len(topPosts) >= 5 {
break
}
if !existingIDs[int(p.ID)] {
topPosts = append(topPosts, struct {
ArticleID int `json:"article_id"`
Title string `json:"title"`
Count int `json:"count"`
}{
ArticleID: int(p.ID),
Title: p.Title,
Count: int(p.ReadCount),
})
existingIDs[int(p.ID)] = true
}
}
}
}
// 5. 合作咨询总数
inquiryCount, _ := repositories.GetInquiryCount()
// 6. 作品总数
workCount, _ := repositories.GetWorkCount()
// 7. 文章总数
postCount, _ := repositories.GetPostCount()
// 8. 管理员操作统计
operationTrend, err := repositories.GetOperationTrend(startDate, endDate)
if err != nil {
operationTrend = []repositories.OperationTrendData{}
}
utils.Success(c, gin.H{
"postsTrend": postsTrend,
"uvTrend": uvTrend,
"userRegions": userRegions,
"topPosts": topPosts,
"inquiryCount": inquiryCount,
"posts": postCount,
"works": workCount,
"operationTrend": operationTrend,
})
}