feat: add ahoy dashboard and city statistics

- Introduce a new admin dashboard for viewing Ahoy statistics.
- Display total visits, event counts, and unique visitors.
- List most popular and least popular active cities with their visit counts.
- Add a panel for recent events.
- Modify existing dashboard to include a section for inactive cities.

This commit introduces a comprehensive dashboard that helps
admin users monitor the traffic and engagement statistics of
various cities. The changes include functionality to show
active and inactive cities based on their popularity,
allowing for better insights into user engagement across
the application.
This commit is contained in:
songtianlun 2025-01-28 01:43:59 +08:00
parent 2a0226eb68
commit 069b6d4a4f
3 changed files with 98 additions and 1 deletions

View File

@ -0,0 +1,66 @@
ActiveAdmin.register_page "Ahoy Dashboard" do
menu label: "总览", parent: "数据统计", priority: 1
content title: "总览" do
columns do
column do
panel "访问统计" do
para "总访问量: #{Ahoy::Visit.count}"
para "总事件数: #{Ahoy::Event.count}"
para "独立访客数: #{Ahoy::Visit.distinct.count(:visitor_token)}"
end
end
column do
panel "热门城市" do
table_for City.by_popularity.limit(10) do
column("城市") { |city| link_to(city.name, admin_city_path(city)) }
column("访问量") { |city| city.view_count }
end
end
end
column do
panel "热门天气艺术" do
table_for WeatherArt.by_popularity.limit(10) do
column("作品") { |art| link_to(art.to_s, admin_weather_art_path(art)) }
column("访问量") { |art| art.view_count }
end
end
end
end
columns do
column do
panel "最冷门活跃城市" do
table_for City.least_popular_active.limit(10) do
column("城市") { |city| link_to(city.name, admin_city_path(city)) }
column("访问量") { |city| city.view_count }
# column("状态") { |city| status_tag(city.active? ? "活跃" : "停用") }
end
end
end
column do
panel "热门未活跃城市" do
table_for City.most_popular_inactive.limit(10) do
column("城市") { |city| link_to(city.name, admin_city_path(city)) }
column("访问量") { |city| city.view_count }
column("状态") { |city| status_tag(city.active? ? "活跃" : "停用") }
column("所属区域") { |city| city.country.region.name }
end
end
end
end
# 添加一个事件列表面板
panel "最近事件" do
table_for Ahoy::Event.order(time: :desc).limit(10) do
column :time
column :name
column :properties
end
end
end
end

View File

@ -37,9 +37,11 @@ ActiveAdmin.register_page "Dashboard" do
end end
end end
end end
end
columns do
column do column do
panel "冷门活跃城市" do panel "冷门活跃城市" do
table_for City.least_popular_active.limit(10) do table_for City.least_popular_active.limit(10) do
column("城市") { |city| link_to(city.name, admin_city_path(city)) } column("城市") { |city| link_to(city.name, admin_city_path(city)) }
column("访问量") { |city| city.view_count } column("访问量") { |city| city.view_count }
@ -47,6 +49,17 @@ ActiveAdmin.register_page "Dashboard" do
end end
end end
end end
column do
panel "热门未活跃城市" do
table_for City.most_popular_inactive.limit(10) do
column("城市") { |city| link_to(city.name, admin_city_path(city)) }
column("访问量") { |city| city.view_count }
column("状态") { |city| status_tag(city.active? ? "活跃" : "停用") }
column("所属区域") { |city| city.country.region.name }
end
end
end
end end
# 添加一个事件列表面板 # 添加一个事件列表面板

View File

@ -53,6 +53,24 @@ class City < ApplicationRecord
.order("visit_count ASC, cities.name ASC") .order("visit_count ASC, cities.name ASC")
end end
} }
scope :most_popular_inactive, -> {
if ActiveRecord::Base.connection.adapter_name.downcase == 'sqlite'
where(active: false)
.joins("LEFT JOIN ahoy_events ON json_extract(ahoy_events.properties, '$.city_id') = cities.id
AND json_extract(ahoy_events.properties, '$.event_type') = 'city_view'")
.group("cities.id")
.select("cities.*, COUNT(ahoy_events.id) as visit_count")
.order("COUNT(ahoy_events.id) DESC, cities.name ASC")
else
where(active: false)
.joins("LEFT JOIN ahoy_events ON (ahoy_events.properties::jsonb->>'city_id')::integer = cities.id
AND ahoy_events.properties::jsonb->>'event_type' = 'city_view'")
.group("cities.id")
.select("cities.*, COUNT(ahoy_events.id) as visit_count")
.order("COUNT(ahoy_events.id) DESC, cities.name ASC")
end
}
def to_s def to_s
name name