后台布局

This commit is contained in:
李琦
2026-01-16 12:21:10 +08:00
parent 080a964e34
commit 1eeeaf03ba
3 changed files with 86 additions and 26 deletions

View File

@@ -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' }
},

View File

@@ -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
}

View File

@@ -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 += `