108 lines
2.5 KiB
Go
108 lines
2.5 KiB
Go
package handler
|
|
|
|
import (
|
|
"strconv"
|
|
|
|
"gotest/internal/model"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// AccessLogHandler 访问日志处理器
|
|
type AccessLogHandler struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewAccessLogHandler 创建访问日志处理器
|
|
func NewAccessLogHandler(db *gorm.DB) *AccessLogHandler {
|
|
return &AccessLogHandler{db: db}
|
|
}
|
|
|
|
// ListLogs 获取访问日志列表 GET /api/v1/admin/access-logs
|
|
func (h *AccessLogHandler) ListLogs(c *gin.Context) {
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
|
ip := c.Query("ip")
|
|
path := c.Query("path")
|
|
|
|
if page < 1 {
|
|
page = 1
|
|
}
|
|
if pageSize < 1 || pageSize > 100 {
|
|
pageSize = 20
|
|
}
|
|
offset := (page - 1) * pageSize
|
|
|
|
query := h.db.Model(&model.AccessLog{})
|
|
|
|
if ip != "" {
|
|
query = query.Where("ip LIKE ?", "%"+ip+"%")
|
|
}
|
|
if path != "" {
|
|
query = query.Where("path LIKE ?", "%"+path+"%")
|
|
}
|
|
|
|
var total int64
|
|
query.Count(&total)
|
|
|
|
var logs []model.AccessLog
|
|
if err := query.Order("id DESC").Offset(offset).Limit(pageSize).Find(&logs).Error; err != nil {
|
|
FailInternal(c, "查询失败: "+err.Error())
|
|
return
|
|
}
|
|
|
|
Success(c, gin.H{
|
|
"list": logs,
|
|
"total": total,
|
|
"page": page,
|
|
"page_size": pageSize,
|
|
})
|
|
}
|
|
|
|
// GetStats 获取访问统计 GET /api/v1/admin/access-logs/stats
|
|
func (h *AccessLogHandler) GetStats(c *gin.Context) {
|
|
var totalVisits int64
|
|
h.db.Model(&model.AccessLog{}).Count(&totalVisits)
|
|
|
|
var todayVisits int64
|
|
h.db.Model(&model.AccessLog{}).Where("created_at >= date('now')").Count(&todayVisits)
|
|
|
|
var uniqueIPs int64
|
|
h.db.Model(&model.AccessLog{}).Distinct("ip").Count(&uniqueIPs)
|
|
|
|
// 最近 24 小时每小时访问量
|
|
type hourlyCount struct {
|
|
Hour string `json:"hour"`
|
|
Count int64 `json:"count"`
|
|
}
|
|
var hourly []hourlyCount
|
|
h.db.Model(&model.AccessLog{}).
|
|
Select("strftime('%Y-%m-%d %H:00', created_at) as hour, count(*) as count").
|
|
Where("created_at >= datetime('now', '-24 hours')").
|
|
Group("hour").
|
|
Order("hour ASC").
|
|
Scan(&hourly)
|
|
|
|
// 最近 10 条日志
|
|
var recent []model.AccessLog
|
|
h.db.Order("id DESC").Limit(10).Find(&recent)
|
|
|
|
Success(c, gin.H{
|
|
"total_visits": totalVisits,
|
|
"today_visits": todayVisits,
|
|
"unique_ips": uniqueIPs,
|
|
"hourly": hourly,
|
|
"recent": recent,
|
|
})
|
|
}
|
|
|
|
// DeleteLogs 清空访问日志 DELETE /api/v1/admin/access-logs
|
|
func (h *AccessLogHandler) DeleteLogs(c *gin.Context) {
|
|
if err := h.db.Where("1 = 1").Delete(&model.AccessLog{}).Error; err != nil {
|
|
FailInternal(c, "清空失败: "+err.Error())
|
|
return
|
|
}
|
|
SuccessMsg(c, "清空成功")
|
|
}
|