package statSer import ( "bytes" "context" "fmt" "os" "path" "stat/api/proto" "stat/common/log" "stat/common/stdLog" "stat/common/utils" "stat/models/appInfoMod" "stat/models/blocDailystatmod" "stat/models/botdailyhourstat" "stat/models/channelmod" "stat/models/dailyhourstatmod" "stat/models/dailystatmod" "stat/models/minutestatmod" "stat/models/rechargemod" "stat/models/registermod" "stat/models/withdrawUserOrdermod" "strconv" "time" "github.com/360EntSecGroup-Skylar/excelize" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" ) // 获取日常统计信息列表 func ListDailyStat(ctx context.Context, param proto.ListDailyStatReq) (code stdLog.CodeType, data interface{}, err error) { resp := &proto.ListDailyStatRes{ Total: 0, TotalInfo: &proto.DailyStatInfo{}, List: make([]*proto.DailyStatInfo, 0), } skip, limit := utils.ToDBPage(param.PageNum, param.PageSize) total, statList, err := dailystatmod.GetDailyStatList(ctx, param.AppId, param.StartTime, param.EndTime, skip, limit) if err != nil { code = stdLog.Failure return } appIds := make([]int32, 0) for _, v := range statList { appIds = append(appIds, v.AppId) } appInfoMap, err := MakeAppInfosMapByIds(ctx, appIds) if err != nil { code = stdLog.Failure return } for _, v := range statList { appName := "" if appInfo, ok := appInfoMap[v.AppId]; ok { appName = appInfo.Name } tmp := DailyStatToInfo(v) tmp.AppName = appName resp.List = append(resp.List, tmp) } if param.AppId != nil || param.StartTime != nil || param.EndTime != nil { var count int err := dailystatmod.GetDailyStatTotalListShard(ctx, param.AppId, param.StartTime, param.EndTime, utils.GlobalShardMonth, func(item *dailystatmod.DailyStatMod) { count++ tmp := DailyStatToInfo(item) DailyStatInfoAccumulate(resp.TotalInfo, tmp) }) if err != nil { code = stdLog.Failure return code, nil, err } // 计算留存率平均值 if count > 0 { resp.TotalInfo.Day1RetainRate = resp.TotalInfo.Day1RetainRate / float64(count) resp.TotalInfo.Day3RetainRate = resp.TotalInfo.Day3RetainRate / float64(count) resp.TotalInfo.Day7RetainRate = resp.TotalInfo.Day7RetainRate / float64(count) } } resp.Total = total data = resp code = stdLog.Success return } // 获取日常统计信息列表 func ListDailyStatExport(ctx context.Context, param proto.ListDailyStatReq) (string, error) { skip, limit := utils.ToDBPage(param.PageNum, param.PageSize) _, statList, err := dailystatmod.GetDailyStatList(ctx, param.AppId, param.StartTime, param.EndTime, skip, limit) if err != nil { return "", err } filePath := fmt.Sprintf("./tmp/日常统计信息列表-%s.xlsx", time.Now().Format("2006-01-02 15:04:05")) if sErr := dailyStatexport(filePath, statList); sErr != nil { return "", sErr } return filePath, nil } func dailyStatexport(rPath string, transInfos []*dailystatmod.DailyStatMod) error { f := excelize.NewFile() sheetName := "Sheet1" // 设置列宽 f.SetColWidth("Sheet1", "A", "O", 20) // 设置表头行高 f.SetRowHeight("Sheet1", 1, 30) // 设置表头样式 headStyleID, _ := f.NewStyle(`{ "font":{ "color":"#333333", "bold":true, "size":16, "family":"arial" }, "alignment":{ "vertical":"center", "horizontal":"center" } }`) f.SetCellStyle("Sheet1", "A1", "O1", headStyleID) idx := f.NewSheet(sheetName) var exportTransWaterTitle = map[string]string{ "A1": "日期", "B1": "总日活", "C1": "android日活", "D1": "ios日活", "E1": "总新增", "F1": "android新增", "G1": "ios新增", "H1": "总充值", "I1": "android充值", "J1": "ios充值", "K1": "总新增H5", "L1": "渠道新增", "M1": "渠道总充值", "N1": "老用户总充值", "O1": "新用户总充值", "P1": "复充总金额", "Q1": "重充VIP总金额", "R1": "拉起订单数", "S1": "成功订单数", } for k, v := range exportTransWaterTitle { f.SetCellValue(sheetName, k, v) } for k, v := range transInfos { i := 'A' // i 不能超过Z,即列输不能超过26列,超出将出现bug date := v.SumDate.Local().Format("2006-01-02") f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), date) //日期 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.TotalVisitCount) //总日活 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.TotalVisitCount-(v.LightVisitCount+v.TodayH5VisitCount)) //android日活 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.LightVisitCount+v.TodayH5VisitCount) //ios日活 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.NewTotalCount) //总新增 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.NewTotalCount-(v.LightAddCount+v.H5AddCount)) //android总新增 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.LightAddCount+v.H5AddCount) //Ios总新增 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), float64(v.TotalAmount)/100) //总充值 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), float64(v.TodayAndroidRecharge)/100) //android充值 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), float64(v.TotalAmount)/100-float64(v.TodayAndroidRecharge)/100) //ios充值 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.H5AddCount) //总新增H5 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.NewDistrictCount) //渠道新增 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), float64(v.TodayDistrictRecharge)/100) //渠道总充值 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), float64(v.TotalAmount-v.NewRechargeAmount)/100) //老用户总充值 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), float64(v.NewRechargeAmount)/100) //新用户总充值 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), float64(v.RepeatAmount)/100) //复充总金额 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), float64(v.RepeatVipMoney)/100) //重充VIP总金额 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.TotalRechargeOrder) //拉起订单数 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.SuccessRechargeOrder) //成功订单数 } f.SetActiveSheet(idx) p, _ := os.Getwd() fileName := path.Join(p, rPath) if err := f.SaveAs(fileName); err != nil { log.Error("SettlementInfo:export save file to disk failed", log.Any("fileName", fileName), log.E(err)) return err } return nil } // 获取日常统计信息列表 func BlocListDailyStat(ctx context.Context, param proto.ListBlocDailyStatReq) (code stdLog.CodeType, data interface{}, err error) { resp := proto.ListBlocDailyStatRes{ Total: 0, List: make([]proto.BlocDailyStatInfo, 0), } skip, limit := utils.ToDBPage(param.PageNum, param.PageSize) total, statList, err := blocDailystatmod.GetBlocDailyStatList(ctx, param.AppId, param.StartTime, param.EndTime, skip, limit) if err != nil { code = stdLog.Failure return } appIds := make([]int32, 0) for _, v := range statList { appIds = append(appIds, v.AppId) } appInfoMap, err := MakeAppInfosMapByIds(ctx, appIds) if err != nil { code = stdLog.Failure return code, nil, err } for _, v := range statList { appName := "" if appInfo, ok := appInfoMap[v.AppId]; ok { appName = appInfo.Name } tmp := proto.BlocDailyStatInfo{ SumDate: v.SumDate, AppId: v.AppId, AppName: appName, NewDirectCount: v.NewDirectCount, NewFissionCount: v.NewFissionCount, DirectVisitCount: v.DirectVisitCount, FissionVisitCount: v.FissionVisitCount, Day1RetainRate: v.Day1RetainRate, Day3RetainRate: v.Day3RetainRate, Day7RetainRate: v.Day7RetainRate, DirectAmount: v.DirectAmount, FissionAmount: v.FissionAmount, NewRechargeCount: v.NewRechargeCount, NewRechargeAmount: v.NewRechargeAmount, DaichongAmout: v.DaichongAmout, OnlineAmount: v.OnlineAmount, UserWithDrawAmount: v.UserWithDrawAmount, UserWithDrawPaymoneyAmount: v.UserWithDrawPaymoneyAmount, GameRechageAmount: v.GameRechageAmount, GameWithdrawAmount: v.GameWithdrawAmount, TotalRechargeCount: v.TotalRechargeCount, UpdatedAt: v.UpdatedAt, } tmp.TotalVisitCount = v.DirectVisitCount + v.FissionVisitCount // 日活 tmp.TotalAmount = v.DirectAmount + v.FissionAmount // 总充值 tmp.TotalNewCount = v.NewDirectCount + v.NewFissionCount // 新增 tmp.OldRechargeAmount = tmp.TotalAmount - tmp.NewRechargeAmount // 老用户充值 total := v.DeductionAmountCount + v.DirectAmountCount + v.FissionAmountCount // 充值人数 if tmp.TotalAmount-tmp.DaichongAmout > 0 { tmp.OnlineAmount = tmp.TotalAmount - tmp.DaichongAmout } if tmp.TotalNewCount != 0 { tmp.NewRechargeRate, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", (float64(v.NewRechargeCount)/float64(tmp.TotalNewCount))*100), 64) } if tmp.TotalVisitCount != 0 { tmp.VisitRechargeRate, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", (float64(total)/float64(tmp.TotalVisitCount))*100), 64) } if total != 0 { tmp.ARPPU = (tmp.DirectAmount + tmp.FissionAmount) / total // 金额 } if tmp.TotalVisitCount != 0 { tmp.ARPU = tmp.TotalAmount / tmp.TotalVisitCount // 金额 } resp.List = append(resp.List, tmp) } if param.AppId != nil || param.StartTime != nil || param.EndTime != nil { // 过滤条件至少有一个,不然不统计总数 totalList, err := blocDailystatmod.GetBlocDailyStatListTotal(ctx, param.AppId, param.StartTime, param.EndTime) if err != nil { code = stdLog.Failure return code, nil, err } for _, v := range totalList { resp.TotalInfo.NewDirectCount += v.NewDirectCount resp.TotalInfo.NewFissionCount += v.NewFissionCount resp.TotalInfo.DirectVisitCount += v.DirectVisitCount resp.TotalInfo.FissionVisitCount += v.FissionVisitCount resp.TotalInfo.DirectAmount += v.DirectAmount resp.TotalInfo.FissionAmount += v.FissionAmount resp.TotalInfo.NewRechargeCount += v.NewRechargeCount resp.TotalInfo.NewRechargeAmount += v.NewRechargeAmount resp.TotalInfo.DaichongAmout += v.DaichongAmout resp.TotalInfo.UserWithDrawAmount += v.UserWithDrawAmount resp.TotalInfo.UserWithDrawPaymoneyAmount += v.UserWithDrawPaymoneyAmount resp.TotalInfo.GameRechageAmount += v.GameRechageAmount resp.TotalInfo.GameWithdrawAmount += v.GameWithdrawAmount resp.TotalInfo.TotalRechargeCount += v.TotalRechargeCount } resp.TotalInfo.TotalVisitCount = resp.TotalInfo.DirectVisitCount + resp.TotalInfo.FissionVisitCount // 日活 resp.TotalInfo.TotalAmount = resp.TotalInfo.DirectAmount + resp.TotalInfo.FissionAmount // 总充值 resp.TotalInfo.TotalNewCount = resp.TotalInfo.NewDirectCount + resp.TotalInfo.NewFissionCount // 新增 resp.TotalInfo.OldRechargeAmount = resp.TotalInfo.TotalAmount - resp.TotalInfo.NewRechargeAmount // 老用户充值 if resp.TotalInfo.TotalAmount-resp.TotalInfo.DaichongAmout > 0 { resp.TotalInfo.OnlineAmount = resp.TotalInfo.TotalAmount - resp.TotalInfo.DaichongAmout } } resp.Total = total data = resp code = stdLog.Success return } // 获取充值明细(集团) func BlocListRechargeDetailsInfo(ctx context.Context, param proto.ListBlocRechargeDetailsReq) (code stdLog.CodeType, data interface{}, err error) { resp := proto.ListBlocRechargeDetailsRes{ Total: 0, List: make([]proto.BlocRechargeDetailsInfo, 0), } skip, limit := utils.ToDBPage(param.PageNum, param.PageSize) total, RechagerList, err := rechargemod.GetBlocRechargeDetailsList(ctx, param.AppId, param.StartTime, param.EndTime, skip, limit) if err != nil { code = stdLog.Failure return } appIds := make([]int32, 0) appMap := make(map[int32]int32) for _, v := range RechagerList { if _, ok := appMap[v.AppId]; !ok { appMap[v.AppId] = v.AppId appIds = append(appIds, v.AppId) } } //fmt.Println(appIds) appInfoMap, err := MakeAppInfosMapByIds(ctx, appIds) if err != nil { code = stdLog.Failure return } for _, v := range RechagerList { appName := "" if appInfo, ok := appInfoMap[v.AppId]; ok { appName = appInfo.Name } tmp := proto.BlocRechargeDetailsInfo{ UserId: v.PromCode, AppName: appName, SysType: v.SysType, DevType: v.DevType, ChannelName: v.ChannelName, CID: v.CID, Type: v.Type, OrderId: v.OrderId, Money: v.Money, PayMoney: v.PayMoney, Status: 3, SuccessAt: v.SuccessAt, } resp.List = append(resp.List, tmp) } resp.Total = total data = resp code = stdLog.Success return } // 获取日常统计信息列表 func BlocListDailyTotalStat(ctx context.Context, param proto.ListBlocDailyStatTotalReq) (code stdLog.CodeType, data interface{}, err error) { resp := proto.ListBlocDailyStatTotalRes{ Total: 0, List: make([]proto.BlocDailyStatTotalInfo, 0), } skip, limit := utils.ToDBPage(param.PageNum, param.PageSize) statList, err := blocDailystatmod.GetBlocDailyStatTotalList(ctx, param.StartTime, param.EndTime) if err != nil { code = stdLog.Failure return } count := int64(0) for _, v := range statList { if count >= skip && count <= skip+limit { tmp := proto.BlocDailyStatTotalInfo{ SumDate: v.SumDate, NewDirectCount: v.NewDirectCount, NewFissionCount: v.NewFissionCount, DirectVisitCount: v.DirectVisitCount, FissionVisitCount: v.FissionVisitCount, DirectAmount: v.DirectAmount, FissionAmount: v.FissionAmount, NewRechargeCount: v.NewRechargeCount, NewRechargeAmount: v.NewRechargeAmount, DaichongAmout: v.DaichongAmout, OnlineAmount: v.OnlineAmount, UserWithDrawAmount: v.UserWithDrawAmount, UserWithDrawPaymoneyAmount: v.UserWithDrawPaymoneyAmount, GameRechageAmount: v.GameRechageAmount, GameWithdrawAmount: v.GameWithdrawAmount, TotalRechargeCount: v.TotalRechargeCount, } tmp.TotalVisitCount = v.DirectVisitCount + v.FissionVisitCount // 日活 tmp.TotalAmount = v.DirectAmount + v.FissionAmount // 总充值 tmp.TotalNewCount = v.NewDirectCount + v.NewFissionCount // 新增 tmp.OldRechargeAmount = tmp.TotalAmount - tmp.NewRechargeAmount // 老用户充值 if tmp.TotalAmount-tmp.DaichongAmout > 0 { tmp.OnlineAmount = tmp.TotalAmount - tmp.DaichongAmout } resp.List = append(resp.List, tmp) } count += 1 } resp.Total = count data = resp code = stdLog.Success return } // 获取充值明细(集团) func BlocListRegisterDetailsInfo(ctx context.Context, param proto.ListBlocRegisterDetailsReq) (code stdLog.CodeType, data interface{}, err error) { resp := proto.ListBlocRegisterDetailsRes{ Total: 0, List: make([]proto.BlocRegisterDetailsInfo, 0), } skip, limit := utils.ToDBPage(param.PageNum, param.PageSize) total, RechagerList, err := registermod.GetBlocRegisterDetailsList(ctx, param.AppId, param.StartTime, param.EndTime, skip, limit) if err != nil { code = stdLog.Failure return } appIds := make([]int32, 0) appMap := make(map[int32]int32) for _, v := range RechagerList { if _, ok := appMap[v.AppId]; !ok { appMap[v.AppId] = v.AppId appIds = append(appIds, v.AppId) } } appInfoMap, err := MakeAppInfosMapByIds(ctx, appIds) if err != nil { code = stdLog.Failure return } for _, v := range RechagerList { appName := "" if appInfo, ok := appInfoMap[v.AppId]; ok { appName = appInfo.Name } tmp := proto.BlocRegisterDetailsInfo{ UserId: v.PromCode, AppName: appName, SysType: v.SysType, DevType: v.DevType, Mobile: v.Mobile, IP: v.IP, Name: v.Name, IsDirect: v.IsDirect, RegisterTime: v.RegisterTime, } resp.List = append(resp.List, tmp) } resp.Total = total data = resp code = stdLog.Success return } // 获取提现明细(集团) func BlocListWithdrawDetailsInfo(ctx context.Context, param proto.ListBlocWithdrawDetailsReq) (code stdLog.CodeType, data interface{}, err error) { resp := proto.ListBlocWithdrawDetailsRes{ Total: 0, List: make([]proto.ListBlocWithdrawDetailsInfo, 0), } skip, limit := utils.ToDBPage(param.PageNum, param.PageSize) total, RechagerList, err := withdrawUserOrdermod.GetBlocUserWithdrawOrderList(ctx, param.AppId, param.StartTime, param.EndTime, skip, limit) if err != nil { code = stdLog.Failure return } appIds := make([]int32, 0) appMap := make(map[int32]int32) for _, v := range RechagerList { if _, ok := appMap[v.AppId]; !ok { appMap[v.AppId] = v.AppId appIds = append(appIds, v.AppId) } } //fmt.Println(appIds) appInfoMap, err := MakeAppInfosMapByIds(ctx, appIds) if err != nil { code = stdLog.Failure return } for _, v := range RechagerList { appName := "" if appInfo, ok := appInfoMap[v.AppId]; ok { appName = appInfo.Name } tmp := proto.ListBlocWithdrawDetailsInfo{ UID: v.PromCode, AppName: appName, Name: v.Name, Amount: v.Amount, Money: v.Money, PayMoney: v.PayMoney, PayType: v.PayType, OID: v.OID, ActName: v.ActName, Act: v.Act, UserIP: v.UserIP, DeviceType: v.DeviceType, DevID: v.DevID, Status: v.Status, StatusDesc: v.StatusDesc, SuccessAt: v.SuccessAt, ReceivedAt: v.ReceivedAt, } resp.List = append(resp.List, tmp) } resp.Total = total data = resp code = stdLog.Success return } // 获取提现明细(集团) func ListBlocRechargeChannelInfo(ctx context.Context, param proto.ListBlocRechargeChannelReq) (code stdLog.CodeType, data interface{}, err error) { resp := proto.ListBlocRechargeChannelRes{ Total: 0, List: make([]proto.ListBlocRechargeChannelInfo, 0), } skip, limit := utils.ToDBPage(param.PageNum, param.PageSize) statList, err := blocDailystatmod.GetBlocDailyStatTotalList(ctx, param.StartTime, param.EndTime) if err != nil { code = stdLog.Failure return } count := int64(0) for _, v := range statList { if count >= skip && count <= skip+limit { tmp := proto.ListBlocRechargeChannelInfo{ SumDate: v.SumDate, ChannelName: "大白鲨", BlocOrderMoney: v.DirectAmount + v.FissionAmount, BlocChannelRate: 12, } resp.List = append(resp.List, tmp) } count += 1 } resp.Total = count data = resp code = stdLog.Success return } func ListMinuteStat(ctx context.Context, param proto.ListMinuteStatReq) (code stdLog.CodeType, data interface{}, err error) { resp := proto.ListMinuteStatRes{ TodayGraphList: make([]proto.MinuteStatInfo, 0), } // 获取app信息 appInfo, err := appInfoMod.GetAppInfoById(ctx, *param.AppId) if err != nil { code = stdLog.Failure return } resp.AppInfo = proto.AppInfoRes{ AppId: appInfo.AppId, Name: appInfo.Name, LandPages: appInfo.LandPages, IconImg: appInfo.IconImg, CreatedAt: appInfo.CreatedAt, UpdatedAt: appInfo.UpdatedAt, } start := *param.SumDate end := start.AddDate(0, 0, 1) todayStatList, err := minutestatmod.GetMinuteStatList(ctx, start, end, *param.AppId) if err != nil { code = stdLog.Failure return } for _, v := range todayStatList { tmp := proto.MinuteStatInfo{ SumDate: v.SumDate, NewCount: v.NewCount, AndroidAddCount: v.AndroidAddCount, IosAddCount: v.IosAddCount, H5AddCount: v.H5AddCount, RechargetCount: v.RechargetCount, RechargetMoney: v.RechargetMoney, AccessCount: v.AccessCount, AndroidAccessCount: v.AndroidAccessCount, IosAccessCount: v.IosAccessCount + v.H5AccessCount, LandpageAndroidClick: v.LandpageAndroidClick, LandpageIosAppstoreClick: v.LandpageIosAppstoreClick, LandpageIosAthorClick: v.LandpageIosAthorClick, LandpageIosH5Click: v.LandpageIosH5Click, LightGuestAddCount: v.LightGuestAddCount, } resp.TodayGraphList = append(resp.TodayGraphList, tmp) } compareTime := start.AddDate(0, 0, -1) if param.CompareTime != nil { compareTime = *param.CompareTime } compareTimeEnd := compareTime.AddDate(0, 0, 1) yesterdayStatList, err := minutestatmod.GetMinuteStatList(ctx, compareTime, compareTimeEnd, *param.AppId) if err != nil { code = stdLog.Failure return } for _, v := range yesterdayStatList { tmp := proto.MinuteStatInfo{ SumDate: v.SumDate, NewCount: v.NewCount, AndroidAddCount: v.AndroidAddCount, IosAddCount: v.IosAddCount, H5AddCount: v.H5AddCount, RechargetCount: v.RechargetCount, RechargetMoney: v.RechargetMoney, AccessCount: v.AccessCount, AndroidAccessCount: v.AndroidAccessCount, IosAccessCount: v.IosAccessCount + v.H5AccessCount, LandpageAndroidClick: v.LandpageAndroidClick, LandpageIosAppstoreClick: v.LandpageIosAppstoreClick, LandpageIosAthorClick: v.LandpageIosAthorClick, LandpageIosH5Click: v.LandpageIosH5Click, LightGuestAddCount: v.LightGuestAddCount, } resp.YesterdayGraphList = append(resp.YesterdayGraphList, tmp) } data = resp code = stdLog.Success return } // 获取日常统计信息列表 func ListDailyHourStat(ctx context.Context, param *proto.ListDailyHourStatReq) (code stdLog.CodeType, data *proto.ListDailyHourStatRes, err error) { resp := &proto.ListDailyHourStatRes{ Total: 0, List: make([]*proto.DailyHourStatInfo, 0), } filter := bson.M{} opt := &options.FindOptions{} opt.SetSort(bson.M{dailyhourstatmod.FN.DailyHourStat.SumDate: -1}) opt.SetSkip((param.PageNum - 1) * param.PageSize) opt.SetLimit(param.PageSize) if param.AppId != nil { filter[dailyhourstatmod.FN.DailyHourStat.AppId] = *param.AppId } if param.StartTime != nil && param.EndTime != nil { filter[dailyhourstatmod.FN.DailyHourStat.SumDate] = bson.M{"$gte": *param.StartTime, "$lt": *param.EndTime} } if param.SumHour != nil { filter[dailyhourstatmod.FN.DailyHourStat.SumHour] = *¶m.SumHour } total, _ := dailyhourstatmod.CountDailyHourStats(ctx, filter) statList, err := dailyhourstatmod.FindManyDailyHourStat(ctx, filter, opt) if err != nil { code = stdLog.Failure return } appIds := make([]int32, 0) for _, v := range statList { appIds = append(appIds, v.AppId) } appInfoMap, err := MakeAppInfosMapByIds(ctx, appIds) if err != nil { code = stdLog.Failure return } for _, v := range statList { appName := "" if appInfo, ok := appInfoMap[v.AppId]; ok { appName = appInfo.Name } tmp := DailyHourStatToInfo(v) tmp.AppName = appName resp.List = append(resp.List, tmp) } resp.Total = total data = resp code = stdLog.Success return } // 获取日常统计信息列表 func ListDailyHourStatExport(ctx context.Context, param *proto.ListDailyHourStatReq) (*bytes.Buffer, error) { _, data, err := ListDailyHourStat(ctx, param) if err != nil { return nil, err } return ExportDailyHourStat(data.List) } func ListHourStatLine(ctx context.Context, param proto.ListHourStatLineReq) (code stdLog.CodeType, data interface{}, err error) { resp := proto.ListHourStatLineResp{ TodayGraphList: make([]proto.ListHourStatLineInfo, 0), YesterdayGraphList: make([]proto.ListHourStatLineInfo, 0), } // 获取app信息 appInfo, err := appInfoMod.GetAppInfoById(ctx, *param.AppId) if err != nil { code = stdLog.Failure return } resp.AppInfo = proto.AppInfoRes{ AppId: appInfo.AppId, Name: appInfo.Name, LandPages: appInfo.LandPages, IconImg: appInfo.IconImg, CreatedAt: appInfo.CreatedAt, UpdatedAt: appInfo.UpdatedAt, } start := *param.SumDate end := start.AddDate(0, 0, 1) todayFilter := bson.M{ "sumDate": bson.M{"$gte": start, "$lte": end}, "appId": *param.AppId, } todayStatList, err := botdailyhourstat.FindManyBotHourStat(ctx, todayFilter) if err != nil { code = stdLog.Failure return } for _, v := range todayStatList { tmp := proto.ListHourStatLineInfo{ SumDate: v.SumDate, HourNewDistrict: v.HourStat.Register.Total.District.Count, HourNewWeb: v.HourStat.Register.Total.Web.Count, HourNewNormal: v.HourStat.Register.Total.Normal.Count, HourNew: v.HourStat.Register.Count(), HourAndroidNew: v.HourStat.Register.Android.Count(), HourIosNew: v.HourStat.Register.Ios.Count(), HourDistrictRecharge: v.HourStat.Recharge.Total.District.Value, HourWebRecharge: v.HourStat.Recharge.Total.Web.Value, HourNormalRecharge: v.HourStat.Recharge.Total.Normal.Value, HourAndroidRecharge: v.HourStat.Recharge.Android.Value(), HourIosRecharge: v.HourStat.Recharge.Ios.Value(), HourVipRecharge: v.HourStat.RechargeVip.Value(), HourDistrictVip: v.HourStat.RechargeVip.Total.District.Value, HourWebVip: v.HourStat.RechargeVip.Total.Web.Value, HourNormalVip: v.HourStat.RechargeVip.Total.Normal.Value, } resp.TodayGraphList = append(resp.TodayGraphList, tmp) } compareTime := start.AddDate(0, 0, -1) if param.CompareTime != nil { compareTime = *param.CompareTime } compareTimeEnd := compareTime.AddDate(0, 0, 1) yestodayFilter := bson.M{ "sumDate": bson.M{"$gte": compareTime, "$lte": compareTimeEnd}, "appId": *param.AppId, } yesterdayStatList, err := botdailyhourstat.FindManyBotHourStat(ctx, yestodayFilter) if err != nil { code = stdLog.Failure return } for _, v := range yesterdayStatList { tmp := proto.ListHourStatLineInfo{ SumDate: v.SumDate, HourNewDistrict: v.HourStat.Register.Total.District.Count, HourNewWeb: v.HourStat.Register.Total.Web.Count, HourNewNormal: v.HourStat.Register.Total.Normal.Count, HourNew: v.HourStat.Register.Count(), HourAndroidNew: v.HourStat.Register.Android.Count(), HourIosNew: v.HourStat.Register.Ios.Count(), HourDistrictRecharge: v.HourStat.Recharge.Total.District.Value, HourWebRecharge: v.HourStat.Recharge.Total.Web.Value, HourNormalRecharge: v.HourStat.Recharge.Total.Normal.Value, HourAndroidRecharge: v.HourStat.Recharge.Android.Value(), HourIosRecharge: v.HourStat.Recharge.Ios.Value(), HourVipRecharge: v.HourStat.RechargeVip.Value(), HourDistrictVip: v.HourStat.RechargeVip.Total.District.Value, HourWebVip: v.HourStat.RechargeVip.Total.Web.Value, HourNormalVip: v.HourStat.RechargeVip.Total.Normal.Value, } resp.YesterdayGraphList = append(resp.YesterdayGraphList, tmp) } data = resp code = stdLog.Success return } // 获取日常统计信息列表 func ChannelStatExport(ctx context.Context, param proto.ChannelStatExportReq) (string, error) { statfilter := bson.M{} opt := &options.FindOptions{} opt.SetSort(bson.M{channelmod.FN.ChannelStat.SumDate: -1}) opt.SetLimit(5000) if param.AppId != nil && len(*param.AppId) > 0 { statfilter[channelmod.FN.ChannelStat.AppId] = bson.M{"$in": *param.AppId} } if param.Channel != nil { statfilter[channelmod.FN.ChannelStat.Channel] = *param.Channel } if param.StartTime != nil && param.EndTime != nil { statfilter[channelmod.FN.ChannelStat.SumDate] = bson.M{"$gte": *param.StartTime, "$lte": *param.EndTime} } statList, err := channelmod.FindManyChannelStat(ctx, statfilter, opt) if err != nil { return "", err } filePath := fmt.Sprintf("./tmp/渠道统计信息列表-%s.xlsx", time.Now().Format("2006-01-02 15:04:05")) if sErr := channelStatexport(filePath, statList); sErr != nil { return "", sErr } return filePath, nil } func channelStatexport(rPath string, statInfos channelmod.ChannelStatList) error { f := excelize.NewFile() sheetName := "Sheet1" // 设置列宽 f.SetColWidth("Sheet1", "A", "O", 20) // 设置表头行高 f.SetRowHeight("Sheet1", 1, 30) // 设置表头样式 headStyleID, _ := f.NewStyle(`{ "font":{ "color":"#333333", "bold":true, "size":16, "family":"arial" }, "alignment":{ "vertical":"center", "horizontal":"center" } }`) f.SetCellStyle("Sheet1", "A1", "O1", headStyleID) // 统计时间 app名称 所属渠道 总新增 总充值 idx := f.NewSheet(sheetName) var exportTransWaterTitle = map[string]string{ "A1": "日期", "B1": "APP名称", "C1": "渠道码", "D1": "总新增", "E1": "总充值", } for k, v := range exportTransWaterTitle { f.SetCellValue(sheetName, k, v) } appInfos, _ := appInfoMod.GetAllAppInfo(context.Background()) for k, v := range statInfos { i := 'A' // i 不能超过Z,即列输不能超过26列,超出将出现bug date := v.SumDate.Local().Format("2006-01-02") f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), date) //日期 i++ appName := "" for _, appInfo := range appInfos { if appInfo.AppId == v.AppId { appName = appInfo.Name } } f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), appName) //APP名称 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.Channel) //渠道吗 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.NewTotalCount) //总新增 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), float64(v.TotalAmount)/100) //总充值 } f.SetActiveSheet(idx) p, _ := os.Getwd() fileName := path.Join(p, rPath) if err := f.SaveAs(fileName); err != nil { log.Error("SettlementInfo:export save file to disk failed", log.Any("fileName", fileName), log.E(err)) return err } return nil }