160 lines
3.4 KiB
Go
160 lines
3.4 KiB
Go
package repositories
|
||
|
||
import (
|
||
// "log"
|
||
"time"
|
||
|
||
"github.com/niangaodev/art-code/config"
|
||
"github.com/niangaodev/art-code/models"
|
||
)
|
||
|
||
// Helper to parse date string to unix timestamp
|
||
func parseDateToUnix(dateStr string, isEnd bool) int64 {
|
||
if dateStr == "" {
|
||
return 0
|
||
}
|
||
// Try parsing with time first
|
||
t, err := time.ParseInLocation("2006-01-02 15:04", dateStr, time.Local)
|
||
if err == nil {
|
||
if isEnd {
|
||
// HH:mm:59
|
||
return t.Add(59 * time.Second).Unix()
|
||
}
|
||
return t.Unix()
|
||
}
|
||
|
||
// Try parsing just date
|
||
t, err = time.ParseInLocation("2006-01-02", dateStr, time.Local)
|
||
if err == nil {
|
||
if isEnd {
|
||
// 23:59:59
|
||
return t.Add(24*time.Hour - 1*time.Second).Unix()
|
||
}
|
||
return t.Unix()
|
||
}
|
||
|
||
return 0
|
||
}
|
||
|
||
// CreateAccessLog 创建访问日志
|
||
func CreateAccessLog(log *models.AccessLog) error {
|
||
now := time.Now().Unix()
|
||
query := `INSERT INTO access_logs (ip, user_agent, path, method, status_code, response_time, region, created_at, deleted_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0)`
|
||
_, err := config.DB.Exec(query, log.IP, log.UserAgent, log.Path, log.Method, log.StatusCode, log.ResponseTime, log.Region, now)
|
||
return err
|
||
}
|
||
|
||
// UVTrendData UV趋势数据
|
||
type UVTrendData struct {
|
||
Date string `json:"date"`
|
||
Count int `json:"value"`
|
||
YoY float64 `json:"yoy"`
|
||
MoM float64 `json:"mom"`
|
||
}
|
||
|
||
// GetDailyUV 获取UV趋势
|
||
func GetDailyUV(startDate, endDate string) ([]UVTrendData, error) {
|
||
query := `
|
||
SELECT FROM_UNIXTIME(access_time, '%Y-%m-%d') as date, COUNT(DISTINCT user_ip) as count
|
||
FROM user_access_logs
|
||
WHERE 1=1
|
||
`
|
||
args := []interface{}{}
|
||
|
||
if startDate != "" {
|
||
startUnix := parseDateToUnix(startDate, false)
|
||
query += " AND access_time >= ?"
|
||
args = append(args, startUnix)
|
||
} else {
|
||
// 默认最近7天
|
||
startUnix := time.Now().AddDate(0, 0, -6).Unix()
|
||
query += " AND access_time >= ?"
|
||
args = append(args, startUnix)
|
||
}
|
||
|
||
if endDate != "" {
|
||
endUnix := parseDateToUnix(endDate, true)
|
||
query += " AND access_time <= ?"
|
||
args = append(args, endUnix)
|
||
}
|
||
|
||
query += `
|
||
GROUP BY date
|
||
ORDER BY date ASC
|
||
`
|
||
|
||
rows, err := config.DB.Query(query, args...)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
defer rows.Close()
|
||
|
||
var results []UVTrendData
|
||
for rows.Next() {
|
||
var r UVTrendData
|
||
if err := rows.Scan(&r.Date, &r.Count); err != nil {
|
||
return nil, err
|
||
}
|
||
// 暂未实现真实的同比环比计算逻辑,设为0
|
||
r.YoY = 0
|
||
r.MoM = 0
|
||
results = append(results, r)
|
||
}
|
||
return results, nil
|
||
}
|
||
|
||
// GetUserRegions 获取用户地域分布
|
||
func GetUserRegions(startDate, endDate string) ([]struct {
|
||
Region string
|
||
Count int
|
||
}, error) {
|
||
query := `
|
||
SELECT
|
||
COALESCE(NULLIF(user_location, ''), 'Unknown') as region,
|
||
COUNT(DISTINCT user_ip) as count
|
||
FROM user_access_logs
|
||
WHERE 1=1
|
||
`
|
||
args := []interface{}{}
|
||
|
||
if startDate != "" {
|
||
startUnix := parseDateToUnix(startDate, false)
|
||
query += " AND access_time >= ?"
|
||
args = append(args, startUnix)
|
||
}
|
||
|
||
if endDate != "" {
|
||
endUnix := parseDateToUnix(endDate, true)
|
||
query += " AND access_time <= ?"
|
||
args = append(args, endUnix)
|
||
}
|
||
|
||
query += `
|
||
GROUP BY region
|
||
ORDER BY count DESC
|
||
LIMIT 20
|
||
`
|
||
|
||
rows, err := config.DB.Query(query, args...)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
defer rows.Close()
|
||
|
||
var results []struct {
|
||
Region string
|
||
Count int
|
||
}
|
||
for rows.Next() {
|
||
var r struct {
|
||
Region string
|
||
Count int
|
||
}
|
||
if err := rows.Scan(&r.Region, &r.Count); err != nil {
|
||
return nil, err
|
||
}
|
||
results = append(results, r)
|
||
}
|
||
return results, nil
|
||
}
|