From 1eeeaf03ba48f049a0c193fb38d2967f5fd75d9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=90=A6?= Date: Fri, 16 Jan 2026 12:21:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8E=E5=8F=B0=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/admin/dashboard/Analytics.vue | 1 + server/repositories/log_repository.go | 77 +++++++++++++------ server/repositories/post_repository.go | 34 +++++++- 3 files changed, 86 insertions(+), 26 deletions(-) diff --git a/client/src/pages/admin/dashboard/Analytics.vue b/client/src/pages/admin/dashboard/Analytics.vue index 44c1a28..e909880 100644 --- a/client/src/pages/admin/dashboard/Analytics.vue +++ b/client/src/pages/admin/dashboard/Analytics.vue @@ -323,6 +323,7 @@ const topPostsOption = computed(() => ({ }, yAxis: { type: 'category', + inverse: true, data: stats.value.topPosts?.map((i: any) => i.title.length > 10 ? i.title.substring(0, 10) + '...' : i.title) || [], axisLabel: { color: '#ccc' } }, diff --git a/server/repositories/log_repository.go b/server/repositories/log_repository.go index bf2a99a..030968c 100644 --- a/server/repositories/log_repository.go +++ b/server/repositories/log_repository.go @@ -1,10 +1,42 @@ package repositories import ( + // "log" + "time" + "github.com/niangaodev/art-code/config" "github.com/niangaodev/art-code/models" ) +// Helper to parse date strings flexibly +func parseDateString(dateStr string, isEnd bool) string { + if dateStr == "" { + return "" + } + // Try parsing with time first + t, err := time.ParseInLocation("2006-01-02 15:04", dateStr, time.Local) + if err == nil { + if isEnd { + // If it's end time, go to end of that minute + return t.Format("2006-01-02 15:04") + ":59" + } + return t.Format("2006-01-02 15:04:05") + } + + // Try parsing just date + t, err = time.ParseInLocation("2006-01-02", dateStr, time.Local) + if err == nil { + if isEnd { + // If it's end date, go to end of day + return t.Format("2006-01-02") + " 23:59:59" + } + return t.Format("2006-01-02") + " 00:00:00" + } + + // Return original if parsing fails (fallback) + return dateStr +} + // CreateAccessLog 创建访问日志 func CreateAccessLog(log *models.AccessLog) error { query := `INSERT INTO access_logs (ip, user_agent, path, method, status_code, response_time, region) VALUES (?, ?, ?, ?, ?, ?, ?)` @@ -23,25 +55,25 @@ type UVTrendData struct { // GetDailyUV 获取UV趋势 func GetDailyUV(startDate, endDate string) ([]UVTrendData, error) { query := ` - SELECT DATE_FORMAT(created_at, '%Y-%m-%d') as date, COUNT(DISTINCT ip) as count - FROM access_logs + SELECT DATE_FORMAT(access_time, '%Y-%m-%d') as date, COUNT(DISTINCT user_ip) as count + FROM user_access_logs WHERE 1=1 ` args := []interface{}{} if startDate != "" { - query += " AND created_at >= ?" - args = append(args, startDate) + formattedStart := parseDateString(startDate, false) + query += " AND access_time >= ?" + args = append(args, formattedStart) } else { // 默认最近7天 - query += " AND created_at >= DATE_SUB(CURDATE(), INTERVAL 6 DAY)" + query += " AND access_time >= DATE_SUB(CURDATE(), INTERVAL 6 DAY)" } if endDate != "" { - query += " AND created_at <= ?" - // End date usually needs to cover the whole day, so append time or next day - // For simplicity assuming YYYY-MM-DD format, we might want <= YYYY-MM-DD 23:59:59 - args = append(args, endDate+" 23:59:59") + formattedEnd := parseDateString(endDate, true) + query += " AND access_time <= ?" + args = append(args, formattedEnd) } query += ` @@ -74,29 +106,29 @@ func GetUserRegions(startDate, endDate string) ([]struct { Region string Count int }, error) { - // 简单的截取省份逻辑,实际可能需要更复杂的解析,这里假设region格式为 国家|区域|省份|城市|ISP - // 我们可以取省份 (第3部分) query := ` SELECT - SUBSTRING_INDEX(SUBSTRING_INDEX(region, '|', 3), '|', -1) as province, - COUNT(DISTINCT ip) as count - FROM access_logs - WHERE region != 'Internal' AND region != 'Unknown' AND region IS NOT NULL + COALESCE(NULLIF(user_location, ''), 'Unknown') as region, + COUNT(DISTINCT user_ip) as count + FROM user_access_logs + WHERE 1=1 ` args := []interface{}{} if startDate != "" { - query += " AND created_at >= ?" - args = append(args, startDate) + formattedStart := parseDateString(startDate, false) + query += " AND access_time >= ?" + args = append(args, formattedStart) } if endDate != "" { - query += " AND created_at <= ?" - args = append(args, endDate+" 23:59:59") + formattedEnd := parseDateString(endDate, true) + query += " AND access_time <= ?" + args = append(args, formattedEnd) } query += ` - GROUP BY province + GROUP BY region ORDER BY count DESC LIMIT 20 ` @@ -119,10 +151,7 @@ func GetUserRegions(startDate, endDate string) ([]struct { if err := rows.Scan(&r.Region, &r.Count); err != nil { return nil, err } - // 过滤掉无效数据 - if r.Region != "" && r.Region != "0" { - results = append(results, r) - } + results = append(results, r) } return results, nil } diff --git a/server/repositories/post_repository.go b/server/repositories/post_repository.go index 0437bb7..8e999ab 100644 --- a/server/repositories/post_repository.go +++ b/server/repositories/post_repository.go @@ -3,11 +3,39 @@ package repositories import ( "database/sql" "log" + "time" "github.com/niangaodev/art-code/config" "github.com/niangaodev/art-code/models" ) +// Helper to parse date strings flexibly (duplicated to avoid circular dependency if moved to utils, or just keep simple) +// Ideally this should be in a utils package, but for now we'll keep it local to avoid refactoring everything +func parsePostDateString(dateStr string, isEnd bool) string { + if dateStr == "" { + return "" + } + // Try parsing with time first + t, err := time.ParseInLocation("2006-01-02 15:04", dateStr, time.Local) + if err == nil { + if isEnd { + return t.Format("2006-01-02 15:04") + ":59" + } + return t.Format("2006-01-02 15:04:05") + } + + // Try parsing just date + t, err = time.ParseInLocation("2006-01-02", dateStr, time.Local) + if err == nil { + if isEnd { + return t.Format("2006-01-02") + " 23:59:59" + } + return t.Format("2006-01-02") + " 00:00:00" + } + + return dateStr +} + // GetPosts 获取所有博客文章(支持搜索) func GetPosts(keyword string) ([]models.Post, error) { var rows *sql.Rows @@ -405,16 +433,18 @@ func GetNewPostsTrend(startDate, endDate string) ([]TrendData, error) { args := []interface{}{dateFormat} if startDate != "" { + formattedStart := parsePostDateString(startDate, false) query += " AND created_at >= ?" - args = append(args, startDate) + args = append(args, formattedStart) } else { // 默认最近7天 query += " AND created_at >= DATE_SUB(CURDATE(), INTERVAL 6 DAY)" } if endDate != "" { + formattedEnd := parsePostDateString(endDate, true) query += " AND created_at <= ?" - args = append(args, endDate+" 23:59:59") + args = append(args, formattedEnd) } query += `