@@ -0,0 +1,91 @@
|
||||
package statctrl
|
||||
|
||||
import (
|
||||
"91porn-server/common"
|
||||
"91porn-server/common/stderr"
|
||||
"91porn-server/models/commod"
|
||||
"91porn-server/models/s/statordermod"
|
||||
"91porn-server/web/service/statser"
|
||||
"github.com/gin-gonic/gin"
|
||||
"time"
|
||||
)
|
||||
|
||||
// OrderStats doc
|
||||
// @Summary 订单统计
|
||||
// @Description 订单统计
|
||||
// @Tags statctrl
|
||||
// @Accept mpfd,json
|
||||
// @Produce json,html
|
||||
// @Param pageNumber query integer true "当前页"
|
||||
// @Param pageSize query integer true "每页条数"
|
||||
// @Param type query integer true "订单类型"
|
||||
// @Param channel query string false "渠道"
|
||||
// @Param start query string false "开始时间UTC时间戳"
|
||||
// @Param end query string false "结束时间UTC时间戳"
|
||||
// @Success 200 {string} json "{"msg": "操作成功"}"
|
||||
// @Failure 400 {string} json "{"msg": "操作失败"}"
|
||||
// @Router /web/stats/order/list [get]
|
||||
func OrderStats(ctx *gin.Context) {
|
||||
type Query struct {
|
||||
Type *statordermod.OrderType `form:"type" json:"type"` //订单类型
|
||||
Channel *string `form:"channel" json:"channel"`
|
||||
Start *time.Time `form:"start" json:"start"`
|
||||
End *time.Time `form:"end" json:"end"`
|
||||
}
|
||||
var arg struct {
|
||||
commod.Page
|
||||
Query
|
||||
}
|
||||
if err := ctx.ShouldBind(&arg); err != nil {
|
||||
common.ServeJSON(ctx, stderr.ErrParamError, "stat VideoEarnStats arg error "+err.Error())
|
||||
return
|
||||
}
|
||||
endTime := time.Now()
|
||||
if arg.End != nil {
|
||||
endTime = *arg.End
|
||||
}
|
||||
var startTime time.Time
|
||||
if arg.Start != nil {
|
||||
startTime = *arg.Start
|
||||
}
|
||||
skip := int64((arg.PageNumber - 1) * arg.PageSize)
|
||||
limit := int64(arg.PageSize)
|
||||
page, err := statser.OrderPages(skip, limit,
|
||||
statser.OrderChannelMatch{arg.Channel},
|
||||
statser.OrderTypeMatch{arg.Type},
|
||||
statser.OrderSumDateGTEAndLTMatch{&startTime, &endTime},
|
||||
)
|
||||
if err != nil {
|
||||
common.ServeJSON(ctx, stderr.Failure, "statctrl OrderPages error: "+err.Error())
|
||||
return
|
||||
}
|
||||
common.ServeJSON(ctx, stderr.Success, page)
|
||||
}
|
||||
|
||||
// RchSucRate doc
|
||||
// @Summary 充值成功率
|
||||
// @Description 充值成功率
|
||||
// @Tags statctrl
|
||||
// @Accept mpfd,json
|
||||
// @Produce json,html
|
||||
// @Param sumDate query string true "日期"
|
||||
// @Param channel query string true "渠道"
|
||||
// @Success 200 {string} json "{"msg": "操作成功"}"
|
||||
// @Failure 400 {string} json "{"msg": "操作失败"}"
|
||||
// @Router /web/admin/stats/order/sucRate [post]
|
||||
func RchSucRate(ctx *gin.Context) {
|
||||
var args struct {
|
||||
SumDate time.Time `form:"sumDate" json:"sumDate" binding:"required"`
|
||||
Channel string `form:"channel" json:"channel" binding:"required"`
|
||||
}
|
||||
if err := ctx.ShouldBind(&args); err != nil {
|
||||
common.ServeJSON(ctx, stderr.ErrParamError, "stat RchSucRate arg error "+err.Error())
|
||||
return
|
||||
}
|
||||
rchSucRateMap, err := statser.RechargeSucRateMap(args.SumDate, args.Channel)
|
||||
if err != nil {
|
||||
common.ServeJSON(ctx, stderr.Failure, "statctrl OrderPages error: "+err.Error())
|
||||
return
|
||||
}
|
||||
common.ServeJSON(ctx, stderr.Success, rchSucRateMap)
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package statctrl
|
||||
|
||||
import (
|
||||
"91porn-server/common"
|
||||
"91porn-server/common/stderr"
|
||||
"91porn-server/web/service/statser"
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func DataStat(ctx *gin.Context) {
|
||||
var args struct {
|
||||
Start time.Time `form:"startTime" json:"startTime" binding:"required"`
|
||||
End time.Time `form:"endTime" json:"endTime" binding:"required"`
|
||||
}
|
||||
if err := ctx.ShouldBind(&args); err != nil {
|
||||
common.ServeJSON(ctx, stderr.ErrParamError, "stat RchSucRate arg error "+err.Error())
|
||||
return
|
||||
}
|
||||
res, err, titles := statser.DataStat(args.Start, args.End)
|
||||
if err != nil {
|
||||
common.ServeJSON(ctx, stderr.Failure, "DataStat DataStat error: "+err.Error())
|
||||
return
|
||||
}
|
||||
var (
|
||||
headList []string
|
||||
dataBytes = new(bytes.Buffer)
|
||||
)
|
||||
headList = []string{"时间", "楼凤", "vip充值", "金币充值", "新增用户"}
|
||||
for i := range titles {
|
||||
headList = append(headList, titles[i]+"金额", titles[i]+"-数量")
|
||||
}
|
||||
headList = append(headList, titles...)
|
||||
//设置编码格式
|
||||
dataBytes.WriteString("\xEF\xBB\xBF")
|
||||
wr := csv.NewWriter(dataBytes)
|
||||
wr.Write(headList)
|
||||
for _, v := range res {
|
||||
bodyList := []string{
|
||||
v.SumData,
|
||||
strconv.FormatInt(v.LoufengTrade, 10),
|
||||
strconv.FormatInt(v.VIPRecharge, 10),
|
||||
strconv.FormatInt(v.CoinRecharge, 10),
|
||||
strconv.FormatInt(v.NewUser, 10),
|
||||
}
|
||||
vipTrans := make([]string, 0)
|
||||
for i := range titles {
|
||||
if len(v.VipTrande) < 1 {
|
||||
vipTrans = append(vipTrans, "0", "0")
|
||||
} else if vipTrande, ok := v.VipTrande[titles[i]]; ok {
|
||||
vipTrans = append(vipTrans, fmt.Sprintf("%d", vipTrande.Amount), fmt.Sprintf("%d", vipTrande.Count))
|
||||
} else {
|
||||
vipTrans = append(vipTrans, "0", "0")
|
||||
}
|
||||
}
|
||||
bodyList = append(bodyList, vipTrans...)
|
||||
wr.Write(bodyList)
|
||||
}
|
||||
//清空
|
||||
wr.Flush()
|
||||
ctx.Writer.Header().Set("Content-type", "application/octet-stream")
|
||||
//c.Writer.Header().Set("Content-Type", "text/csv")
|
||||
ctx.Writer.Header().Set("Content-Disposition", fmt.Sprintf("attachment;filename=%s", "companys.csv"))
|
||||
ctx.String(200, dataBytes.String())
|
||||
return
|
||||
}
|
||||
func VidStat(ctx *gin.Context) {
|
||||
var args struct {
|
||||
Start time.Time `form:"startTime" json:"startTime" binding:"required"`
|
||||
End time.Time `form:"endTime" json:"endTime" binding:"required"`
|
||||
}
|
||||
if err := ctx.ShouldBind(&args); err != nil {
|
||||
common.ServeJSON(ctx, stderr.ErrParamError, "stat RchSucRate arg error "+err.Error())
|
||||
return
|
||||
}
|
||||
var (
|
||||
headList []string
|
||||
dataBytes = new(bytes.Buffer)
|
||||
)
|
||||
headList = []string{"时间", "短视频销售额", "短视频数量", "长视频销售额", "长视频数量"}
|
||||
//设置编码格式
|
||||
dataBytes.WriteString("\xEF\xBB\xBF")
|
||||
wr := csv.NewWriter(dataBytes)
|
||||
wr.Write(headList)
|
||||
start := args.Start
|
||||
end := args.End
|
||||
|
||||
for start.Before(end) {
|
||||
head := start
|
||||
tail := head.Add(time.Hour * 24 * 15)
|
||||
if tail.After(end) {
|
||||
tail = end
|
||||
}
|
||||
res, err := statser.PayVidStat(head, tail)
|
||||
if err != nil {
|
||||
common.ServeJSON(ctx, stderr.Failure, "statser PayVidStat error: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range res {
|
||||
bodyList := []string{
|
||||
v.SumData,
|
||||
strconv.FormatInt(v.ShortVidAmount, 10),
|
||||
strconv.FormatInt(v.ShortVidCount, 10),
|
||||
strconv.FormatInt(v.LongVidAmount, 10),
|
||||
strconv.FormatInt(v.LongVidCount, 10),
|
||||
}
|
||||
wr.Write(bodyList)
|
||||
}
|
||||
start = tail
|
||||
}
|
||||
|
||||
//清空
|
||||
wr.Flush()
|
||||
ctx.Writer.Header().Set("Content-type", "application/octet-stream")
|
||||
ctx.Writer.Header().Set("Content-Disposition", fmt.Sprintf("attachment;filename=%s", "videoSales.csv"))
|
||||
ctx.String(200, dataBytes.String())
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package statctrl
|
||||
|
||||
import (
|
||||
"91porn-server/common"
|
||||
"91porn-server/common/stderr"
|
||||
"91porn-server/models/commod"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// DailyStats doc
|
||||
// @Summary 用户登陆统计
|
||||
// @Description 从指定点时间点开始统计用户登陆
|
||||
// @Tags web-统计管理
|
||||
// @Accept mpfd,json
|
||||
// @Produce json,html
|
||||
// @Param pageNumber query integer true "当前页"
|
||||
// @Param pageSize query integer true "每页条数"
|
||||
// @Param startTime query integer false "开始时间UTC时间戳"
|
||||
// @Param endTime query integer false "结束时间UTC时间戳"
|
||||
// @Success 200 {string} json "{"msg": "操作成功"}"
|
||||
// @Failure 400 {string} json "{"msg": "操作失败"}"
|
||||
// @Router /web/stats/user/daily/list [get]
|
||||
func DailyStats(c *gin.Context) {
|
||||
type Query struct {
|
||||
StartTime *time.Time `form:"startTime" json:"startTime" binding:""` //开始时间
|
||||
EndTime *time.Time `form:"endTime" json:"endTime" binding:""` //结束时间
|
||||
ExpansionFactor *int64 `form:"expansionFactor" json:"expansionFactor" binding:"omitempty,min=1"` //膨胀系数
|
||||
}
|
||||
var arg struct {
|
||||
commod.Page
|
||||
Query
|
||||
}
|
||||
if err := c.ShouldBind(&arg); err != nil {
|
||||
common.ServeJSON(c, stderr.ErrParamError, "DailyStats arg error "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
//endTime := time.Now()
|
||||
//if arg.EndTime != nil {
|
||||
// endTime = *arg.EndTime
|
||||
//}
|
||||
//
|
||||
//var startTime time.Time
|
||||
//if arg.StartTime != nil {
|
||||
// startTime = *arg.StartTime
|
||||
//}
|
||||
//
|
||||
//skip := int64((arg.PageNumber - 1) * arg.PageSize)
|
||||
//limit := int64(arg.PageSize)
|
||||
//var expansionFactor int64
|
||||
//if arg.ExpansionFactor != nil {
|
||||
// expansionFactor = *arg.ExpansionFactor
|
||||
//}
|
||||
//page, err := statser.DailyStatsPage(skip, limit, startTime, endTime, expansionFactor)
|
||||
//if err != nil {
|
||||
// common.ServeJSON(c, stderr.Failure, "statctrl DailyStatsPage error "+err.Error())
|
||||
// return
|
||||
//}
|
||||
common.ServeJSON(c, stderr.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package statctrl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"91porn-server/common"
|
||||
"91porn-server/common/stderr"
|
||||
"91porn-server/common/timeutil/timerange"
|
||||
"91porn-server/models/commod"
|
||||
"91porn-server/models/s/statvidmod"
|
||||
"91porn-server/models/v/vidmod"
|
||||
"91porn-server/web/service/deduction"
|
||||
"91porn-server/web/service/payvidlgser"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
const VideoAggregateStatsTopN = 20
|
||||
|
||||
// VideoEarnStats doc
|
||||
// @Summary 视屏收入统计
|
||||
// @Description 统计从指定时间区间的视屏收入
|
||||
// @Tags web-统计管理
|
||||
// @Accept mpfd,json
|
||||
// @Produce json,html
|
||||
// @Param uid query string true "用户ID"
|
||||
// @Param startTime query string true "开始时间"
|
||||
// @Param endTime query string true "结束时间"
|
||||
// @Success 200 {string} json "{"msg": "操作成功"}"
|
||||
// @Failure 400 {string} json "{"msg": "操作失败"}"
|
||||
// @Router /web/stats/video/earn/list [get]
|
||||
func VideoEarnStats(c *gin.Context) {
|
||||
type Query struct {
|
||||
StartTime *time.Time `form:"startTime" json:"startTime,omitempty" binding:""` //开始时间
|
||||
EndTime *time.Time `form:"endTime" json:"endTime,omitempty" binding:""` //结束时间
|
||||
UID *uint64 `form:"uid" json:"uid" binding:""` //uid
|
||||
Vid *string `form:"vid" json:"vid" binding:""` //vid
|
||||
}
|
||||
var arg struct {
|
||||
commod.Page
|
||||
Query
|
||||
}
|
||||
if err := c.ShouldBind(&arg); err != nil {
|
||||
common.ServeJSON(c, stderr.ErrParamError, "stat VideoEarnStats arg error "+err.Error())
|
||||
return
|
||||
}
|
||||
endTime := time.Now()
|
||||
if arg.EndTime != nil {
|
||||
endTime = timerange.LocDayRange(*arg.EndTime).Head
|
||||
}
|
||||
startTime := time.Time{}
|
||||
if arg.StartTime != nil {
|
||||
startTime = timerange.LocDayRange(*arg.StartTime).Head
|
||||
}
|
||||
var vid *primitive.ObjectID
|
||||
if arg.Vid != nil {
|
||||
id, _ := primitive.ObjectIDFromHex(*arg.Vid)
|
||||
vid = &id
|
||||
}
|
||||
var vids []primitive.ObjectID
|
||||
if arg.UID != nil {
|
||||
list, _ := vidmod.FindMany((&vidmod.PublisherIDMatch{PublisherID: arg.UID}).New())
|
||||
vids = list.IDs()
|
||||
}
|
||||
limit := int64(arg.PageSize)
|
||||
skip := int64((arg.PageNumber - 1) * arg.PageSize)
|
||||
page, err := statvidmod.VideoStatPages(skip, limit,
|
||||
statvidmod.SumDateGTEAndLTMatch{GTE: &startTime, LT: &endTime},
|
||||
statvidmod.VidMatch{Vid: vid},
|
||||
statvidmod.VidInMatch{Vids: vids},
|
||||
)
|
||||
if err != nil {
|
||||
common.ServeJSON(c, stderr.Failure, "stat VideoEarnStats Failure, error: !"+err.Error())
|
||||
return
|
||||
}
|
||||
common.ServeJSON(c, stderr.Success, page)
|
||||
}
|
||||
|
||||
// VideoEarnStats doc
|
||||
// @Summary 视频收入聚合统计排序
|
||||
// @Description 聚合统计指定时间区间内视频收入,取总收益前20展示
|
||||
// @Tags web-统计管理
|
||||
// @Accept mpfd,json
|
||||
// @Produce json,html
|
||||
// @Param uid query string true "用户ID"
|
||||
// @Param startTime query string true "开始时间"
|
||||
// @Param endTime query string true "结束时间"
|
||||
// @Success 200 {object} payvidlgser.VideoCoinIncomeAggregateTopNStat "success"
|
||||
// @Failure 400 {string} json "{"msg": "操作失败"}"
|
||||
// @Router /web/stats/video/earn/aggregate [get]
|
||||
func VideoAggregateStats(c *gin.Context) {
|
||||
type Query struct {
|
||||
StartTime *time.Time `form:"startTime" json:"startTime,omitempty" binding:""` //开始时间
|
||||
EndTime *time.Time `form:"endTime" json:"endTime,omitempty" binding:""` //结束时间
|
||||
UID *uint64 `form:"uid" json:"uid" binding:""` //uid
|
||||
}
|
||||
args := &Query{}
|
||||
if err := c.ShouldBind(args); err != nil {
|
||||
common.ServeJSON(c, stderr.ErrParamError, fmt.Sprintf("stat VideoAggregateStats arg error %s", err.Error()))
|
||||
return
|
||||
}
|
||||
endTime := time.Now()
|
||||
if args.EndTime != nil {
|
||||
endTime = timerange.LocDayRange(*args.EndTime).Head
|
||||
}
|
||||
//最多允许查半年内的数据,防止数据量过大
|
||||
startTime := endTime.AddDate(0, -6, 0)
|
||||
if args.StartTime != nil && args.StartTime.After(startTime) {
|
||||
startTime = timerange.LocDayRange(*args.StartTime).Head
|
||||
}
|
||||
stat, err := payvidlgser.VideoCoinIncomeAggregateTopN(VideoAggregateStatsTopN, startTime, endTime)
|
||||
if err != nil {
|
||||
common.ServeJSON(c, stderr.Failure, "stat VideoAggregateStats Failure, error: !"+err.Error())
|
||||
return
|
||||
}
|
||||
common.ServeJSON(c, stderr.Success, stat)
|
||||
}
|
||||
|
||||
// VideoPublisherDeductionStats doc
|
||||
// @Summary 视频博主扣量前后视频总售卖
|
||||
// @Description 统计博主扣量前视频总售卖,扣量后总售卖
|
||||
// @Tags web-统计管理
|
||||
// @Accept mpfd,json
|
||||
// @Produce json,html
|
||||
// @Param uid query string true "用户ID"
|
||||
// @Param startTime query string true "开始时间"
|
||||
// @Param endTime query string true "结束时间"
|
||||
// @Success 200 {string} json deduction.PublisherDeduction
|
||||
// @Failure 400 {string} json "{"msg": "操作失败"}"
|
||||
// @Router /web/stats/video/publisher/deduction [get]
|
||||
func VideoPublisherDeductionStats(c *gin.Context) {
|
||||
args := &deduction.Query{}
|
||||
if err := c.ShouldBind(args); err != nil {
|
||||
common.ServeJSON(c, stderr.ErrParamError,
|
||||
fmt.Sprintf("stat VideoPublisherDeductionStats arg error %s", err.Error()))
|
||||
return
|
||||
}
|
||||
if args.EndTime == nil {
|
||||
*args.EndTime = timerange.LocDayRange(time.Now()).Head
|
||||
}
|
||||
// 早于这之前的历史数据无法查询
|
||||
startTime := time.Date(2021, time.October, 18, 23, 59, 59, 0, time.Local)
|
||||
if args.StartTime != nil && args.StartTime.Before(startTime) {
|
||||
common.ServeJSON(c, stderr.ErrParamError, fmt.Sprintf("stat VideoPublisherDeductionStats error %s", "start time too early"))
|
||||
return
|
||||
}
|
||||
if args.EndTime.Before(*args.StartTime) {
|
||||
common.ServeJSON(c, stderr.ErrParamError, fmt.Sprintf("stat VideoPublisherDeductionStats error %s", "start time is after end time"))
|
||||
return
|
||||
}
|
||||
stat, err := deduction.StatPublisherDeduction(args)
|
||||
if err != nil {
|
||||
common.ServeJSON(c, stderr.Failure, fmt.Sprintf("stat VideoPublisherDeductionStats error %s", err.Error()))
|
||||
return
|
||||
}
|
||||
common.ServeJSON(c, stderr.Success, stat)
|
||||
}
|
||||
Reference in New Issue
Block a user