init push

This commit is contained in:
2026-05-21 19:52:45 +08:00
commit e3f75311ab
1280 changed files with 179173 additions and 0 deletions

208
backend/repo/pg/stat.go Normal file
View File

@@ -0,0 +1,208 @@
package pg
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
v1 "github.com/chaitin/panda-wiki/api/stat/v1"
"github.com/chaitin/panda-wiki/domain"
"github.com/chaitin/panda-wiki/store/cache"
"github.com/chaitin/panda-wiki/store/pg"
"github.com/chaitin/panda-wiki/utils"
)
type StatRepository struct {
db *pg.DB
cache *cache.Cache
}
func NewStatRepository(db *pg.DB, cahe *cache.Cache) *StatRepository {
return &StatRepository{
db: db,
cache: cahe,
}
}
func (r *StatRepository) CreateStatPage(ctx context.Context, stat *domain.StatPage) error {
return r.db.WithContext(ctx).Model(&domain.StatPage{}).Create(stat).Error
}
func (r *StatRepository) GetHotPages(ctx context.Context, kbID string) ([]*domain.HotPage, error) {
var hotPages []*domain.HotPage
if err := r.db.WithContext(ctx).Model(&domain.StatPage{}).
Where("kb_id = ?", kbID).
Where("node_id != '' ").
Where("scene = ?", domain.StatPageSceneNodeDetail).
Group("node_id").
Select("node_id, COUNT(*) as count").
Order("count DESC").
Limit(10).
Find(&hotPages).Error; err != nil {
return nil, err
}
return hotPages, nil
}
func (r *StatRepository) GetHotPagesNoLimit(ctx context.Context, kbID string) ([]*domain.HotPage, error) {
var hotPages []*domain.HotPage
if err := r.db.WithContext(ctx).Model(&domain.StatPage{}).
Where("kb_id = ?", kbID).
Where("node_id != '' ").
Where("scene = ?", domain.StatPageSceneNodeDetail).
Group("node_id").
Select("node_id, COUNT(*) as count").
Find(&hotPages).Error; err != nil {
return nil, err
}
return hotPages, nil
}
func (r *StatRepository) GetHotScene(ctx context.Context, kbID string) (map[domain.StatPageScene]int64, error) {
var scenes map[domain.StatPageScene]int64
if err := r.db.WithContext(ctx).Model(&domain.StatPage{}).
Where("kb_id = ?", kbID).
Group("scene").
Select("scene, COUNT(*) as count").
Order("count DESC").
Limit(10).
Find(&scenes).Error; err != nil {
return nil, err
}
return scenes, nil
}
func (r *StatRepository) GetHotRefererHosts(ctx context.Context, kbID string) ([]*domain.HotRefererHost, error) {
var hotRefererHosts []*domain.HotRefererHost
if err := r.db.WithContext(ctx).Model(&domain.StatPage{}).
Where("kb_id = ? AND referer_host != ?", kbID, "").
Group("referer_host").
Select("referer_host, COUNT(*) as count").
Order("count DESC").
Limit(10).
Find(&hotRefererHosts).Error; err != nil {
return nil, err
}
return hotRefererHosts, nil
}
func (r *StatRepository) GetHotBrowsers(ctx context.Context, kbID string) (*domain.HotBrowser, error) {
var hotBrowsers *domain.HotBrowser
var osCount []domain.BrowserCount
var browserCount []domain.BrowserCount
query := r.db.WithContext(ctx).Model(&domain.StatPage{}).
Where("kb_id = ?", kbID).
Where("browser_name != '' ").
Group("browser_name").
Select("browser_name as name, COUNT(*) as count")
if err := query.Order("count DESC").Limit(10).Find(&browserCount).Error; err != nil {
return nil, err
}
query = r.db.WithContext(ctx).Model(&domain.StatPage{}).
Where("kb_id = ?", kbID).
Where("browser_os != '' ").
Group("browser_os").
Select("browser_os as name, COUNT(*) as count")
if err := query.Order("count DESC").Limit(10).Find(&osCount).Error; err != nil {
return nil, err
}
hotBrowsers = &domain.HotBrowser{
OS: osCount,
Browser: browserCount,
}
return hotBrowsers, nil
}
func (r *StatRepository) GetStatPageCount(ctx context.Context, kbID string) (*v1.StatCountResp, error) {
var count v1.StatCountResp
if err := r.db.WithContext(ctx).Model(&domain.StatPage{}).
Where("kb_id = ?", kbID).
Select("COUNT(DISTINCT ip) as ip_count, COUNT(DISTINCT session_id) as session_count, COUNT(*) as page_visit_count").
Scan(&count).Error; err != nil {
return nil, err
}
return &count, nil
}
func (r *StatRepository) GetInstantCount(ctx context.Context, kbID string) ([]*domain.InstantCountResp, error) {
var instantCount []*domain.InstantCountResp
if err := r.db.WithContext(ctx).Model(&domain.StatPage{}).
Where("kb_id = ? AND created_at >= NOW() - INTERVAL '1h'", kbID).
Select("date_trunc('minute', created_at) as time, COUNT(*) as count").
Group("time").
Order("time ASC").
Find(&instantCount).Error; err != nil {
return nil, err
}
return instantCount, nil
}
func (r *StatRepository) GetInstantPages(ctx context.Context, kbID string) ([]*domain.InstantPageResp, error) {
var instantPages []*domain.InstantPageResp
if err := r.db.WithContext(ctx).Model(&domain.StatPage{}).
Where("kb_id = ?", kbID).
Select("node_id, ip, scene, created_at,user_id").
Order("created_at DESC").
Limit(10).
Find(&instantPages).Error; err != nil {
return nil, err
}
return instantPages, nil
}
func (r *StatRepository) RemoveOldData(ctx context.Context) error {
if err := r.db.WithContext(ctx).Model(&domain.StatPage{}).
Where("created_at < ?", utils.GetTimeHourOffset(-24)).
Delete(&domain.StatPage{}).Error; err != nil {
return err
}
return nil
}
// GetYesterdayPVByNode 获取昨天的PV数据按node_id分组
func (r *StatRepository) GetYesterdayPVByNode(ctx context.Context) (map[string]int64, error) {
type PVResult struct {
NodeID string
Count int64
}
var results []PVResult
if err := r.db.WithContext(ctx).Model(&domain.StatPage{}).
Where("created_at < ?", utils.GetTimeHourOffset(0)).
Where("created_at >= ?", utils.GetTimeHourOffset(-24)).
Where("node_id != ?", "").
Group("node_id").
Select("node_id, COUNT(*) as count").
Find(&results).Error; err != nil {
return nil, err
}
pvMap := make(map[string]int64)
for _, result := range results {
pvMap[result.NodeID] = result.Count
}
return pvMap, nil
}
// UpsertNodeStats 插入或更新node_stats表
func (r *StatRepository) UpsertNodeStats(ctx context.Context, nodeID string, pvCount int64) error {
nodeStats := &domain.NodeStats{
NodeID: nodeID,
PV: pvCount,
}
// 使用GORM的Clauses进行upsert操作
return r.db.WithContext(ctx).
Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "node_id"}},
DoUpdates: clause.Assignments(map[string]interface{}{
"pv": gorm.Expr("node_stats.pv + ?", pvCount),
}),
}).
Create(nodeStats).Error
}