123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- package service
- import (
- "bufio"
- "designs/config"
- "designs/global"
- "designs/model"
- "designs/utils"
- "fmt"
- "github.com/pkg/errors"
- "math"
- "os"
- "path/filepath"
- "strconv"
- "strings"
- "time"
- )
- func RemainDataBydDay(types int, pf string, gid string, startTime string, endTime string) (map[string]map[string]interface{}, error) {
- var err error
- start := time.Now()
- //对于传过来的endTime ,做一个处理
- t, _ := time.Parse("2006-01-02", endTime)
- endTimeData := t.AddDate(0, 0, 1).Format("2006-01-02")
- UsersBydDay := utils.GetTimeDayDate(startTime, endTime) //用户分别是在哪天注册的
- UserLoginBydDay := utils.GetTimeDayDate(startTime, endTime) //用户分别是在哪天注册的
- var UsersId []int
- userIdMap := make(map[int]bool)
- if types == 1 {
- //先计算出这个时间内 ,每天的注册用户数量
- var users []model.User
- err = global.App.DB.Table("user").
- Where("pf", pf).Where("gid", gid).
- Where("createdAt", ">=", startTime).
- Where("createdAt", "<=", endTimeData).
- Select("userId", "createdAt").
- Scan(&users).Error
- if err != nil {
- return nil, err
- }
- fmt.Printf("步骤2耗时: %v\n", time.Since(start))
- for _, user := range users {
- userIdMap[user.UserId] = true
- UsersBydDay[user.CreatedAt.Format("2006-01-02")] = append(UsersBydDay[user.CreatedAt.Format("2006-01-02")], user.UserId)
- }
- for user := range userIdMap {
- UsersId = append(UsersId, user)
- }
- users = nil //用完后清空内存
- } else if types == 2 {
- var users []model.UserLogin
- err = global.App.DB.Table("user_login").
- Where("pf", pf).Where("gid", gid).
- Where("loginTime", ">=", startTime).
- Where("loginTime", "<=", endTimeData).
- Group("userId").
- Scan(&users).Error
- if err != nil {
- return nil, err
- }
- for _, user := range users {
- UsersId = append(UsersId, user.UserId)
- UsersBydDay[user.LoginTime.Format("2006-01-02")] = append(UsersBydDay[user.LoginTime.Format("2006-01-02")], user.UserId)
- }
- } else {
- return nil, errors.New("type 参数错误")
- }
- //把每天的注册用户进行集合,查出后面所有天数的活跃情况
- var UserLogin []model.UserOnline
- //err = global.App.DB.Table("user_online_copy1 as user_online").
- // Where("pf", pf).Where("gid", gid).
- // Raw("USE INDEX (DATE)").
- // WhereIn("userId", UsersId).
- // Where("logTime", ">=", startTime).
- // Select("logTime", "user_online.userId").
- // Group("date,user_online.userId").
- // Scan(&UserLogin).Error
- //if err != nil {
- // return nil, err
- //}
- // 使用 Raw 方法执行带有 FORCE INDEX 的 SQL 查询
- query := `
- SELECT
- logTime,
- user_online.userId
- FROM
- user_online AS user_online USE INDEX (date)
- INNER JOIN (
- SELECT userId
- FROM user
- WHERE pf = ?
- AND gid = ?
- AND createdAt >= ?
- AND createdAt <= ?
- ) AS t ON t.userId = user_online.userId
- WHERE
- user_online.pf = ?
- AND user_online.gid = ?
- AND DATE(logTime) >= ?
- GROUP BY
- date,
- user_online.userId;
- `
- err = global.App.DB.Raw(query, pf, gid, startTime, endTime, pf, gid, startTime).Scan(&UserLogin).Error
- if err != nil {
- return nil, err
- }
- fmt.Printf("步骤3耗时: %v\n", time.Since(start))
- //对这些数据进行整理
- for _, v := range UserLogin {
- //根据天进行分组,得出总共有多少
- times := v.LogTime.Format("2006-01-02")
- UserLoginBydDay[times] = append(UserLoginBydDay[times], v.UserId)
- }
- res := make(map[string]map[string]interface{})
- //逐天比较注册的数据和留存的数据,得出每天的活跃比例和人数
- for day, v := range UsersBydDay {
- remain := make(map[string]interface{})
- remain["count"] = len(v)
- remain["date"] = day
- //分别比较每一天的数据
- for dayDate, loginDay := range UserLoginBydDay {
- ok, remainDays := utils.CompareDates(dayDate, day)
- if !ok {
- continue
- }
- remain[remainDays] = math.Round(utils.IntersectionRate(v, loginDay)*100*100) / 100
- }
- res[day] = remain
- }
- fmt.Printf("步骤4耗时: %v\n", time.Since(start))
- return res, nil
- }
- func RemainDataBydDayNew(types int, pf string, gid string, startTime string, endTime string) (map[string]map[string]interface{}, error) {
- //目前只有types = 1
- //对于传过来的endTime ,做一个处理
- t, _ := time.Parse("2006-01-02", endTime)
- endTimeData := t.AddDate(0, 0, 1).Format("2006-01-02")
- UsersBydDay := utils.GetTimeDayDate(startTime, endTime) //用户分别是在哪天注册的
- //先计算出这个时间内 ,每天的注册用户数量
- var users []model.User
- err := global.App.DB.Table("user").
- Where("pf", pf).Where("gid", gid).
- Where("createdAt", ">=", startTime).
- Where("createdAt", "<=", endTimeData).
- Select("userId", "createdAt").
- Scan(&users).Error
- if err != nil {
- return nil, err
- }
- var UsersId []int
- userIdMap := make(map[int]bool)
- for _, user := range users {
- userIdMap[user.UserId] = true
- UsersBydDay[user.CreatedAt.Format("2006-01-02")] = append(UsersBydDay[user.CreatedAt.Format("2006-01-02")], user.UserId)
- }
- for user := range userIdMap {
- UsersId = append(UsersId, user)
- }
- UserLoginBydDay := utils.GetTimeDayDate(startTime, endTime) //用户分别是在哪天注册的
- for k, _ := range UserLoginBydDay {
- //根据pf,gid,startTime,endTime 取出数据
- UserLoginBydDay[k] = GetLocalActiveLog(gid, pf, k)
- }
- res := make(map[string]map[string]interface{})
- for day, v := range UsersBydDay {
- remain := make(map[string]interface{})
- remain["count"] = len(v)
- remain["date"] = day
- //分别比较每一天的数据
- for dayDate, loginDay := range UserLoginBydDay {
- ok, remainDays := utils.CompareDates(dayDate, day)
- if !ok {
- continue
- }
- remain[remainDays] = math.Round(utils.IntersectionRate(v, loginDay)*100*100) / 100
- }
- res[day] = remain
- }
- return res, nil
- }
- func OnlineToFile() {
- //分批读取数据
- now := time.Now()
- for i := 1; i <= 45; i++ {
- var onlineData []model.UserOnline
- date := now.AddDate(0, 0, -i).Format("20060102")
- global.App.DB.Table("user_online_old").Where("date", date).Scan(&onlineData)
- //根据gid和pf,分文件存储
- for _, v := range onlineData {
- SetLocalActiveLog(v.Gid, v.Pf, "", v.UserId, v.Type, v.LogTime)
- }
- fmt.Println(date, "数据归档完成,耗时:", time.Since(now))
- }
- //var onlineData []model.UserOnline
- //
- //date := "20250423"
- //
- //global.App.DB.Table("user_online").Where("date", date).Scan(&onlineData)
- //
- ////根据gid和pf,分文件存储
- //for _, v := range onlineData {
- // SetLocalActiveLog(v.Gid, v.Pf, "", v.UserId, v.Type, v.LogTime)
- //}
- }
- func SetLocalActiveLog(gid string, pf string, openId string, userId int, types int, now time.Time) error {
- // 生成日期目录路径(示例:./data/2024-06-15)
- dateDir := now.Format("2006-01-02")
- dirPath := filepath.Join("storage", dateDir)
- // 创建日期目录(若不存在)
- if err := os.MkdirAll(dirPath, 0755); err != nil {
- return err
- }
- // 生成文件名(示例:g123_wechat.txt)
- fileName := fmt.Sprintf("%s_%s.txt", gid, pf)
- filePath := filepath.Join(dirPath, fileName)
- // 追加写入文件
- file, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
- if err != nil {
- return fmt.Errorf("failed to open file: %v", err)
- }
- defer file.Close()
- // 写入数据(示例:1584,oXyZ123456\n)
- if _, err := fmt.Fprintf(file, "%d,%d,%s\n", userId, types, now.Format("2006-01-02 15:04:05")); err != nil {
- return fmt.Errorf("failed to write file: %v", err)
- }
- return nil
- }
- func GetLocalActiveLog(gid string, pf string, date string) []int {
- var dir string
- if config.Get("app.local") == "local" {
- //url = "mongodb://localhost:27017"
- dir = "storage"
- } else {
- dir = "/www/wwwroot/chunhao_receive/storage"
- }
- dirPath := filepath.Join(dir, date)
- fileName := fmt.Sprintf("%s_%s.txt", gid, pf)
- filePath := filepath.Join(dirPath, fileName)
- file, _ := os.Open(filePath)
- defer file.Close() // 确保函数结束时关闭文件
- // 创建 Scanner 对象
- scanner := bufio.NewScanner(file)
- var res []int
- // 逐行读取文件内容
- lineNumber := 1
- for scanner.Scan() {
- line := scanner.Text() // 获取当前行内容
- lineNumber++
- userId, _ := strconv.Atoi(strings.Split(line, ",")[0])
- if !utils.InArray(userId, res) {
- res = append(res, userId)
- }
- }
- return res
- }
|