463 lines
16 KiB
Go
463 lines
16 KiB
Go
package admin_dashboard
|
||
|
||
import (
|
||
"bdqr-server/app/main/api/internal/service"
|
||
"context"
|
||
"time"
|
||
|
||
"bdqr-server/app/main/api/internal/svc"
|
||
"bdqr-server/app/main/api/internal/types"
|
||
"bdqr-server/common/globalkey"
|
||
"bdqr-server/common/xerr"
|
||
|
||
"github.com/pkg/errors"
|
||
"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 {
|
||
logx.Infof("开始获取今日API调用成本,时间范围: %v 到 %v", todayStart, todayEnd)
|
||
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
|
||
logx.Infof("今日API调用成本统计完成,总成本: %f", todayApiCost)
|
||
}
|
||
} else {
|
||
logx.Errorf("TianyuanapiCallLogService 未初始化,无法获取API调用成本")
|
||
}
|
||
// 今日利润 = 营收 - 佣金 - 返利 - 税务成本 - 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 {
|
||
logx.Infof("开始获取当月API调用成本,时间范围: %v 到 %v", monthStart, monthEnd)
|
||
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
|
||
logx.Infof("当月API调用成本统计完成,总成本: %f", monthApiCost)
|
||
}
|
||
} else {
|
||
logx.Errorf("TianyuanapiCallLogService 未初始化,无法获取API调用成本")
|
||
}
|
||
// 当月利润
|
||
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 {
|
||
logx.Infof("开始获取总API调用成本(无时间限制)")
|
||
totalApiStats, err := l.svcCtx.TianyuanapiCallLogService.GetStatistics(l.ctx, service.StatisticsFilter{})
|
||
if err != nil {
|
||
logx.Errorf("获取总API调用成本失败: %v", err)
|
||
} else {
|
||
totalApiCost = totalApiStats.TotalCost
|
||
logx.Infof("总API调用成本统计完成,总成本: %f", totalApiCost)
|
||
}
|
||
} else {
|
||
logx.Errorf("TianyuanapiCallLogService 未初始化,无法获取API调用成本")
|
||
}
|
||
// 总利润
|
||
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
|
||
}
|