wucan 8 mēneši atpakaļ
vecāks
revīzija
777581c731

+ 5 - 1
.env

@@ -9,4 +9,8 @@ REDIS_PORT=6379
 REDIS_PASSWORD=
 
 #path
-DOWNLOAD_DIR=
+DOWNLOAD_DIR=
+
+MYSQL_HOST=124.223.73.12
+MYSQL_USERNAME=chunhao
+MYSQL_PASSWORD=chunhao2024

+ 22 - 0
bootstrap/mongodb.go

@@ -0,0 +1,22 @@
+package bootstrap
+
+import (
+	"context"
+	"designs/global"
+	"go.mongodb.org/mongo-driver/v2/mongo"
+	"go.mongodb.org/mongo-driver/v2/mongo/readpref"
+	"go.uber.org/zap"
+)
+import mongoOption "go.mongodb.org/mongo-driver/v2/mongo/options"
+
+func InitializeMongo() *mongo.Client {
+	client, _ := mongo.Connect(mongoOption.Client().ApplyURI("mongodb://localhost:27017"))
+
+	err := client.Ping(context.Background(), readpref.Primary())
+	if err != nil {
+		global.App.Log.Error("mongoDB connect ping failed, err:", zap.Any("err", err))
+		return nil
+	}
+
+	return client
+}

+ 26 - 10
controller/v1/gameAction.go

