first commit
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/global"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/mysqldao"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/errcode"
|
||||
)
|
||||
|
||||
// DashboardService 仪表盘统计服务。
|
||||
type DashboardService struct {
|
||||
statsDao *mysqldao.StatsDao
|
||||
}
|
||||
|
||||
// NewDashboardService 创建仪表盘服务。
|
||||
func NewDashboardService() *DashboardService {
|
||||
return &DashboardService{statsDao: mysqldao.NewStatsDao()}
|
||||
}
|
||||
|
||||
// Summary 聚合仪表盘核心指标:用户/订单/营收/待办。
|
||||
func (s *DashboardService) Summary(ctx context.Context) (*dto.DashboardResponse, *errcode.Error) {
|
||||
ctx, span := global.Tracer.Start(ctx, "svc.DashboardSummary")
|
||||
defer span.End()
|
||||
|
||||
todayStart := todayStartUnix()
|
||||
|
||||
userStats, err := s.statsDao.UserStatsGet(ctx, todayStart)
|
||||
if err != nil {
|
||||
return nil, errcode.DatabaseError
|
||||
}
|
||||
userStatusMap, err := s.statsDao.UserStatsGetByStatus(ctx)
|
||||
if err != nil {
|
||||
return nil, errcode.DatabaseError
|
||||
}
|
||||
orderStats, err := s.statsDao.OrderStatsGet(ctx)
|
||||
if err != nil {
|
||||
return nil, errcode.DatabaseError
|
||||
}
|
||||
revenueStats, err := s.statsDao.RevenueStatsGet(ctx, todayStart)
|
||||
if err != nil {
|
||||
return nil, errcode.DatabaseError
|
||||
}
|
||||
todoStats, err := s.statsDao.TodoStatsGet(ctx)
|
||||
if err != nil {
|
||||
return nil, errcode.DatabaseError
|
||||
}
|
||||
contentStats, err := s.statsDao.ContentStatsGet(ctx)
|
||||
if err != nil {
|
||||
return nil, errcode.DatabaseError
|
||||
}
|
||||
now := nowUnix()
|
||||
vipStats, err := s.statsDao.VIPStatsGet(ctx, now, now+7*86400)
|
||||
if err != nil {
|
||||
return nil, errcode.DatabaseError
|
||||
}
|
||||
goodsStats, err := s.statsDao.GoodsStatsGet(ctx)
|
||||
if err != nil {
|
||||
return nil, errcode.DatabaseError
|
||||
}
|
||||
usageStats, err := s.statsDao.UsageStatsGet(ctx, todayStatDate())
|
||||
if err != nil {
|
||||
return nil, errcode.DatabaseError
|
||||
}
|
||||
socialStats, err := s.statsDao.SocialStatsGet(ctx)
|
||||
if err != nil {
|
||||
return nil, errcode.DatabaseError
|
||||
}
|
||||
|
||||
return &dto.DashboardResponse{
|
||||
Users: dto.DashboardUsers{
|
||||
Total: userStats.Total,
|
||||
TodayNew: userStats.TodayNew,
|
||||
Normal: userStatusMap[UserStatusNormal],
|
||||
TempBan: userStatusMap[UserStatusTempBan],
|
||||
PermBan: userStatusMap[UserStatusPermBan],
|
||||
Deactivated: userStatusMap[UserStatusDeactivated],
|
||||
},
|
||||
Orders: dto.DashboardOrders{
|
||||
Total: orderStats.Total,
|
||||
Pending: orderStats.Pending,
|
||||
Paid: orderStats.Paid,
|
||||
Cancelled: orderStats.Cancelled,
|
||||
Expired: orderStats.Expired,
|
||||
Refunded: orderStats.Refunded,
|
||||
},
|
||||
Revenue: dto.DashboardRevenue{
|
||||
TotalRevenue: revenueStats.TotalRevenue,
|
||||
TodayRevenue: revenueStats.TodayRevenue,
|
||||
RefundTotal: revenueStats.RefundTotal,
|
||||
},
|
||||
Todo: dto.DashboardTodo{
|
||||
RefundPending: todoStats.RefundPending,
|
||||
OutfitPendingAudit: todoStats.OutfitPendingAudit,
|
||||
GoodsOnShelf: todoStats.GoodsOnShelf,
|
||||
},
|
||||
Content: dto.DashboardContent{
|
||||
Outfit: dto.DashboardOutfitStats{
|
||||
Total: contentStats.OutfitTotal,
|
||||
Pending: contentStats.OutfitPending,
|
||||
Passed: contentStats.OutfitPassed,
|
||||
Rejected: contentStats.OutfitRejected,
|
||||
Banned: contentStats.OutfitBanned,
|
||||
},
|
||||
Clothes: dto.DashboardClothesStats{
|
||||
Total: contentStats.ClothesTotal,
|
||||
Processing: contentStats.ClothesProcessing,
|
||||
Success: contentStats.ClothesSuccess,
|
||||
Failed: contentStats.ClothesFailed,
|
||||
},
|
||||
Share: dto.DashboardShareStats{
|
||||
Total: contentStats.ShareTotal,
|
||||
Normal: contentStats.ShareNormal,
|
||||
Cancelled: contentStats.ShareCancelled,
|
||||
Expired: contentStats.ShareExpired,
|
||||
Banned: contentStats.ShareBanned,
|
||||
},
|
||||
},
|
||||
VIP: dto.DashboardVIP{
|
||||
MemberTotal: vipStats.MemberTotal,
|
||||
Monthly: vipStats.Monthly,
|
||||
Yearly: vipStats.Yearly,
|
||||
Trial: vipStats.Trial,
|
||||
ExpiringSoon: vipStats.ExpiringSoon,
|
||||
},
|
||||
Goods: dto.DashboardGoods{
|
||||
Total: goodsStats.Total,
|
||||
OnShelf: goodsStats.OnShelf,
|
||||
OffShelf: goodsStats.OffShelf,
|
||||
ByType: buildGoodsTypeCounts(goodsStats.ByType),
|
||||
},
|
||||
Usage: dto.DashboardUsage{
|
||||
AIRecommend: usageStats.AIRecommend,
|
||||
ClosetShare: usageStats.ClosetShare,
|
||||
OutfitShare: usageStats.OutfitShare,
|
||||
},
|
||||
Social: dto.DashboardSocial{
|
||||
CosImageCount: socialStats.CosImageCount,
|
||||
LikeCount: socialStats.LikeCount,
|
||||
CollectCount: socialStats.CollectCount,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// buildGoodsTypeCounts 商品类型数量 DAO → DTO。
|
||||
func buildGoodsTypeCounts(in []mysqldao.GoodsTypeCount) []dto.GoodsTypeCount {
|
||||
out := make([]dto.GoodsTypeCount, 0, len(in))
|
||||
for _, v := range in {
|
||||
out = append(out, dto.GoodsTypeCount{Type: v.Type, Count: v.Count})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Trends 返回近 N 天趋势(新增用户/已支付订单量/营收,按天补零对齐)。
|
||||
func (s *DashboardService) Trends(ctx context.Context, days int) (*dto.TrendResponse, *errcode.Error) {
|
||||
ctx, span := global.Tracer.Start(ctx, "svc.DashboardTrends")
|
||||
defer span.End()
|
||||
|
||||
if days <= 0 {
|
||||
days = 30
|
||||
}
|
||||
if days > 90 {
|
||||
days = 90
|
||||
}
|
||||
|
||||
startTs := todayStartUnix() - int64(days-1)*86400
|
||||
stats, err := s.statsDao.TrendStatsGet(ctx, startTs)
|
||||
if err != nil {
|
||||
return nil, errcode.DatabaseError
|
||||
}
|
||||
|
||||
loc := time.Now().Location()
|
||||
startDay := time.Unix(startTs, 0).In(loc)
|
||||
points := make([]dto.TrendPoint, 0, days)
|
||||
for i := 0; i < days; i++ {
|
||||
date := startDay.AddDate(0, 0, i).Format("2006-01-02")
|
||||
points = append(points, dto.TrendPoint{
|
||||
Date: date,
|
||||
NewUsers: stats.NewUsers[date],
|
||||
Orders: stats.Orders[date],
|
||||
Revenue: stats.Revenue[date],
|
||||
})
|
||||
}
|
||||
|
||||
return &dto.TrendResponse{Points: points}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user