Files
ycc-proxy-server/app/main/api/internal/logic/admin_dashboard/admingetdashboardstatisticslogic.go
2026-01-13 18:30:10 +08:00

452 lines
16 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package admin_dashboard
import (
"context"
"time"
"ycc-server/common/globalkey"
"ycc-server/common/xerr"
"github.com/pkg/errors"
"ycc-server/app/main/api/internal/service"
"ycc-server/app/main/api/internal/svc"
"ycc-server/app/main/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type AdminGetDashboardStatisticsLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAdminGetDashboardStatisticsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetDashboardStatisticsLogic {
return &AdminGetDashboardStatisticsLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *AdminGetDashboardStatisticsLogic) AdminGetDashboardStatistics() (resp *types.AdminGetDashboardStatisticsResp, err error) {
// 使用Asia/Shanghai时区
loc, _ := time.LoadLocation("Asia/Shanghai")
now := time.Now().In(loc)
// 计算时间范围
todayStart := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, loc)
todayEnd := todayStart.AddDate(0, 0, 1)
yesterdayStart := todayStart.AddDate(0, 0, -1)
yesterdayEnd := todayStart
monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, loc)
monthEnd := monthStart.AddDate(0, 1, 0)
// 1. 订单统计
orderStats, err := l.calculateOrderStatistics(todayStart, todayEnd, yesterdayStart, yesterdayEnd, monthStart, monthEnd)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "计算订单统计失败, %v", err)
}
// 2. 营收统计
revenueStats, err := l.calculateRevenueStatistics(todayStart, todayEnd, yesterdayStart, yesterdayEnd, monthStart, monthEnd)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "计算营收统计失败, %v", err)
}
// 3. 代理统计
agentStats, err := l.calculateAgentStatistics(todayStart, monthStart)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "计算代理统计失败, %v", err)
}
// 4. 利润统计
profitStats, err := l.calculateProfitStatistics(todayStart, todayEnd, monthStart, monthEnd, revenueStats)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "计算利润统计失败, %v", err)
}
// 5. 订单趋势最近7天
orderTrend, err := l.calculateOrderTrend(now, loc)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "计算订单趋势失败, %v", err)
}
// 6. 营收趋势最近7天
revenueTrend, err := l.calculateRevenueTrend(now, loc)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "计算营收趋势失败, %v", err)
}
return &types.AdminGetDashboardStatisticsResp{
OrderStats: orderStats,
RevenueStats: revenueStats,
AgentStats: agentStats,
ProfitStats: profitStats,
OrderTrend: orderTrend,
RevenueTrend: revenueTrend,
}, nil
}
// calculateOrderStatistics 计算订单统计
func (l *AdminGetDashboardStatisticsLogic) calculateOrderStatistics(todayStart, todayEnd, yesterdayStart, yesterdayEnd, monthStart, monthEnd time.Time) (types.AdminOrderStatistics, error) {
var stats types.AdminOrderStatistics
// 今日订单数
todayBuilder := l.svcCtx.OrderModel.SelectBuilder().
Where("status = ? AND create_time >= ? AND create_time < ?", "paid", todayStart, todayEnd)
todayCount, err := l.svcCtx.OrderModel.FindCount(l.ctx, todayBuilder, "id")
if err != nil {
return stats, err
}
stats.TodayCount = todayCount
// 昨日订单数
yesterdayBuilder := l.svcCtx.OrderModel.SelectBuilder().
Where("status = ? AND create_time >= ? AND create_time < ?", "paid", yesterdayStart, yesterdayEnd)
yesterdayCount, err := l.svcCtx.OrderModel.FindCount(l.ctx, yesterdayBuilder, "id")
if err != nil {
return stats, err
}
stats.YesterdayCount = yesterdayCount
// 当月订单数
monthBuilder := l.svcCtx.OrderModel.SelectBuilder().
Where("status = ? AND create_time >= ? AND create_time < ?", "paid", monthStart, monthEnd)
monthCount, err := l.svcCtx.OrderModel.FindCount(l.ctx, monthBuilder, "id")
if err != nil {
return stats, err
}
stats.MonthCount = monthCount
// 总订单数
totalBuilder := l.svcCtx.OrderModel.SelectBuilder().
Where("status = ?", "paid")
totalCount, err := l.svcCtx.OrderModel.FindCount(l.ctx, totalBuilder, "id")
if err != nil {
return stats, err
}
stats.TotalCount = totalCount
// 计算变化率
if stats.YesterdayCount > 0 {
stats.ChangeRate = float64(stats.TodayCount-stats.YesterdayCount) / float64(stats.YesterdayCount) * 100
} else if stats.TodayCount > 0 {
stats.ChangeRate = 100 // 从0增长到有值算100%增长
}
return stats, nil
}
// calculateRevenueStatistics 计算营收统计
func (l *AdminGetDashboardStatisticsLogic) calculateRevenueStatistics(todayStart, todayEnd, yesterdayStart, yesterdayEnd, monthStart, monthEnd time.Time) (types.AdminRevenueStatistics, error) {
var stats types.AdminRevenueStatistics
// 今日营收
todayBuilder := l.svcCtx.OrderModel.SelectBuilder().
Where("status = ? AND create_time >= ? AND create_time < ?", "paid", todayStart, todayEnd)
todayAmount, err := l.svcCtx.OrderModel.FindSum(l.ctx, todayBuilder, "amount")
if err != nil {
return stats, err
}
stats.TodayAmount = todayAmount
// 昨日营收
yesterdayBuilder := l.svcCtx.OrderModel.SelectBuilder().
Where("status = ? AND create_time >= ? AND create_time < ?", "paid", yesterdayStart, yesterdayEnd)
yesterdayAmount, err := l.svcCtx.OrderModel.FindSum(l.ctx, yesterdayBuilder, "amount")
if err != nil {
return stats, err
}
stats.YesterdayAmount = yesterdayAmount
// 当月营收
monthBuilder := l.svcCtx.OrderModel.SelectBuilder().
Where("status = ? AND create_time >= ? AND create_time < ?", "paid", monthStart, monthEnd)
monthAmount, err := l.svcCtx.OrderModel.FindSum(l.ctx, monthBuilder, "amount")
if err != nil {
return stats, err
}
stats.MonthAmount = monthAmount
// 总营收
totalBuilder := l.svcCtx.OrderModel.SelectBuilder().
Where("status = ?", "paid")
totalAmount, err := l.svcCtx.OrderModel.FindSum(l.ctx, totalBuilder, "amount")
if err != nil {
return stats, err
}
stats.TotalAmount = totalAmount
// 计算变化率
if stats.YesterdayAmount > 0 {
stats.ChangeRate = (stats.TodayAmount - stats.YesterdayAmount) / stats.YesterdayAmount * 100
} else if stats.TodayAmount > 0 {
stats.ChangeRate = 100 // 从0增长到有值算100%增长
}
return stats, nil
}
// calculateAgentStatistics 计算代理统计
func (l *AdminGetDashboardStatisticsLogic) calculateAgentStatistics(todayStart, monthStart time.Time) (types.AdminAgentStatistics, error) {
var stats types.AdminAgentStatistics
// 代理总数
totalBuilder := l.svcCtx.AgentModel.SelectBuilder()
totalCount, err := l.svcCtx.AgentModel.FindCount(l.ctx, totalBuilder, "id")
if err != nil {
return stats, err
}
stats.TotalCount = totalCount
// 今日新增
todayBuilder := l.svcCtx.AgentModel.SelectBuilder().
Where("create_time >= ?", todayStart)
todayNew, err := l.svcCtx.AgentModel.FindCount(l.ctx, todayBuilder, "id")
if err != nil {
return stats, err
}
stats.TodayNew = todayNew
// 当月新增
monthBuilder := l.svcCtx.AgentModel.SelectBuilder().
Where("create_time >= ?", monthStart)
monthNew, err := l.svcCtx.AgentModel.FindCount(l.ctx, monthBuilder, "id")
if err != nil {
return stats, err
}
stats.MonthNew = monthNew
return stats, nil
}
// calculateProfitStatistics 计算利润统计
func (l *AdminGetDashboardStatisticsLogic) calculateProfitStatistics(todayStart, todayEnd, monthStart, monthEnd time.Time, revenueStats types.AdminRevenueStatistics) (types.AdminProfitStatistics, error) {
var stats types.AdminProfitStatistics
// 税务成本比例6%
const companyTaxRate = 0.06
// 今日利润计算
// 今日营收
todayRevenue := revenueStats.TodayAmount
// 今日佣金
todayCommissionBuilder := l.svcCtx.AgentCommissionModel.SelectBuilder().
Where("del_state = ? AND status != ? AND create_time >= ? AND create_time < ?", globalkey.DelStateNo, 3, todayStart, todayEnd)
todayCommission, err := l.svcCtx.AgentCommissionModel.FindSum(l.ctx, todayCommissionBuilder, "amount")
if err != nil {
return stats, err
}
// 今日返利
todayRebateBuilder := l.svcCtx.AgentRebateModel.SelectBuilder().
Where("del_state = ? AND status != ? AND create_time >= ? AND create_time < ?", globalkey.DelStateNo, 3, todayStart, todayEnd)
todayRebate, err := l.svcCtx.AgentRebateModel.FindSum(l.ctx, todayRebateBuilder, "rebate_amount")
if err != nil {
return stats, err
}
// 今日税务成本订单金额的6%
todayCompanyTax := todayRevenue * companyTaxRate
// 今日提现收税agent_withdrawal_tax表中tax_status=2的tax_amount总和
todayTaxIncomeBuilder := l.svcCtx.AgentWithdrawalTaxModel.SelectBuilder().
Where("del_state = ? AND tax_status = ? AND create_time >= ? AND create_time < ?", globalkey.DelStateNo, 2, todayStart, todayEnd)
todayTaxIncome, err := l.svcCtx.AgentWithdrawalTaxModel.FindSum(l.ctx, todayTaxIncomeBuilder, "tax_amount")
if err != nil {
return stats, err
}
// 今日API调用成本
todayApiCost := 0.0
if l.svcCtx.TianyuanapiCallLogService != nil {
todayApiStats, err := l.svcCtx.TianyuanapiCallLogService.GetStatistics(l.ctx, service.StatisticsFilter{
StartDate: todayStart,
EndDate: todayEnd,
})
if err != nil {
logx.Errorf("获取今日API调用成本失败: %v", err)
} else {
todayApiCost = todayApiStats.TotalCost
}
}
// 今日利润 = 营收 - 佣金 - 返利 - 税务成本 - API调用成本 + 提现收税
stats.TodayProfit = todayRevenue - todayCommission - todayRebate - todayCompanyTax - todayApiCost + todayTaxIncome
if todayRevenue > 0 {
stats.TodayProfitRate = stats.TodayProfit / todayRevenue * 100
}
// 今日明细
stats.TodayDetail = types.AdminProfitDetail{
Revenue: todayRevenue,
Commission: todayCommission,
Rebate: todayRebate,
CompanyTax: todayCompanyTax,
ApiCost: todayApiCost,
TaxIncome: todayTaxIncome,
Profit: stats.TodayProfit,
ProfitRate: stats.TodayProfitRate,
}
// 当月利润计算
// 当月营收
monthRevenue := revenueStats.MonthAmount
// 当月佣金
monthCommissionBuilder := l.svcCtx.AgentCommissionModel.SelectBuilder().
Where("del_state = ? AND status != ? AND create_time >= ? AND create_time < ?", globalkey.DelStateNo, 3, monthStart, monthEnd)
monthCommission, err := l.svcCtx.AgentCommissionModel.FindSum(l.ctx, monthCommissionBuilder, "amount")
if err != nil {
return stats, err
}
// 当月返利
monthRebateBuilder := l.svcCtx.AgentRebateModel.SelectBuilder().
Where("del_state = ? AND status != ? AND create_time >= ? AND create_time < ?", globalkey.DelStateNo, 3, monthStart, monthEnd)
monthRebate, err := l.svcCtx.AgentRebateModel.FindSum(l.ctx, monthRebateBuilder, "rebate_amount")
if err != nil {
return stats, err
}
// 当月税务成本
monthCompanyTax := monthRevenue * companyTaxRate
// 当月提现收税
monthTaxIncomeBuilder := l.svcCtx.AgentWithdrawalTaxModel.SelectBuilder().
Where("del_state = ? AND tax_status = ? AND create_time >= ? AND create_time < ?", globalkey.DelStateNo, 2, monthStart, monthEnd)
monthTaxIncome, err := l.svcCtx.AgentWithdrawalTaxModel.FindSum(l.ctx, monthTaxIncomeBuilder, "tax_amount")
if err != nil {
return stats, err
}
// 当月API调用成本
monthApiCost := 0.0
if l.svcCtx.TianyuanapiCallLogService != nil {
monthApiStats, err := l.svcCtx.TianyuanapiCallLogService.GetStatistics(l.ctx, service.StatisticsFilter{
StartDate: monthStart,
EndDate: monthEnd,
})
if err != nil {
logx.Errorf("获取当月API调用成本失败: %v", err)
} else {
monthApiCost = monthApiStats.TotalCost
}
}
// 当月利润
stats.MonthProfit = monthRevenue - monthCommission - monthRebate - monthCompanyTax - monthApiCost + monthTaxIncome
if monthRevenue > 0 {
stats.MonthProfitRate = stats.MonthProfit / monthRevenue * 100
}
// 当月明细
stats.MonthDetail = types.AdminProfitDetail{
Revenue: monthRevenue,
Commission: monthCommission,
Rebate: monthRebate,
CompanyTax: monthCompanyTax,
ApiCost: monthApiCost,
TaxIncome: monthTaxIncome,
Profit: stats.MonthProfit,
ProfitRate: stats.MonthProfitRate,
}
// 总利润计算
// 总营收
totalRevenue := revenueStats.TotalAmount
// 总佣金
totalCommissionBuilder := l.svcCtx.AgentCommissionModel.SelectBuilder().
Where("del_state = ? AND status != ?", globalkey.DelStateNo, 3)
totalCommission, err := l.svcCtx.AgentCommissionModel.FindSum(l.ctx, totalCommissionBuilder, "amount")
if err != nil {
return stats, err
}
// 总返利
totalRebateBuilder := l.svcCtx.AgentRebateModel.SelectBuilder().
Where("status != ?", 3)
totalRebate, err := l.svcCtx.AgentRebateModel.FindSum(l.ctx, totalRebateBuilder, "rebate_amount")
if err != nil {
return stats, err
}
// 总税务成本
totalCompanyTax := totalRevenue * companyTaxRate
// 总提现收税
totalTaxIncomeBuilder := l.svcCtx.AgentWithdrawalTaxModel.SelectBuilder().
Where("tax_status = ?", 2)
totalTaxIncome, err := l.svcCtx.AgentWithdrawalTaxModel.FindSum(l.ctx, totalTaxIncomeBuilder, "tax_amount")
if err != nil {
return stats, err
}
// 总API调用成本
totalApiCost := 0.0
if l.svcCtx.TianyuanapiCallLogService != nil {
totalApiStats, err := l.svcCtx.TianyuanapiCallLogService.GetStatistics(l.ctx, service.StatisticsFilter{})
if err != nil {
logx.Errorf("获取总API调用成本失败: %v", err)
} else {
totalApiCost = totalApiStats.TotalCost
}
}
// 总利润
stats.TotalProfit = totalRevenue - totalCommission - totalRebate - totalCompanyTax - totalApiCost + totalTaxIncome
if totalRevenue > 0 {
stats.TotalProfitRate = stats.TotalProfit / totalRevenue * 100
}
// 总计明细
stats.TotalDetail = types.AdminProfitDetail{
Revenue: totalRevenue,
Commission: totalCommission,
Rebate: totalRebate,
CompanyTax: totalCompanyTax,
ApiCost: totalApiCost,
TaxIncome: totalTaxIncome,
Profit: stats.TotalProfit,
ProfitRate: stats.TotalProfitRate,
}
return stats, nil
}
// calculateOrderTrend 计算订单趋势最近7天
func (l *AdminGetDashboardStatisticsLogic) calculateOrderTrend(now time.Time, loc *time.Location) ([]types.AdminTrendData, error) {
var trend []types.AdminTrendData
// 计算最近7天的日期
for i := 6; i >= 0; i-- {
date := now.AddDate(0, 0, -i)
dateStart := time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, loc)
dateEnd := dateStart.AddDate(0, 0, 1)
// 查询当天的订单数
builder := l.svcCtx.OrderModel.SelectBuilder().
Where("status = ? AND create_time >= ? AND create_time < ?", "paid", dateStart, dateEnd)
count, err := l.svcCtx.OrderModel.FindCount(l.ctx, builder, "id")
if err != nil {
return nil, err
}
trend = append(trend, types.AdminTrendData{
Date: date.Format("01-02"),
Value: float64(count),
})
}
return trend, nil
}
// calculateRevenueTrend 计算营收趋势最近7天
func (l *AdminGetDashboardStatisticsLogic) calculateRevenueTrend(now time.Time, loc *time.Location) ([]types.AdminTrendData, error) {
var trend []types.AdminTrendData
// 计算最近7天的日期
for i := 6; i >= 0; i-- {
date := now.AddDate(0, 0, -i)
dateStart := time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, loc)
dateEnd := dateStart.AddDate(0, 0, 1)
// 查询当天的营收
builder := l.svcCtx.OrderModel.SelectBuilder().
Where("status = ? AND create_time >= ? AND create_time < ?", "paid", dateStart, dateEnd)
amount, err := l.svcCtx.OrderModel.FindSum(l.ctx, builder, "amount")
if err != nil {
return nil, err
}
trend = append(trend, types.AdminTrendData{
Date: date.Format("01-02"),
Value: amount,
})
}
return trend, nil
}