feat: add analytics backend

This commit is contained in:
2026-05-17 10:14:08 +08:00
parent 6542912d93
commit 3decff526a
19 changed files with 809 additions and 0 deletions
@@ -0,0 +1,72 @@
package com.emotion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.emotion.dto.response.analytics.AnalyticsPreferenceItem;
import com.emotion.dto.response.analytics.AnalyticsTopEventItem;
import com.emotion.dto.response.analytics.AnalyticsTrendItem;
import com.emotion.dto.response.analytics.AnalyticsUserItem;
import com.emotion.entity.AnalyticsEvent;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDateTime;
import java.util.List;
@Mapper
public interface AnalyticsEventMapper extends BaseMapper<AnalyticsEvent> {
@Select("SELECT COUNT(*) FROM t_analytics_event WHERE is_deleted = 0 AND occurred_at >= #{start} AND occurred_at < #{end}")
Long countAll(@Param("start") LocalDateTime start, @Param("end") LocalDateTime end);
@Select("SELECT COUNT(*) FROM t_analytics_event WHERE is_deleted = 0 AND event_name = #{eventName} AND occurred_at >= #{start} AND occurred_at < #{end}")
Long countEvent(@Param("eventName") String eventName,
@Param("start") LocalDateTime start,
@Param("end") LocalDateTime end);
@Select("SELECT COUNT(DISTINCT COALESCE(user_id, anonymous_id)) FROM t_analytics_event WHERE is_deleted = 0 AND occurred_at >= #{start} AND occurred_at < #{end} AND COALESCE(user_id, anonymous_id) IS NOT NULL")
Long countUniqueVisitors(@Param("start") LocalDateTime start, @Param("end") LocalDateTime end);
@Select("SELECT COUNT(DISTINCT COALESCE(user_id, anonymous_id)) FROM t_analytics_event WHERE is_deleted = 0 AND user_id IS NOT NULL AND occurred_at >= #{start} AND occurred_at < #{end}")
Long countActiveUsers(@Param("start") LocalDateTime start, @Param("end") LocalDateTime end);
@Select("SELECT COALESCE(AVG(duration_ms), 0) FROM t_analytics_event WHERE is_deleted = 0 AND event_name = 'page_leave' AND duration_ms IS NOT NULL AND duration_ms >= 0 AND occurred_at >= #{start} AND occurred_at < #{end}")
Double avgStayMs(@Param("start") LocalDateTime start, @Param("end") LocalDateTime end);
@Select("SELECT event_name AS eventName, event_type AS eventType, COUNT(*) AS count, COUNT(DISTINCT COALESCE(user_id, anonymous_id)) AS users " +
"FROM t_analytics_event WHERE is_deleted = 0 AND occurred_at >= #{start} AND occurred_at < #{end} " +
"GROUP BY event_name, event_type ORDER BY count DESC LIMIT #{limit}")
List<AnalyticsTopEventItem> selectTopEvents(@Param("start") LocalDateTime start,
@Param("end") LocalDateTime end,
@Param("limit") int limit);
@Select("SELECT DATE_FORMAT(occurred_at, #{dateFormat}) AS bucket, event_name AS eventName, COUNT(*) AS count, COUNT(DISTINCT COALESCE(user_id, anonymous_id)) AS users " +
"FROM t_analytics_event WHERE is_deleted = 0 AND occurred_at >= #{start} AND occurred_at < #{end} " +
"GROUP BY DATE_FORMAT(occurred_at, #{dateFormat}), event_name ORDER BY bucket ASC, count DESC")
List<AnalyticsTrendItem> selectTrend(@Param("start") LocalDateTime start,
@Param("end") LocalDateTime end,
@Param("dateFormat") String dateFormat);
@Select("SELECT event_name AS eventName, COUNT(DISTINCT COALESCE(user_id, anonymous_id)) AS users " +
"FROM t_analytics_event WHERE is_deleted = 0 AND event_name IN ('app_launch', 'page_view', 'script_inspiration_click', 'script_generate_start', 'script_generate_success', 'script_detail_view', 'path_select', 'script_tts_play') " +
"AND occurred_at >= #{start} AND occurred_at < #{end} AND COALESCE(user_id, anonymous_id) IS NOT NULL " +
"GROUP BY event_name")
List<AnalyticsTopEventItem> selectFunnelUsers(@Param("start") LocalDateTime start,
@Param("end") LocalDateTime end);
@Select("SELECT #{dimension} AS dimension, JSON_UNQUOTE(JSON_EXTRACT(properties, CONCAT('$.', #{dimension}))) AS value, COUNT(*) AS count, COUNT(DISTINCT COALESCE(user_id, anonymous_id)) AS users " +
"FROM t_analytics_event WHERE is_deleted = 0 AND properties IS NOT NULL AND occurred_at >= #{start} AND occurred_at < #{end} " +
"GROUP BY JSON_UNQUOTE(JSON_EXTRACT(properties, CONCAT('$.', #{dimension}))) " +
"HAVING value IS NOT NULL AND value <> '' ORDER BY count DESC LIMIT #{limit}")
List<AnalyticsPreferenceItem> selectPreference(@Param("dimension") String dimension,
@Param("start") LocalDateTime start,
@Param("end") LocalDateTime end,
@Param("limit") int limit);
@Select("SELECT user_id AS userId, anonymous_id AS anonymousId, COUNT(*) AS eventCount, MAX(occurred_at) AS lastActiveTime " +
"FROM t_analytics_event WHERE is_deleted = 0 AND occurred_at >= #{start} AND occurred_at < #{end} " +
"GROUP BY user_id, anonymous_id ORDER BY eventCount DESC, lastActiveTime DESC LIMIT #{limit}")
List<AnalyticsUserItem> selectUsers(@Param("start") LocalDateTime start,
@Param("end") LocalDateTime end,
@Param("limit") int limit);
}