package statSer import ( "context" "fmt" "os" "path" "sort" "stat/api/proto" "stat/common/log" "stat/common/stdLog" "stat/common/utils" "stat/models/channelCodeBlocStatMod" "stat/models/channelmod" "time" "github.com/360EntSecGroup-Skylar/excelize" "go.mongodb.org/mongo-driver/bson" ) // // 获取渠道码统计信息列表 // func ListChannelCodeStat(ctx context.Context, param proto.ListChannelCodeStatReq) (code stdLog.CodeType, data interface{}, err error) { // resp := proto.ListChannelCodeStatRes{ // Total: 0, // List: make([]proto.ChannelCodeStatInfo, 0), // } // // 获取需要过滤的渠道信息 // channels1 := make([]string, 0) // if param.Channel != nil { // // 获取渠道信息 // channelInfo, err := channelmod.GetChannelInfoByChannel(ctx, *param.Channel) // if err != nil { // code = stdLog.ChannelNotExists // return code, data, err // } // if channelInfo.Channel == "" { // code = stdLog.Success // return code, resp, nil // } // // 获取子渠道 // if channelInfo.ParentChannel == "" { // chList, err := channelmod.GetAllChildChannel(ctx, channelInfo.Channel) // if err != nil { // code = stdLog.Failure // return code, data, err // } // for _, v := range chList { // channels1 = append(channels1, v.Channel) // } // } // channels1 = append(channels1, channelInfo.Channel) // } // channels2 := make([]string, 0) // // 根据渠道备注,获取渠道信息 // if param.ChannelRemark != nil { // // 获取渠道 // chList, err := channelmod.GetChannelByRemark(ctx, *param.ChannelRemark) // if err != nil { // code = stdLog.Failure // return code, data, err // } // if len(chList) == 0 { // code = stdLog.Success // return code, resp, nil // } // for _, v1 := range chList { // // 获取子渠道 // if v1.ParentChannel == "" && len(v1.Channel) > 0 { // chList, err := channelmod.GetAllChildChannel(ctx, v1.Channel) // if err != nil { // code = stdLog.Failure // return code, data, err // } // for _, v2 := range chList { // channels2 = append(channels2, v2.Channel) // } // } // channels2 = append(channels2, v1.Channel) // } // } // channels := make([]string, 0) // // 合并 // if param.Channel != nil && param.ChannelRemark != nil { // for _, ch1 := range channels1 { // for _, ch2 := range channels2 { // if ch1 == ch2 { // channels = append(channels, ch1) // } // } // } // } else if param.Channel != nil && param.ChannelRemark == nil { // channels = channels1 // } else if param.Channel == nil && param.ChannelRemark != nil { // channels = channels2 // } // codes1 := make([]string, 0) // // 获取渠道的渠道码 // if len(channels) > 0 { // codeList, err := channelCodeMod.GetChannelCodesByChannels(ctx, channels) // if err != nil { // code = stdLog.Failure // return code, data, err // } // for _, v := range codeList { // codes1 = append(codes1, v.ChannelCode) // } // } // codes := make([]string, 0) // // 只搜索渠道码 // if param.ChannelCode != nil && param.Channel == nil && param.ChannelRemark == nil { // codes = append(codes, *param.ChannelCode) // } else if param.ChannelCode != nil && (param.Channel != nil || param.ChannelRemark != nil) { // codes2 := make([]string, 0) // for _, v := range codes1 { // if v == *param.ChannelCode { // codes2 = []string{*param.ChannelCode} // break // } // } // if len(codes2) == 0 { // code = stdLog.Success // return code, resp, nil // } // codes = codes2 // } else { // codes = codes1 // } // skip, limit := utils.ToDBPage(param.PageNum, param.PageSize) // total, statList, err := channelCodeStatMod.GetChannelCodeStatList(ctx, codes, 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 := channelSer.MakeAppInfosMapByIds(ctx, appIds) // if err != nil { // code = stdLog.Failure // return // } // codeList, err := channelCodeMod.GetChannelCodesByIds(ctx, appIds) // if err != nil { // code = stdLog.Failure // return // } // appInfoCodeMap := make(map[string]*channelCodeMod.ChannelCode) // for _, v := range codeList { // _v := v // appInfoCodeMap[v.ChannelCode+fmt.Sprintf("%d", v.AppId)] = &_v // } // for _, v := range statList { // appName := "" // if appInfo, ok := appInfoMap[v.AppId]; ok { // appName = appInfo.Name // } // channel := "" // settlement := channelmod.SettlementCPA // rate := float64(0.8) // if channelCodeInfo, ok := appInfoCodeMap[v.ChannelCode+fmt.Sprintf("%d", v.AppId)]; ok { // channel = channelCodeInfo.Channel // channelInfo, _ := channelmod.GetChannelInfoByChannel(ctx, channel) // if channelInfo.Channel == channel { // settlement = channelCodeInfo.Settlement // if settlement == channelmod.SettlementCPS { // rate = float64(channelInfo.CPSRate) / 100 // } else { // rate = float64(channelInfo.CPAPrice) // } // } // } else { // 官方活没收益 // rate = float64(200) // } // tmp := proto.ChannelCodeStatInfo{ // SumDate: v.SumDate, // ChannelCode: v.ChannelCode, // AppId: v.AppId, // AppName: appName, // Channel: channel, // Settlement: settlement, // NewDirectCount: v.NewDirectCount, // NewFissionCount: v.NewFissionCount, // NewDeductionCount: v.NewDeductionCount, // DirectVisitCount: v.DirectVisitCount, // FissionVisitCount: v.FissionVisitCount, // Day1RetainRate: v.Day1RetainRate, // Day3RetainRate: v.Day3RetainRate, // Day7RetainRate: v.Day7RetainRate, // Recharge: v.DirectAmount, // FissionAmount: v.FissionAmount, // DeductionAmount: v.DeductionAmount, // NewRechargeCount: v.NewRechargeCount, // NewRechargeAmount: v.NewRechargeAmount, // LandPageVisitCount: v.LandPageVisitCount, // TotalAmount: v.DirectAmount + v.FissionAmount + v.DeductionAmount, // TotalNewCount: v.NewDirectCount + v.NewFissionCount + v.NewDeductionCount, // IncomeRate: float64(0.0), // UpdatedAt: v.UpdatedAt, // } // if settlement == channelmod.SettlementCPS { // tmp.CPSRate = rate // channelIncome := float64(v.DirectAmount) * rate // if channelIncome > 0 { // tmp.IncomeRate, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", (float64(tmp.Recharge+tmp.DeductionAmount+tmp.FissionAmount))/channelIncome), 64) // } // } else { // tmp.CPAPrice = rate / 100 // channelIncome := float64(v.NewDirectCount) * rate // if channelIncome > 0 { // tmp.IncomeRate, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", (float64(tmp.Recharge+tmp.DeductionAmount+tmp.FissionAmount))/channelIncome), 64) // } // } // resp.List = append(resp.List, tmp) // } // resp.Total = total // // 总量 // TotalList, err := channelCodeStatMod.GetChannelCodeStatListTotal(ctx, codes, param.AppId, param.StartTime, param.EndTime) // if err != nil { // log.Error("GetChannelCodeStatListTotal", log.E(err)) // code = stdLog.Failure // return // } // toatlSum := proto.ChannelCodeStatInfo{ // IncomeRate: float64(0.0), // } // for _, valueInfo := range TotalList { // toatlSum.NewDirectCount += valueInfo.NewDirectCount // toatlSum.NewFissionCount += valueInfo.NewFissionCount // toatlSum.NewDeductionCount += valueInfo.NewDeductionCount // toatlSum.DirectVisitCount += valueInfo.DirectVisitCount // toatlSum.FissionVisitCount += valueInfo.FissionVisitCount // toatlSum.Day1RetainRate += valueInfo.Day1RetainRate // toatlSum.Day3RetainRate += valueInfo.Day3RetainRate // toatlSum.Day7RetainRate += valueInfo.Day7RetainRate // toatlSum.Recharge += valueInfo.DirectAmount // toatlSum.FissionAmount += valueInfo.FissionAmount // toatlSum.DeductionAmount += valueInfo.DeductionAmount // toatlSum.NewRechargeCount += valueInfo.NewRechargeCount // toatlSum.NewRechargeAmount += valueInfo.NewRechargeAmount // toatlSum.LandPageVisitCount += valueInfo.LandPageVisitCount // toatlSum.TotalAmount += (valueInfo.DirectAmount + valueInfo.FissionAmount + valueInfo.DeductionAmount) // toatlSum.TotalNewCount += (valueInfo.NewDirectCount + valueInfo.NewFissionCount + valueInfo.NewDeductionCount) // } // resp.TotalInfo = toatlSum // data = resp // code = stdLog.Success // return // } // // 代理商获取渠道码统计信息列表 // func ListChannelCodeStatAgent(ctx context.Context, account string, param proto.ListChannelCodeStatAgentReq) (code stdLog.CodeType, data interface{}, err error) { // resp := proto.ListChannelCodeStatAgentRes{ // Total: 0, // List: make([]proto.ChannelCodeStatAgentInfo, 0), // } // // 获取渠道信息 // channelInfo, err := channelmod.GetChannelInfoByAccount(ctx, account) // if err != nil || channelInfo.Channel == "" { // code = stdLog.AgentAccountNotExists // return // } // // 获取子渠道 // childChannels, err := channelmod.GetAllChildChannel(ctx, channelInfo.Channel) // if err != nil || channelInfo.Channel == "" { // code = stdLog.Failure // return // } // channels := make([]string, 0) // for _, v := range childChannels { // channels = append(channels, v.Channel) // } // channels = append(channels, channelInfo.Channel) // // 获取渠道的渠道码 // codeList, err := channelCodeMod.GetChannelCodesByChannels(ctx, channels) // if err != nil { // code = stdLog.Failure // return // } // codes := make([]string, 0) // channelCodeMap := make(map[string]string) // if param.ChannelCode != nil { // codes = append(codes, *param.ChannelCode) // for _, v := range codeList { // channelCodeMap[v.ChannelCode+fmt.Sprintf("%d", v.AppId)] = v.Channel // } // } else { // for _, v := range codeList { // codes = append(codes, v.ChannelCode) // channelCodeMap[v.ChannelCode+fmt.Sprintf("%d", v.AppId)] = v.Channel // } // } // skip, limit := utils.ToDBPage(param.PageNum, param.PageSize) // total, statList, err := channelCodeStatMod.GetChannelCodeStatAgentList(ctx, codes, *param.AppId, param.StartTime, param.EndTime, skip, limit) // if err != nil { // code = stdLog.Failure // return // } // for _, v := range statList { // channelName, ok := channelCodeMap[v.ChannelCode+fmt.Sprintf("%d", v.AppId)] // if !ok { // 只能查询渠道下面的渠道码 // continue // } // tmp := proto.ChannelCodeStatAgentInfo{ // SumDate: v.SumDate, // ChannelCode: v.ChannelCode, // Channel: channelName, // NewDirectCount: v.NewDirectCount, // Recharge: v.DirectAmount, // } // // CPA子渠道不显示充值金额 // if channelInfo.ParentChannel != "" && channelInfo.Settlement == channelmod.SettlementCPA { // tmp.Recharge = 0 // } // resp.List = append(resp.List, tmp) // } // totalStatList, err := channelCodeStatMod.GetChannelCodeStatAgentListTotal(ctx, codes, *param.AppId, param.StartTime, param.EndTime) // if err != nil { // code = stdLog.Failure // return // } // totalCount := int64(0) // totalAmount := int64(0) // for _, v := range totalStatList { // _, ok := channelCodeMap[v.ChannelCode+fmt.Sprintf("%d", v.AppId)] // if !ok { // 只能查询渠道下面的渠道码 // continue // } // // CPA子渠道不显示充值金额 // if channelInfo.ParentChannel != "" && channelInfo.Settlement == channelmod.SettlementCPA { // totalAmount = 0 // } else { // totalAmount += v.DirectAmount // } // totalCount += v.NewDirectCount // } // resp.Total = total // resp.TotalAmount = totalAmount // resp.TotalCount = totalCount // data = resp // code = stdLog.Success // return // } func CacheKey(channel *string, appId *int32, start, end *time.Time) string { key := "" if channel != nil { key += fmt.Sprintf("channel:%s;", *channel) } else { key += "channel:;" } if appId != nil { key += fmt.Sprintf("appId:%d;", *appId) } else { key += "appId:;" } if start != nil { key += fmt.Sprintf("start:%v;", *start) } else { key += "start:;" } if end != nil { key += fmt.Sprintf("end:%v;", *end) } else { key += "end:;" } return key } // 获取渠道码统计信息列表(集团) func ListBlocChannelCodeStat(ctx context.Context, param *proto.BlocListChannelCodeStatReq) (code stdLog.CodeType, data interface{}, err error) { resp := proto.BlocListChannelCodeStatRes{ Total: 0, List: make([]proto.BlocChannelCodeStatInfo, 0), } if param.Channel != nil && *param.Channel == channelmod.OfficialChannelDisplayName { tmp := channelmod.OfficialChannelName param.Channel = &tmp } // 获取渠道的渠道码 skip, limit := utils.ToDBPage(param.PageNum, param.PageSize) total, statList, err := channelCodeBlocStatMod.GetBlocChannelCodeBlocStatList(ctx, param.Channel, 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 } childstatList := make([]*channelCodeBlocStatMod.ChannelCodeBlocStat, 0) if param.WithChild != nil && param.Channel != nil && len(*param.Channel) > 0 { childChannelList, _ := channelmod.FindManyChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.ParentChannel: *param.Channel}) if len(childChannelList) > 0 { channelArray := make([]string, 0) for _, v := range childChannelList { channelArray = append(channelArray, v.Channel) } _, childstatList, _ = channelCodeBlocStatMod.GetBlocChannelCodeStatTotal(ctx, channelArray, param.AppId, param.StartTime, param.EndTime) } // 汇总排序 (存在一级没有 二级存在的情况) for _, childinfo := range childstatList { find := false for _, v := range statList { if v.SumDate.Equal(childinfo.SumDate) { find = true } } if !find { childinfo.ChannelCode = *param.Channel statList = append(statList, childinfo) } } sort.Sort(statList) } // get channels channels := make([]string, 0, len(statList)) for _, item := range statList { channels = append(channels, item.ChannelCode) } ruleMap, err := MakeRuleMap(ctx, channels) if err != nil { code = stdLog.Failure return } //组装 按照时间排序 for _, v := range statList { appName := "" if appInfo, ok := appInfoMap[v.AppId]; ok { appName = appInfo.Name } for _, childinfo := range childstatList { if v.SumDate.Equal(childinfo.SumDate) { v.NewDirectCount += childinfo.NewDirectCount v.NewFissionCount += childinfo.NewFissionCount v.NewDeductionCount += childinfo.NewDeductionCount v.DirectVisitCount += childinfo.DirectVisitCount v.FissionVisitCount += childinfo.FissionVisitCount v.DeductionAmount += childinfo.DeductionAmount v.DirectAmount += childinfo.DirectAmount v.FissionAmount += childinfo.FissionAmount } } tmp := proto.BlocChannelCodeStatInfo{ SumDate: v.SumDate, ChannelCode: channelmod.ChannelDisplayName(v.ChannelCode), AppId: v.AppId, AppName: appName, Channel: v.Channel, NewDirectCount: v.NewDirectCount, NewFissionCount: v.NewFissionCount, NewDeductionCount: v.NewDeductionCount, DirectVisitCount: v.DirectVisitCount, FissionVisitCount: v.FissionVisitCount, DeductionAmount: v.DeductionAmount, RechargeAmount: v.DirectAmount, FissionAmount: v.FissionAmount, UpdatedAt: v.UpdatedAt, } ruleinfo := ruleMap.GetRule(v.ChannelCode, v.AppId) if ruleinfo != nil { if ruleinfo.Settlement == channelmod.SettlementCPA { tmp.Settlement = fmt.Sprintf("CPA_%.2f", float64(ruleinfo.CPAPrice)/100) tmp.TodayIncome = tmp.NewDirectCount * ruleinfo.CPAPrice } else if ruleinfo.Settlement == channelmod.SettlementCPS { tmp.Settlement = fmt.Sprintf("CPS_%.2f", float64(ruleinfo.CPSRate)/100) tmp.TodayIncome = tmp.RechargeAmount * ruleinfo.CPSRate / 100 } else if ruleinfo.Settlement == channelmod.SettlementCPT { tmp.Settlement = "CPT" } else if ruleinfo.Settlement == channelmod.SettlementCPC { tmp.Settlement = "CPC" } } resp.List = append(resp.List, tmp) } resp.Total = total // 查询条件不为空时统计总量 if param.Channel != nil || param.AppId != nil || (param.StartTime != nil && param.EndTime != nil) { // 总量 TotalList, err := channelCodeBlocStatMod.GetBlocChannelCodeBlocStatListTotal(ctx, param.Channel, param.AppId, param.StartTime, param.EndTime) if err != nil { code = stdLog.Failure return code, nil, err } // get channels channels = make([]string, 0, len(TotalList)) for _, item := range TotalList { channels = append(channels, item.ChannelCode) } ruleMap, err = MakeRuleMap(ctx, channels) if err != nil { code = stdLog.Failure return code, nil, err } toatlSum := &proto.BlocChannelCodeStatInfo{} for _, valueInfo := range TotalList { toatlSum.NewDirectCount += valueInfo.NewDirectCount toatlSum.NewFissionCount += valueInfo.NewFissionCount toatlSum.DirectVisitCount += valueInfo.DirectVisitCount toatlSum.FissionVisitCount += valueInfo.FissionVisitCount toatlSum.RechargeAmount += valueInfo.DirectAmount toatlSum.DeductionAmount += valueInfo.DeductionAmount toatlSum.NewDeductionCount += valueInfo.NewDeductionCount ruleinfo := ruleMap.GetRule(valueInfo.ChannelCode, valueInfo.AppId) if ruleinfo != nil { if ruleinfo.Settlement == channelmod.SettlementCPA { toatlSum.TodayIncome += valueInfo.NewDirectCount * ruleinfo.CPAPrice } else if ruleinfo.Settlement == channelmod.SettlementCPS { toatlSum.TodayIncome += valueInfo.DirectAmount * ruleinfo.CPSRate / 100 } } } resp.TotalInfo = *toatlSum } data = resp code = stdLog.Success return } func ListBlocChannelExport(ctx context.Context, param *proto.BlocListChannelCodeStatReq) (string, error) { if param.Channel != nil && *param.Channel == channelmod.OfficialChannelDisplayName { tmp := channelmod.OfficialChannelName param.Channel = &tmp } // 获取渠道的渠道码 statList, err := channelCodeBlocStatMod.GetBlocChannelCodeBlocStatListTotal(ctx, param.Channel, param.AppId, param.StartTime, param.EndTime) if err != nil { return "", err } appIds := make([]int32, 0) for _, v := range statList { appIds = append(appIds, v.AppId) } appInfoMap, err := MakeAppInfosMapByIds(ctx, appIds) if err != nil { return "", err } // get channels channels := make([]string, 0, len(statList)) for _, item := range statList { channels = append(channels, item.ChannelCode) } ruleMap, err := MakeRuleMap(ctx, channels) if err != nil { return "", err } result := make([]*proto.BlocChannelCodeStatInfo, 0) for _, v := range statList { appName := "" if appInfo, ok := appInfoMap[v.AppId]; ok { appName = appInfo.Name } tmp := &proto.BlocChannelCodeStatInfo{ SumDate: v.SumDate, ChannelCode: channelmod.ChannelDisplayName(v.ChannelCode), AppId: v.AppId, AppName: appName, Channel: v.Channel, NewDirectCount: v.NewDirectCount, NewFissionCount: v.NewFissionCount, DirectVisitCount: v.DirectVisitCount, NewDeductionCount: v.NewDeductionCount, FissionVisitCount: v.FissionVisitCount, DeductionAmount: v.DeductionAmount, RechargeAmount: v.DirectAmount, FissionAmount: v.FissionAmount, UpdatedAt: v.UpdatedAt, } ruleinfo := ruleMap.GetRule(v.ChannelCode, v.AppId) if ruleinfo != nil { if ruleinfo.Settlement == channelmod.SettlementCPA { tmp.Settlement = fmt.Sprintf("CPA_%.2f", float64(ruleinfo.CPAPrice)/100) tmp.TodayIncome = tmp.NewDirectCount * ruleinfo.CPAPrice } else if ruleinfo.Settlement == channelmod.SettlementCPS { tmp.Settlement = fmt.Sprintf("CPS_%.2f", float64(ruleinfo.CPSRate)/100) tmp.TodayIncome = tmp.RechargeAmount * ruleinfo.CPSRate / 100 } else if ruleinfo.Settlement == channelmod.SettlementCPT { tmp.Settlement = "CPT" } else if ruleinfo.Settlement == channelmod.SettlementCPC { tmp.Settlement = "CPC" } } result = append(result, tmp) } filePath := fmt.Sprintf("./tmp/渠道列表-%s.xlsx", time.Now().Format("2006-01-02 15:04:05")) if err := export(ctx, filePath, result); err != nil { return "", err } return filePath, nil } func export(ctx context.Context, rPath string, channelStatList []*proto.BlocChannelCodeStatInfo) error { f := excelize.NewFile() sheetName := "Sheet1" idx := f.NewSheet(sheetName) var exportTransWaterTitle = map[string]string{} exportTransWaterTitle = map[string]string{ "A1": "日期", "B1": "渠道", "C1": "结算方式", "D1": "当日支出", "E1": "新增(直推)", "F1": "新增(裂变)", "G1": "新增(扣量)", "H1": "访问量", "I1": "直推充值金额", "J1": "裂变充值金额", } for k, v := range exportTransWaterTitle { f.SetCellValue(sheetName, k, v) } for k, v := range channelStatList { i := 'A' // i 不能超过Z,即列输不能超过26列,超出将出现bug f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.SumDate) i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.ChannelCode) i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.Settlement) i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), float64(v.TodayIncome)/100) i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.NewDirectCount) i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.NewFissionCount) i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.NewDeductionCount) i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.DirectVisitCount+v.FissionVisitCount) i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), float64(v.DeductionAmount)/100) i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), float64(v.FissionAmount)/100) } f.SetActiveSheet(idx) p, _ := os.Getwd() fileName := path.Join(p, rPath) if err := f.SaveAs(fileName); err != nil { log.Error("srv_vipcode:export save file to disk failed", log.Any("fileName", fileName), log.E(err)) return err } return nil }