@@ -13,10 +13,10 @@ import (
 
 func UserActionList(c *gin.Context) {
 	form := request.Check(c, &struct {
-		Gid       string `form:"gid" binding:"required"`
-		Pf        string `form:"pf" binding:""`
-		StartTime string `form:"startTime" binding:"required"`
-		EndTime   string `form:"endTime" binding:"required"`
+		Gid       string   `form:"gid" binding:"required"`
+		Pf        []string `form:"pf" binding:""`
+		StartTime string   `form:"startTime" binding:"required"`
+		EndTime   string   `form:"endTime" binding:"required"`
 	}{})
 
 	//查询出所有的事件
@@ -74,6 +74,7 @@ func UserActionList(c *gin.Context) {
 	}
 
 	type responses struct {
+		Id              int     `json:"id"`
 		ActionId        string  `json:"actionId"`
 		ActionName      string  `json:"actionName"`
 		ActionCount     int     `json:"actionCount"`
@@ -93,6 +94,7 @@ func UserActionList(c *gin.Context) {
 		}
 
 		res = append(res, responses{
+			Id:              v.ID,
 			ActionId:        v.ActionId,
 			ActionName:      v.ActionName,
 			ActionCount:     actionSumMap[v.ActionId],
@@ -110,9 +112,10 @@ func UserActionList(c *gin.Context) {
 
 func UserActionDetail(c *gin.Context) {
 	form := request.Check(c, &struct {
-		Id        int    `form:"id" binding:"required"`
-		StartTime string `form:"startTime" binding:"required"`
-		EndTime   string `form:"endTime" binding:"required"`
+		Id        int      `form:"id" binding:"required"`
+		Pf        []string `form:"pf" binding:""`
+		StartTime string   `form:"startTime" binding:"required"`
+		EndTime   string   `form:"endTime" binding:"required"`
 	}{})
 
 	//查询启动次数
@@ -235,9 +238,17 @@ func UserActionDetailDistribution(c *gin.Context) {
 		for _, v := range days {
 			res[v] = activeCount[v]
 		}
-		fmt.Print(len(userAction) / len(days))
+		//fmt.Print(len(userAction) / len(days))
+
+		//response.Success(c, gin.H{"data": res, "avg": fmt.Sprintf("%.2f", float64(len(userAction))/float64(len(days)))})
+
+		response.Success(c, gin.H{
+			"data": map[string]interface{}{
+				"avg":  fmt.Sprintf("%.2f", float64(len(userAction))/float64(len(days))),
+				"list": res,
+			},
+		})
 
-		response.Success(c, gin.H{"data": res, "avg": fmt.Sprintf("%.2f", float64(len(userAction))/float64(len(days)))})
 	} else if form.Type == 2 {
 		var userAction []struct {
 			UserId    int    `json:"userId" gorm:"not null;column:userId;"`
@@ -266,7 +277,12 @@ func UserActionDetailDistribution(c *gin.Context) {
 			res[v] = len(activeCount[v])
 		}
 
-		response.Success(c, gin.H{"data": res, "avg": fmt.Sprintf("%.2f", float64(len(userAction))/float64(len(days)))})
+		response.Success(c, gin.H{
+			"data": map[string]interface{}{
+				"avg":  fmt.Sprintf("%.2f", float64(len(userAction))/float64(len(days))),
+				"list": res,
+			},
+		})
 	} else if form.Type == 3 {
 		var userAction []struct {
 			UserId    int    `json:"userId" gorm:"not null;column:userId;"`

+ 1 - 1
controller/v1/gameConfig.go

@@ -137,7 +137,7 @@ func SetGameAction(c *gin.Context) {
 	response.Success(c, gin.H{})
 }
 
-// 更新游戏的打点
+// 更新游戏中的事件
 func UpdateGameAction(c *gin.Context) {
 	form := request.Check(c, &struct {
 		Gid        string `form:"gid" json:"gid" binding:"required"`

+ 0 - 28
controller/v1/interfaceLog.go

@@ -84,34 +84,6 @@ func GetInterfaceLog(c *gin.Context) {
 
 // 获取所有的接口,以及接口的名字
 func GetInterfaceInfo(c *gin.Context) {
-
-	//router.Use(middleware.Logmiddleware())
-	//router.POST("/v1/user/login", v1.Login)                                                        //游戏登录
-	//router.POST("/v1/user/refreshToken", middleware.RefreshTokenAuthMiddleware(), v1.RefreshToken) //token刷新
-	//router.POST("/v1/user/addGidConfig", v1.AddGidConfig)
-	//router.POST("/v1/user/getGidConfig", v1.GetGidConfig)
-	//router.POST("/v1/user/getSysTime", v1.GetSysTime) //添加游戏配置数据
-	//
-	//router.POST("/v1/user/getTodayLog", v1.GetTodayLog)
-	//
-	//GroupV1 := router.Group("/v1")
-	//GroupV1.Use(middleware.TokenAuthMiddleware()).Use()
-	//{
-	//	GroupV1.POST("/user/getUserData", v1.GetUserData)                       //获取用户数据
-	//	GroupV1.POST("/user/setGameData", v1.SetGameData)                       //设置游戏数据
-	//	GroupV1.POST("/user/getGameData", v1.GetGameData)                       //获取游戏数据
-	//	GroupV1.POST("/user/setRankData", v1.SetRankData)                       //设置排行数据
-	//	GroupV1.POST("/user/getRankData", v1.GetRankData)                       //获取排行数据
-	//	GroupV1.POST("/user/updateUserInfo", v1.UpdateUserInfo)                 //更新用户数据
-	//	GroupV1.POST("/user/setProvinceRankData", v1.SetProvinceRankData)       //设置省内排行数据
-	//	GroupV1.POST("/user/getProvinceRankData", v1.GetProvinceRankData)       //获取排行数据
-	//	GroupV1.POST("/user/getProvinceRankSumData", v1.GetProvinceRankSumData) //获取省份排行数据
-	//	GroupV1.POST("/user/updateUserlocation", v1.UpdateUserlocation)         //更新位置数据
-	//
-	//	GroupV1.POST("/user/addUserToBlackList", v1.AddUserToBlackList)
-	//	GroupV1.POST("/user/deleteUserFormBlackList", v1.DeleteUserFormBlackList)
-	//	GroupV1.POST("/user/readBlackList", v1.ReadBlackList)
-
 	response.Success(c, gin.H{
 		"data": []struct {
 			Name string `json:"name"`

+ 17 - 0
controller/v1/user.go

@@ -9,6 +9,8 @@ import (
 	"designs/global"
 	"designs/service"
 	"designs/utils"
+	"fmt"
+	"go.mongodb.org/mongo-driver/v2/bson"
 	"strings"
 	"time"
 
@@ -225,3 +227,18 @@ func GetUserOnlineMsg(c *gin.Context) {
 		"data": res,
 	})
 }
+
+func UserBehaviorList(c *gin.Context) {
+	//form := request.Check(c, &struct {
+	//	Gid    string `form:"gid" json:"gid" binding:"required"`
+	//	Pf     string `form:"pf" json:"pf" binding:"required"`
+	//	Cid    string `form:"cid" json:"cid" binding:""`
+	//	Order  string `form:"order" json:"order" binding:""`
+	//	Search string `form:"search" json:"search" binding:""`
+	//}{})
+
+	collection := global.App.MongoDB.Database("testing").Collection("numbers")
+	res, _ := collection.InsertOne(context.Background(), bson.D{{"name", "pi"}, {"value", 3.14159}})
+	fmt.Println(res)
+
+}

+ 309 - 3
controller/v1/userBehavior.go

@@ -1,12 +1,17 @@
 package v1
 
 import (
+	"context"
 	"designs/app/common/request"
 	"designs/app/common/response"
 	"designs/global"
 	"designs/service"
 	"designs/utils"
+	"encoding/json"
+	"fmt"
 	"github.com/gin-gonic/gin"
+	"go.mongodb.org/mongo-driver/v2/bson"
+	"go.mongodb.org/mongo-driver/v2/mongo/options"
 	"math"
 	"time"
 )
@@ -128,7 +133,7 @@ func TimeDistributionData(c *gin.Context) {
 		}
 	} else if form.Type == 3 {
 		//启动次数
-		todayTimeDistribution, yesterdayTimeDistribution, yesterdayCount, todayCount, yesterdayThisTimeCount, err := service.GetActiveTimeDistribution(form.Pf, form.Gid)
+		todayTimeDistribution, yesterdayTimeDistribution, yesterdayCount, todayCount, yesterdayThisTimeCount, err := service.GetActionDistribution(form.Pf, form.Gid)
 		if err != nil {
 			response.Fail(c, 1001, err.Error())
 			return
@@ -159,7 +164,7 @@ func MouthDistributionData(c *gin.Context) {
 		Type int    `form:"type" json:"type" binding:"required"`
 	}{})
 	now := time.Now()
-	EndTime := now.Format("2006-01-02")
+	EndTime := now.AddDate(0, 0, 1).Format("2006-01-02")
 	StartTime := now.AddDate(0, 0, -29).Format("2006-01-02")
 
 	data := make(map[string]interface{})
@@ -299,6 +304,9 @@ func DataTrades(c *gin.Context) {
 		Type      int    `form:"type" json:"type" binding:"required"`
 	}{})
 	data := make(map[string]interface{})
+
+	form.EndTime = form.EndTime + " 23:59:59"
+
 	if form.Type == 1 {
 		//查询新增设备趋势图
 		TimeDistribution, count, avg, err := service.GetRegisterDayDistribution(form.Pf, form.Gid, form.StartTime, form.EndTime)
@@ -379,7 +387,7 @@ func DataTradesDetail(c *gin.Context) {
 		StartTime string `form:"startTime" json:"startTime" binding:"required"`
 		EndTime   string `form:"endTime" json:"endTime" binding:"required"`
 	}{})
-
+	form.EndTime = form.EndTime + " 23:59:59"
 	type dayData struct {
 		NewUser         int `json:"newUser"`
 		ActiveUser      int `json:"activeUser"`
@@ -389,6 +397,7 @@ func DataTradesDetail(c *gin.Context) {
 		AvgTime         int `json:"avgTime"`
 	}
 	var data = make(map[string]dayData)
+
 	//查询新增设备趋势图
 	NewUser, _, _, err := service.GetRegisterDayDistribution(form.Pf, form.Gid, form.StartTime, form.EndTime)
 	if err != nil {
@@ -463,3 +472,300 @@ func RemainDataBydDay(c *gin.Context) {
 		"data": data,
 	})
 }
+
+type AdData struct {
+	Pid           string `json:"pid"`
+	Aid           string `json:"aid"`
+	Cid           string `json:"cid"`
+	ReportUrl     string `json:"reportUrl"`
+	Reported      bool   `json:"reported"`
+	Duration      int64  `json:"duration"`
+	AdReqCount    uint8  `json:"adReqCount"`
+	AdEposedcount uint8  `json:"adEposedcount"`
+	CreateTime    int    `json:"createTime"`
+}
+
+type UserBehavior struct {
+	Id                 string      `bson:"_id,omitempty"`
+	Gid                string      `bson:"gid"`
+	Pf                 string      `bson:"pf"`
+	OpenId             string      `bson:"openId"`
+	AdData             interface{} `bson:"adData"`
+	AdFromCount        int         `bson:"adFromCount"`
+	TotalDuration      int         `bson:"totalDuration"`
+	TotalAdReqCount    int         `bson:"totalAdReqCount"`
+	TotalAdEposedCount int         `bson:"totalAdEposedCount"`
+}
+
+type BehaviorFilter struct {
+	Gt  int `json:"gt"`
+	Gte int `json:"gte"`
+	Lte int `json:"lte"`
+	Lt  int `json:"lt"`
+	Ne  int `json:"ne"`
+	//$gt 大于
+	//$gte:大于或等于
+	//$lt:小于
+	//$lte:小于或等于
+	//$ne:不等于
+}
+
+func BehaviorList(c *gin.Context) {
+	form := request.Check(c, &struct {
+		Gid    string `form:"gid" json:"gid" binding:"required"`
+		Pf     string `form:"pf" json:"pf" binding:"required"`
+		OpenId string `form:"search" json:"search" binding:""`
+		Offset int    `form:"offset" json:"offset" binding:""`
+		Limit  int    `form:"limit" json:"limit" binding:""`
+
+		Reported string `form:"reported" json:"reported" binding:""` //all true false
+		Pid      string `form:"pid" json:"pid" binding:""`
+		Aid      string `form:"aid" json:"aid" binding:""`
+		Cid      string `form:"cid" json:"cid" binding:""`
+
+		Duration      interface{} `form:"duration" json:"duration" binding:""`
+		AdReqCount    interface{} `form:"adReqCount" json:"adReqCount" binding:""`
+		AdEposedcount interface{} `form:"adEposedcount" json:"adEposedcount" binding:""`
+
+		AdFromCount        interface{} `form:"adFromCount" json:"adFromCount" binding:""`
+		TotalDuration      interface{} `form:"totalDuration" json:"totalDuration" binding:""`
+		TotalAdReqCount    interface{} `form:"totalAdReqCount" json:"totalAdReqCount" binding:""`
+		TotalAdEposedCount interface{} `form:"totalAdEposedCount" json:"totalAdEposedCount" binding:""`
+	}{})
+
+	collection := global.App.MongoDB.Database("chunhao").Collection("userBehavior")
+
+	ctx := context.Background()
+	filter := bson.M{"gid": form.Gid, "pf": form.Pf}
+
+	if form.OpenId != "" {
+		filter["openId"] = bson.M{"$regex": form.OpenId}
+	}
+	if form.Pid != "" {
+		filter["adData.pid"] = form.Pid
+	}
+	if form.Aid != "" {
+		filter["adData.aid"] = form.Aid
+	}
+	if form.Cid != "" {
+		filter["adData.cid"] = form.Cid
+	}
+
+	if form.AdFromCount != nil {
+		fmt.Println(form.AdFromCount)
+		marsh, _ := json.Marshal(form.AdFromCount)
+		var adFromCount BehaviorFilter
+		json.Unmarshal(marsh, &adFromCount)
+
+		filters := bson.M{}
+		if adFromCount.Gt != 0 {
+			filters["$gt"] = adFromCount.Gt
+		}
+		if adFromCount.Gte != 0 {
+			filters["$gte"] = adFromCount.Gte
+		}
+		if adFromCount.Lte != 0 {
+			filters["$lte"] = adFromCount.Lte
+		}
+		if adFromCount.Lt != 0 {
+			filters["$lt"] = adFromCount.Lt
+		}
+		if adFromCount.Lt != 0 {
+			filters["$ne"] = adFromCount.Ne
+		}
+
+		if len(filters) > 0 {
+			filter["adFromCount"] = filters
+		}
+	}
+
+	if form.TotalDuration != nil {
+		marsh, _ := json.Marshal(form.TotalDuration)
+		var totalDuration BehaviorFilter
+		json.Unmarshal(marsh, &totalDuration)
+
+		filters := bson.M{}
+		if totalDuration.Gt != 0 {
+			filters["$gt"] = totalDuration.Gt
+		}
+		if totalDuration.Gte != 0 {
+			filters["$gte"] = totalDuration.Gte
+		}
+		if totalDuration.Lte != 0 {
+			filters["$lte"] = totalDuration.Lte
+		}
+		if totalDuration.Lt != 0 {
+			filters["$lt"] = totalDuration.Lt
+		}
+		if totalDuration.Lt != 0 {
+			filters["$ne"] = totalDuration.Ne
+		}
+
+		if len(filters) > 0 {
+			filter["TotalDuration"] = filters
+		}
+	}
+
+	if form.TotalAdReqCount != nil {
+		marsh, _ := json.Marshal(form.TotalAdReqCount)
+		var totalAdReqCount BehaviorFilter
+		json.Unmarshal(marsh, &totalAdReqCount)
+
+		filters := bson.M{}
+		if totalAdReqCount.Gt != 0 {
+			filters["$gt"] = totalAdReqCount.Gt
+		}
+		if totalAdReqCount.Gte != 0 {
+			filters["$gte"] = totalAdReqCount.Gte
+		}
+		if totalAdReqCount.Lte != 0 {
+			filters["$lte"] = totalAdReqCount.Lte
+		}
+		if totalAdReqCount.Lt != 0 {
+			filters["$lt"] = totalAdReqCount.Lt
+		}
+		if totalAdReqCount.Lt != 0 {
+			filters["$ne"] = totalAdReqCount.Ne
+		}
+
+		if len(filters) > 0 {
+			filter["totalAdReqCount"] = filters
+		}
+	}
+
+	if form.TotalAdEposedCount != nil {
+		marsh, _ := json.Marshal(form.TotalAdEposedCount)
+		var totalAdEposedCount BehaviorFilter
+		json.Unmarshal(marsh, &totalAdEposedCount)
+
+		filters := bson.M{}
+		if totalAdEposedCount.Gt != 0 {
+			filters["$gt"] = totalAdEposedCount.Gt
+		}
+		if totalAdEposedCount.Gte != 0 {
+			filters["$gte"] = totalAdEposedCount.Gte
+		}
+		if totalAdEposedCount.Lte != 0 {
+			filters["$lte"] = totalAdEposedCount.Lte
+		}
+		if totalAdEposedCount.Lt != 0 {
+			filters["$lt"] = totalAdEposedCount.Lt
+		}
+		if totalAdEposedCount.Lt != 0 {
+			filters["$ne"] = totalAdEposedCount.Ne
+		}
+
+		if len(filters) > 0 {
+			filter["totalAdEposedCount"] = filters
+		}
+	}
+
+	if form.Duration != nil {
+		marsh, _ := json.Marshal(form.Duration)
+		var duration BehaviorFilter
+		json.Unmarshal(marsh, &duration)
+
+		filters := bson.M{}
+		if duration.Gt != 0 {
+			filters["$gt"] = duration.Gt
+		}
+		if duration.Gte != 0 {
+			filters["$gte"] = duration.Gte
+		}
+		if duration.Lte != 0 {
+			filters["$lte"] = duration.Lte
+		}
+		if duration.Lt != 0 {
+			filters["$lt"] = duration.Lt
+		}
+		if duration.Lt != 0 {
+			filters["$ne"] = duration.Ne
+		}
+
+		if len(filters) > 0 {
+			filter["adData.duration"] = filters
+		}
+	}
+
+	if form.AdReqCount != nil {
+		marsh, _ := json.Marshal(form.AdReqCount)
+		var adReqCount BehaviorFilter
+		json.Unmarshal(marsh, &adReqCount)
+
+		filters := bson.M{}
+		if adReqCount.Gt != 0 {
+			filters["$gt"] = adReqCount.Gt
+		}
+		if adReqCount.Gte != 0 {
+			filters["$gte"] = adReqCount.Gte
+		}
+		if adReqCount.Lte != 0 {
+			filters["$lte"] = adReqCount.Lte
+		}
+		if adReqCount.Lt != 0 {
+			filters["$lt"] = adReqCount.Lt
+		}
+		if adReqCount.Lt != 0 {
+			filters["$ne"] = adReqCount.Ne
+		}
+
+		if len(filters) > 0 {
+			filter["adData.adReqCount"] = filters
+		}
+	}
+
+	if form.AdEposedcount != nil {
+		marsh, _ := json.Marshal(form.AdEposedcount)
+		var adEposedcount BehaviorFilter
+		json.Unmarshal(marsh, &adEposedcount)
+
+		filters := bson.M{}
+		if adEposedcount.Gt != 0 {
+			filters["$gt"] = adEposedcount.Gt
+		}
+		if adEposedcount.Gte != 0 {
+			filters["$gte"] = adEposedcount.Gte
+		}
+		if adEposedcount.Lte != 0 {
+			filters["$lte"] = adEposedcount.Lte
+		}
+		if adEposedcount.Lt != 0 {
+			filters["$lt"] = adEposedcount.Lt
+		}
+		if adEposedcount.Lt != 0 {
+			filters["$ne"] = adEposedcount.Ne
+		}
+
+		if len(filters) > 0 {
+			filter["adData.adEposedcount"] = filters
+		}
+	}
+
+	option := options.Find()
+	option.SetLimit(int64(form.Limit))
+	option.SetSkip(int64(form.Offset))
+
+	cur, err := collection.Find(ctx, filter, option)
+	if err != nil {
+		response.Fail(c, 1001, err.Error())
+		return
+	}
+
+	count, err := collection.CountDocuments(ctx, filter)
+	if err != nil {
+		response.Fail(c, 1001, err.Error())
+		return
+	}
+
+	var data []UserBehavior
+	err = cur.All(ctx, &data)
+	if err != nil {
+		response.Fail(c, 1001, err.Error())
+		return
+	}
+
+	response.Success(c, gin.H{
+		"data":  data,
+		"count": count,
+	})
+}

+ 3 - 2
global/app.go

@@ -3,6 +3,7 @@ package global
 import (
 	"designs/utils"
 	"github.com/go-redis/redis/v8"
+	"go.mongodb.org/mongo-driver/v2/mongo"
 	"go.uber.org/zap"
 	"io"
 )
@@ -27,8 +28,8 @@ type Application struct {
 	//日志
 	Log       *zap.SugaredLogger
 	LogWriter io.Writer
-
-	PwdPath string
+	MongoDB   *mongo.Client
+	PwdPath   string
 }
 
 var (

+ 11 - 3
go.mod

@@ -14,7 +14,7 @@ require (
 	github.com/pkg/errors v0.9.1
 	github.com/sirupsen/logrus v1.9.3
 	go.uber.org/zap v1.27.0
-	golang.org/x/crypto v0.25.0
+	golang.org/x/crypto v0.27.0
 )
 
 require (
@@ -30,10 +30,12 @@ require (
 	github.com/go-playground/locales v0.14.1 // indirect
 	github.com/go-playground/universal-translator v0.18.1 // indirect
 	github.com/go-sql-driver/mysql v1.8.1 // indirect
+	github.com/golang/snappy v0.0.4 // indirect
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.5 // indirect
 	github.com/jonboulle/clockwork v0.4.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/klauspost/compress v1.13.6 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.8 // indirect
 	github.com/leodido/go-urn v1.4.0 // indirect
 	github.com/lestrrat-go/strftime v1.0.6 // indirect
@@ -43,11 +45,17 @@ require (
 	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 	github.com/ugorji/go/codec v1.2.12 // indirect
+	github.com/xdg-go/pbkdf2 v1.0.0 // indirect
+	github.com/xdg-go/scram v1.1.2 // indirect
+	github.com/xdg-go/stringprep v1.0.4 // indirect
+	github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
+	go.mongodb.org/mongo-driver/v2 v2.0.0-beta2 // indirect
 	go.uber.org/multierr v1.10.0 // indirect
 	golang.org/x/arch v0.8.0 // indirect
 	golang.org/x/net v0.27.0 // indirect
-	golang.org/x/sys v0.22.0 // indirect
-	golang.org/x/text v0.17.0 // indirect
+	golang.org/x/sync v0.8.0 // indirect
+	golang.org/x/sys v0.25.0 // indirect
+	golang.org/x/text v0.18.0 // indirect
 	google.golang.org/protobuf v1.34.2 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	gorm.io/driver/mysql v1.5.7 // indirect

+ 47 - 0
go.sum

@@ -42,8 +42,11 @@ github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
 github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
 github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
 github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
+github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
+github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
@@ -53,6 +56,8 @@ github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST
 github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
 github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
@@ -104,6 +109,17 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
 github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
 github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
 github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
+github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
+github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
+github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
+github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
+github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+go.mongodb.org/mongo-driver/v2 v2.0.0-beta2 h1:PRtbRKwblE8ZfI8qOhofcjn9y8CmKZI7trS5vDMeJX0=
+go.mongodb.org/mongo-driver/v2 v2.0.0-beta2/go.mod h1:UGLb3ZgEzaY0cCbJpH9UFt9B6gEXiTPzsnJS38nBeoU=
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
 go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
 go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
@@ -113,19 +129,50 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
 golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
 golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
 golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
 golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
+golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
+golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
 golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
 golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
+golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
 golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
 golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
 golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
 golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
+golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=

+ 9 - 0
main.go

@@ -1,6 +1,7 @@
 package main
 
 import (
+	"context"
 	"designs/bootstrap"
 	"designs/global"
 	"designs/middleware"
@@ -57,6 +58,14 @@ func main() {
 		}
 	}()
 
+	//初始化mongodb
+	global.App.MongoDB = bootstrap.InitializeMongo()
+	defer func() {
+		if global.App.MongoDB != nil {
+			global.App.MongoDB.Disconnect(context.Background())
+		}
+	}()
+
 	bootstrap.RunServer()
 	// ginServer.RunTLS(":443", "your_certificate.crt", "your_private_key.key")
 }

+ 2 - 0
route/api.go

@@ -60,5 +60,7 @@ func SetApiGroupRoutes(router *gin.RouterGroup) {
 		GroupV1.POST("/user/userActionList", v1.UserActionList)
 		GroupV1.POST("/user/userActionDetailDistribution", v1.UserActionDetailDistribution)
 
+		GroupV1.POST("/user/behaviorList", v1.BehaviorList)
+
 	}
 }

+ 2 - 1
service/remainData.go

@@ -5,6 +5,7 @@ import (
 	"designs/model"
 	"designs/utils"
 	"github.com/pkg/errors"
+	"math"
 	"time"
 )
 
@@ -91,7 +92,7 @@ func RemainDataBydDay(types int, pf string, gid string, startTime string, endTim
 			if !ok {
 				continue
 			}
-			remain[remainDays] = int(utils.IntersectionRate(v, loginDay) * 100)
+			remain[remainDays] = math.Round(utils.IntersectionRate(v, loginDay)*100*100) / 100
 		}
 
 		res[day] = remain

+ 94 - 1
service/userBehavior.go

@@ -144,11 +144,13 @@ func GetActiveTimeDistribution(pf string, gid string) (map[string]int, map[strin
 		Where("gid", gid).
 		Where("loginTime", ">", yesterday).
 		Where("loginTime", "<=", today).
-		Pluck("loginTime", &yesterdayRegisterModel).Error
+		Select("userId", "loginTime").
+		Scan(&yesterdayRegisterModel).Error
 	if err != nil {
 		global.App.Log.Error(err.Error())
 		return nil, nil, 0, 0, 0, err
 	}
+
 	var yesterdayCount int64
 	err = global.App.DB.Table("user_login").
 		Where("pf", pf).
@@ -174,6 +176,97 @@ func GetActiveTimeDistribution(pf string, gid string) (map[string]int, map[strin
 	}
 	yesterdayRegister := distinctUserHour(yesterdayRegisterModel)
 	yesterdayTimeDistribution := getTimeDistribution(yesterdayRegister, yesterdayHours)
+
+	todayTimeDistributionRes := make(map[string]int)
+	for k, v := range todayTimeDistribution {
+		todayTimeDistributionRes[timeDuration[k]] = v
+	}
+
+	yesterdayTimeDistributionRes := make(map[string]int)
+	for k, v := range yesterdayTimeDistribution {
+		yesterdayTimeDistributionRes[timeDuration[k]] = v
+	}
+
+	return todayTimeDistributionRes, yesterdayTimeDistributionRes, yesterdayCount, todayCount, yesterdayThisTimeCount, nil
+}
+
+// 启动次数的时段信息
+func GetActionDistribution(pf string, gid string) (map[string]int, map[string]int, int64, int64, int64, error) {
+	now := time.Now()
+	today := now.Format("2006-01-02")
+
+	hours := utils.GetDayHour(now)
+	var todayRegisterModel []time.Time
+
+	//计算今日曲线
+	err := global.App.DB.Table("user_login").
+		Where("pf", pf).
+		Where("gid", gid).
+		Where("loginTime", ">", today).
+		Select("userId", "loginTime").
+		Pluck("loginTime", &todayRegisterModel).Error
+	if err != nil {
+		global.App.Log.Error(err.Error())
+		return nil, nil, 0, 0, 0, err
+	}
+
+	//todayRegister := distinctUserHour(todayRegisterModel)
+
+	var todayCount int64
+	err = global.App.DB.Table("user_login").
+		Where("pf", pf).
+		Where("gid", gid).
+		Where("loginTime", ">", today).
+		Group("userId").Count(&todayCount).Error
+	if err != nil {
+		global.App.Log.Error(err.Error())
+		return nil, nil, 0, 0, 0, err
+	}
+	todayTimeDistribution := getTimeDistribution(todayRegisterModel, hours)
+
+	//计算昨日曲线
+	var yesterdayRegisterModel []time.Time
+
+	yesterdayHours := utils.GetDayHour(now.AddDate(0, 0, -1))
+	yesterday := now.AddDate(0, 0, -1).Format("2006-01-02")
+	yesterdayThisTime := now.AddDate(0, 0, -1).Format("2006-01-02 15:04:05")
+	err = global.App.DB.Table("user_login").
+		Where("pf", pf).
+		Where("gid", gid).
+		Where("loginTime", ">", yesterday).
+		Where("loginTime", "<=", today).
+		Pluck("loginTime", &yesterdayRegisterModel).Error
+	if err != nil {
+		global.App.Log.Error(err.Error())
+		return nil, nil, 0, 0, 0, err
+	}
+
+	var yesterdayCount int64
+	err = global.App.DB.Table("user_login").
+		Where("pf", pf).
+		Where("gid", gid).
+		Where("loginTime", ">", yesterday).
+		Where("loginTime", "<=", today).
+		Group("userId").Count(&yesterdayCount).Error
+	if err != nil {
+		global.App.Log.Error(err.Error())
+		return nil, nil, 0, 0, 0, err
+	}
+
+	var yesterdayThisTimeCount int64
+	err = global.App.DB.Table("user_login").
+		Where("pf", pf).
+		Where("gid", gid).
+		Where("loginTime", ">", yesterday).
+		Where("loginTime", "<=", yesterdayThisTime).
+		Group("userId").Count(&yesterdayCount).Error
+	if err != nil {
+		global.App.Log.Error(err.Error())
+		return nil, nil, 0, 0, 0, err
+	}
+	//yesterdayRegister := distinctUserHour(yesterdayRegisterModel)
+	yesterdayTimeDistribution := getTimeDistribution(yesterdayRegisterModel, yesterdayHours)
+
 	todayTimeDistributionRes := make(map[string]int)
 	for k, v := range todayTimeDistribution {
 		todayTimeDistributionRes[timeDuration[k]] = v

+ 13 - 2
utils/time.go

@@ -28,7 +28,13 @@ func GetDayHour(date time.Time) []int64 {
 func GetTimeDay(startDate string, endDate string) []int64 {
 	var days []int64
 	startTime, _ := time.Parse("2006-01-02", startDate)
-	endTime, _ := time.Parse("2006-01-02", endDate)
+
+	var endTime time.Time
+	if len(endDate) > 10 {
+		endTime, _ = time.Parse("2006-01-02  15:04:05", endDate)
+	} else {
+		endTime, _ = time.Parse("2006-01-02", endDate)
+	}
 
 	for currTime := startTime; !currTime.After(endTime); currTime = currTime.AddDate(0, 0, 1) {
 		// 设置时间为当天的开始时间
@@ -57,7 +63,12 @@ func GetTimeDayDate(startDate string, endDate string) map[string][]int {
 func GetTimeDayDateFormat(startDate string, endDate string) []string {
 	days := make([]string, 0)
 	startTime, _ := time.Parse("2006-01-02", startDate)
-	endTime, _ := time.Parse("2006-01-02", endDate)
+	var endTime time.Time
+	if len(endDate) > 10 {
+		endTime, _ = time.Parse("2006-01-02  15:04:05", endDate)
+	} else {
+		endTime, _ = time.Parse("2006-01-02", endDate)
+	}
 
 	for currTime := startTime; !currTime.After(endTime); currTime = currTime.AddDate(0, 0, 1) {
 		// 设置时间为当天的开始时间