feat(access-logs): 概览支持 Zone/域名多选筛选

概览可按 Zone→Domain 层级多选域名并折叠展开;明细列表 IP 旁展示地区。
后端 overview 支持 hosts 多域名精确匹配。
This commit is contained in:
ryan
2026-07-18 23:07:19 +08:00
parent 6f221b042e
commit 0bb6830047
11 changed files with 426 additions and 21 deletions
@@ -216,9 +216,10 @@ type AccessLogIPAnalysisView struct {
// AccessLogOverviewQuery filters access log overview queries.
type AccessLogOverviewQuery struct {
NodeID string `json:"node_id"`
Host string `json:"host"`
Hours int `json:"hours"`
NodeID string `json:"node_id"`
Host string `json:"host"`
Hosts []string `json:"hosts"`
Hours int `json:"hours"`
}
// AccessLogOverviewMetricPoint is a single overview trend bucket.
@@ -284,6 +285,7 @@ func GetAccessLogOverview(ctx context.Context, input AccessLogOverviewQuery) (*A
query := model.OpenFlareAccessLogQuery{
NodeID: normalized.NodeID,
Host: normalized.Host,
Hosts: normalized.Hosts,
Since: since,
Until: now,
}
@@ -330,13 +332,45 @@ func normalizeAccessLogOverviewQuery(input AccessLogOverviewQuery) AccessLogOver
if hours > maxAccessLogOverviewHours {
hours = maxAccessLogOverviewHours
}
hosts := normalizeAccessLogOverviewHosts(input.Hosts)
host := strings.TrimSpace(input.Host)
if len(hosts) == 0 && host != "" {
// Single host query uses Hosts exact-match for consistency with multi-select.
hosts = []string{host}
host = ""
}
if len(hosts) > 0 {
host = ""
}
return AccessLogOverviewQuery{
NodeID: strings.TrimSpace(input.NodeID),
Host: strings.TrimSpace(input.Host),
Host: host,
Hosts: hosts,
Hours: hours,
}
}
func normalizeAccessLogOverviewHosts(hosts []string) []string {
if len(hosts) == 0 {
return nil
}
seen := make(map[string]struct{}, len(hosts))
result := make([]string, 0, len(hosts))
for _, host := range hosts {
trimmed := strings.TrimSpace(host)
if trimmed == "" {
continue
}
key := strings.ToLower(trimmed)
if _, exists := seen[key]; exists {
continue
}
seen[key] = struct{}{}
result = append(result, trimmed)
}
return result
}
func valueCountDistribution(
ctx context.Context,
query model.OpenFlareAccessLogQuery,
@@ -427,6 +461,7 @@ func buildAccessLogOverviewTrends(
buckets, err := model.ListOpenFlareAccessLogBuckets(ctx, model.OpenFlareAccessLogBucketQuery{
NodeID: query.NodeID,
Host: query.Host,
Hosts: query.Hosts,
Since: query.Since,
Until: query.Until,
FoldMinutes: 60,
@@ -19,7 +19,8 @@ import (
// @Produce json
// @Security SessionCookie
// @Param node_id query string false "节点 ID"
// @Param host query string false "请求 Host"
// @Param host query string false "请求 Host(单域名)"
// @Param hosts query []string false "请求 Host 列表(多域名精确匹配)"
// @Param hours query int false "统计时间范围(小时)"
// @Success 200 {object} response.Any{data=observability.AccessLogOverview} "访问日志概览"
// @Failure 400 {object} response.Any "参数错误"
@@ -31,6 +32,7 @@ func GetAccessLogOverviewHandler(c *gin.Context) {
result, err := GetAccessLogOverview(c.Request.Context(), AccessLogOverviewQuery{
NodeID: c.Query("node_id"),
Host: c.Query("host"),
Hosts: c.QueryArray("hosts"),
Hours: readQueryInt(c, "hours"),
})
if apiutil.AbortBadRequestOnError(c, err) {