Files
stat_center/service/statSer/channelCodeStat.go
T
2026-05-20 16:13:58 +08:00

718 lines
22 KiB
Go

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:<nil>;"
}
if appId != nil {
key += fmt.Sprintf("appId:%d;", *appId)
} else {
key += "appId:<nil>;"
}
if start != nil {
key += fmt.Sprintf("start:%v;", *start)
} else {
key += "start:<nil>;"
}
if end != nil {
key += fmt.Sprintf("end:%v;", *end)
} else {
key += "end:<nil>;"
}
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
}