Files
nl-blogs/server/handlers/dashboard.go

117 lines
3.1 KiB
Go
Raw Normal View History

2026-01-15 13:51:44 +08:00
package handlers
import (
2026-01-20 14:31:39 +08:00
"net/url"
"strings"
2026-01-15 13:51:44 +08:00
"github.com/gin-gonic/gin"
"github.com/niangaodev/art-code/repositories"
2026-01-16 10:19:30 +08:00
"github.com/niangaodev/art-code/utils"
2026-01-15 13:51:44 +08:00
)
2026-01-16 09:32:46 +08:00
// GetDashboardStats 获取仪表盘统计数据
func GetDashboardStats(c *gin.Context) {
2026-01-16 10:19:30 +08:00
startDate := c.Query("startDate")
endDate := c.Query("endDate")
2026-01-20 14:31:39 +08:00
// 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, "+", " ")
}
}
2026-01-16 10:19:30 +08:00
// 1. 获取博文增长趋势
postsTrend, err := repositories.GetNewPostsTrend(startDate, endDate)
2026-01-15 13:51:44 +08:00
if err != nil {
2026-01-16 10:19:30 +08:00
postsTrend = []repositories.TrendData{} // Fallback empty
2026-01-15 13:51:44 +08:00
}
2026-01-16 10:19:30 +08:00
// 2. 获取访客UV (根据IP)
uvTrend, err := repositories.GetDailyUV(startDate, endDate)
2026-01-15 13:51:44 +08:00
if err != nil {
2026-01-16 10:19:30 +08:00
uvTrend = []repositories.UVTrendData{}
2026-01-15 13:51:44 +08:00
}
2026-01-20 15:23:37 +08:00
// 3. 用户画像-地域分布(使用 user_access_logs 表)
userRegions, err := repositories.GetUserRegionsFromUserAccessLogs(startDate, endDate)
2026-01-15 13:51:44 +08:00
if err != nil {
2026-01-20 14:31:39 +08:00
// 即使出错也返回所有34个省份的默认数据Count为0
userRegions = repositories.GetDefaultUserRegions()
2026-01-15 13:51:44 +08:00
}
2026-01-16 09:32:46 +08:00
// 4. 热门文章 Top 5
2026-01-16 13:01:21 +08:00
// 优先使用访问日志统计不足5条则用posts表的read_count补齐
2026-01-16 10:19:30 +08:00
topPosts, err := repositories.GetTopArticlesByAccess(5)
2026-01-16 13:01:21 +08:00
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)
2026-01-16 10:19:30 +08:00
if err == nil {
2026-01-16 13:01:21 +08:00
// Create a map of existing IDs to avoid duplicates
existingIDs := make(map[int]bool)
for _, p := range topPosts {
existingIDs[p.ArticleID] = true
}
2026-01-16 10:19:30 +08:00
for _, p := range dbPosts {
2026-01-16 13:01:21 +08:00
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
}
2026-01-16 10:19:30 +08:00
}
}
2026-01-15 13:51:44 +08:00
}
2026-01-16 09:32:46 +08:00
// 5. 合作咨询总数
2026-01-19 13:53:32 +08:00
inquiryCount, _ := repositories.GetInquiryCount()
2026-01-16 09:32:46 +08:00
2026-01-16 10:19:30 +08:00
// 6. 作品总数
2026-01-16 13:01:21 +08:00
workCount, _ := repositories.GetWorkCount()
2026-01-16 10:19:30 +08:00
// 7. 文章总数
2026-01-16 13:01:21 +08:00
postCount, _ := repositories.GetPostCount()
2026-01-16 10:19:30 +08:00
2026-01-20 14:31:39 +08:00
// 8. 管理员操作统计
operationTrend, err := repositories.GetOperationTrend(startDate, endDate)
if err != nil {
operationTrend = []repositories.OperationTrendData{}
}
2026-01-16 10:19:30 +08:00
utils.Success(c, gin.H{
2026-01-20 14:31:39 +08:00
"postsTrend": postsTrend,
"uvTrend": uvTrend,
"userRegions": userRegions,
"topPosts": topPosts,
"inquiryCount": inquiryCount,
"posts": postCount,
"works": workCount,
"operationTrend": operationTrend,
2026-01-16 09:32:46 +08:00
})
2026-01-15 13:51:44 +08:00
}